K&R 1-23 Remove all C comments From K&amp;R exercise 1-23,


  Write a program to remove all comments from a C program. Don't forget
  to handle quoted strings and character constants properly. C comments
  don't nest.


My solution,

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#define MAXLEN  10000   // max input length

int      get_input(char input[], int maxlen);
char * no_comments(char input[], int len);

_Bool comment_start(char input[], int idx);
_Bool   comment_end(char input[], int idx, char *comments, int cdx);

_Bool quote_start(char input[], int idx);
_Bool   quote_end(char input[], int idx);

int main(void)
{
    char input[MAXLEN];
    int len = get_input(input, MAXLEN);
    char *scrubbed = no_comments(input, len);

    printf("%s", scrubbed);
    free(scrubbed);
}

int get_input(char input[], int maxlen)
{
    int i;
    char c;

    for (i = 0; i &lt; maxlen-1 &amp;&amp; (c = getchar()) != EOF; i++) {
        input[i] = c;
    }
    input[++i] = '\0';

    return i;
}

char * no_comments(char input[], int len)
{
    char *scrubbed = (char *) malloc((len+1) * sizeof(char));
    int sdx = 0;    // index

    char *comments = (char *) malloc((len+1) * sizeof(char));
    comments[0] = '\0';
    int cdx = 0;    // index

    _Bool quoted = 0;

    for (int idx = 0; idx &lt;= len; idx++) {
        if (strlen(comments) == 0) { // outside comment

            if (!quoted &amp;&amp; comment_start(input, idx)) {
                comments[cdx++] = input[idx];
            } else {
                scrubbed[sdx++] = input[idx];
            }

            if (quoted &amp;&amp; quote_end(input, idx)) {
                quoted = 0;
            } else if (!quoted &amp;&amp; quote_start(input, idx)) {
                quoted = 1;
            }

        } else { // inside comment

            if (comment_end(input, idx, comments, cdx)) {
                comments[0] = '\0'; // exit comment
                cdx = 0;
            } else {
                comments[cdx++] = input[idx];
            }
        }
    }
    free(comments);

    return scrubbed;
}

_Bool comment_start(char input[], int idx)
{
    char nxt = input[idx+1];

    return input[idx] == '/' &amp;&amp; (nxt == '*' || nxt == '/');
}

_Bool comment_end(char input[], int idx, char *comments, int cdx)
{
    char prev = comments[cdx-1];
    char cur  = input[idx];
    char nxt  = input[idx+1];

    _Bool new_style = (cdx == 1 &amp;&amp; cur == '/') || (cdx &gt; 1 &amp;&amp; comments[1] == '/');
    _Bool old_style = (cdx == 1 &amp;&amp; cur == '*') || (cdx &gt; 1 &amp;&amp; comments[1] == '*');

    return (new_style &amp;&amp; nxt == '\n') || (old_style &amp;&amp; cdx &gt; 2 &amp;&amp; prev == '*' &amp;&amp; cur == '/');
}

_Bool quote_start(char input[], int idx)
{
    return input[idx] == '"' &amp;&amp; input[idx-1] != '\'';
}

_Bool quote_end(char input[], int idx)
{
    return input[idx] == '"' &amp;&amp; input[idx-1] != '\\';
}
I recommend using Valgrind as the first step of the self-code review. Here it only reports one error when compiled with gcc on Linux:

 $ gcc -O2 main.c -o main -std=c99 -Wall -Wextra  -g
 $ valgrind  --track-origins=yes ./main
 (...)
 ==24100== Conditional jump or move depends on uninitialised value(s)
==24100==    at 0x4009B4: comment_start (main.c:85)
==24100==    by 0x4009B4: no_comments (main.c:54)
==24100==    by 0x40062E: main (main.c:21)
==24100==  Uninitialised value was created by a stack allocation
==24100==    at 0x400620: main (main.c:20)
==24100==
==24100== Conditional jump or move depends on uninitialised value(s)
==24100==    at 0x4009CA: quote_start (main.c:102)
==24100==    by 0x4009CA: no_comments (main.c:62)
==24100==    by 0x40062E: main (main.c:21)
==24100==  Uninitialised value was created by a stack allocation
==24100==    at 0x400620: main (main.c:20)
==24100==
==24100== Conditional jump or move depends on uninitialised value(s)
==24100==    at 0x518C1B2: vfprintf (in /lib64/libc-2.21.so)
==24100==    by 0x51928E8: printf (in /lib64/libc-2.21.so)
==24100==    by 0x400640: main (main.c:23)
==24100==  Uninitialised value was created by a stack allocation
==24100==    at 0x400620: main (main.c:20)
=


The problem lies inside get_input(), exactly in this line:

input[++i] = '\0';


Add printing value of i after each iteration and after the pre-incrementation. You will see something like this:

i == 0
i == 1
i == 2
i == 3
i == 4
i == 5
i == 6
i == 7
i == 8
i == 9
i == 11


Position 10 is not set. However, later on in no_comments() you have a loop:

for (int idx = 0; idx &lt;= len; idx++) {
    if (strlen(comments) == 0) { // outside comment

        if (!quoted &amp;&amp; comment_start(input, idx)) {


Input array and index are passed to comment_start() and read there:

return input[idx] == '/' &amp;&amp; (nxt == '*' || nxt == '/');


At some point you will read an element of input array that has not been initialized. It's an undefined behavior in C and it's quite dangerous.