-1

The code below might seem big, but it's really simple. I wanted to make an exercise generator in C, which concatenates latex formatted strings, stored in the function local arrays.

But the output is totally not what I expected it to be. I might have done something wrong with the pointers, or some overflow somewhere.

Tried all the tips I could find on internet:

(1) Initialize a string with '\0' at position 0; (2) Use a pointer to the string to pass to the function;

int create_exercise_string(char **s, int s_size) {
    // The format of the exercise is x+n=m;
    // ASCII 48-57 = '0' ... '9';
    int exercises_left = 10;
    char *exercise;
    char operation_list[][2] = {"+\0", "-\0"};
    char equal[] = "&=&"; // & is for centering on the item contained in latex;
    char array_begin[] = "\\begin{eqnarray*}\n";
    char array_end[] = "\\end{eqnarray*}";
    char number[1];

    strcat(*s, array_begin);
    s_size -= strlen(array_begin);

    //REMOVE
    puts("before exercise generation");
    while (exercises_left > 0 && s_size > 0) {
        exercise = malloc(256);
        if (!exercise) {
            puts("allocating error, quitting...");
            getchar();
            exit(1);
        }

        exercise[0] = '\0';
// THE INTERESTED PART =================================================
        if (exercises_left < 10)
            strcat(exercise, "\\\\\n");
        printf("exercise number %d\n", exercises_left);
        strcpy(exercise, "x");
        //add an operator
        strcat(exercise, operation_list[rand() % 2]);
        // add a number
        number[0] = (rand() % 10) + 48;
        strcat(exercise, number);
        // add an equal
        strcat(exercise, equal);
        // add a number
        number[0] = (rand() % 10) + 48;
        strcat(exercise, number);
// END =================================================================
        s_size -= strlen(exercise);
        strcat(*s, exercise);
        free(exercise);
        exercises_left--;
    }
    //REMOVE
    puts("exercise generation ended");

    if (s_size < strlen(array_end)) {
        puts("create_exercise_string: buffer overflow detected, quitting...");
        getchar();
        exit(1); // for now... will be substituted with proper code
    }
    else strcat(*s, array_end);

    puts("allocation worked, returning in main");
    return exercises_left; // 0 if succesfull;
}

I was expecting the output to be like this

\begin{eqnarray*}
x-9&=&3\\
x+3&=&12\\
x-2&=&3\\
... 7 other exercises
\end{eqnarray*}

But I actually get

\begin{eqnarray*}
x-5\end{eqnarray*}&=&9\end{eqnarray*}x-9\end{eqnarray*}&=&2\end{eqnarray*}x+3\end{eqnarray*}&=&1\end{eqnarray*}x-7\end{eqnarray*}&=&0\end{eqnarray*}x+6\end{eqnarray*}&=&1\end{eqnarray*}x-6\end{eqnarray*}&=&5\end{eqnarray*}x+6\end{eqnarray*}&=&8\end{eqnarray*}x-8\end{eqnarray*}&=&6\end{eqnarray*}x+4\end{eqnarray*}&=&5\end{eqnarray*}x+1\end{eqnarray*}&=&5\end{eqnarray*}\end{eqnarray*}

With no \n added overall, and some \end{eqnarray*} repeatedly added...

What is wrong?

  • 1
    For one `char number[1]` should be `char number[2]` -- you always need a byte for the null-string terminator. – gstukelj Sep 17 '19 at 17:52
  • `exercise[0] = '\0'` I think this is also problematic, since whatever you'll *concatenate* to the end of the string will be ignored because the null character will be encountered before. – gstukelj Sep 17 '19 at 17:57
  • @GasperStukelj it should replace the '\0' with the initial character of the appending string... there is a '\0' missing somewhere, and I am trying to figure it out. strcat() should always append a terminating null to a string, the problem should be in the way I have declared some strings... maybe referring to one of them doesn't have a terminating null, and this string is right before \end{enqarray*}, so it gets wrote again, and the end of this there is surely a '\0'... now I also need to understand why \\\\\n is not appended. I have to say my coding is a bit of a mess! – randomizzatore Sep 17 '19 at 18:33
  • ... you also need to nul-terminate the corrected `char number[2]` after writing the digit to `number[0]`. You can't use `strcat()` without that terminator on all strings, and it is not present by default. – Weather Vane Sep 17 '19 at 18:34

1 Answers1

-1

I managed to fix it.

All I can say is, when working with strings, always keep in mind if the terminating character is added or not, so in my case, I need to reinforce the study of strings allocation in C.

The problem was the variable number[1].

number[0] = rand() % 10 + 48;

This code adds the char representation of a number between 0 and 9 [48,57] in ASCII.

But it doesn't add a terminating null character!

Everytime I concatenated number to the exercise string, it overflowed to another local variable which had the terminating null character, thus the "undefined behaviour" of strcat() was that it kept reading another local variable.

Lucky me in memory there was a '\0' minefield, otherwise I would have needed to bang my head on the wall, if protected memory was tried to be read.

Thanks for the help!