Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting incorrect values when accessing variables passed along in a pointer to a character array for strtok

Here is my code

//Split up the config by lines
int x;
int numberOfConfigLines = 0;
for (x = 0; x < strlen(buffer); x++)
{
    if (buffer[x] == '\n') {
        numberOfConfigLines++;
    }
}
char *configLines[numberOfConfigLines];
tokenize(configLines, buffer, "\n", numberOfConfigLines);

The idea of this function is to count the amount of newlines in a buffer, then split the buffer into a strtok array using this:

#include <string.h>
#include <stdlib.h>

void tokenize(char **arrToStoreTokens, char *delimitedString, char *delimiter, int expectedTokenArraySize) {
    //Create a clone of the original string to prevent making permanent changes to it
    char *tempString = (char *)malloc(strlen(delimitedString) + 1);
    strcpy(tempString, delimitedString);

    if (expectedTokenArraySize >= 1) {
    arrToStoreTokens[0] = strtok(tempString, delimiter);

        int x;
        for (x = 1; x < expectedTokenArraySize; x++ ) {
            arrToStoreTokens[x] = strtok(NULL, delimiter);
        }
    }

    //Dispose of temporary clone
    free(tempString); 
}

If I access arrToStoreTokens[0] directly, I get the correct result, however when I try to access configLines[0] once thetokenize function has ended, I get different results (can be unknown characters or simply empty)

Additionally, I believe this has only started occurring once I began running the program as root (for a different requirement) - I may be wrong though. - EDIT: Confirmed not to be the problem.

Any ideas?

like image 932
Adam Nygate Avatar asked Sep 28 '22 08:09

Adam Nygate


1 Answers

strtok doesn't reallocate anything. It only makes cut and pointers of what you gave to it.

Your array stores pointers that strtok gives you, but don't copy contents.

So if you free your tempString variable, you free data that was pointed by return values of strtok. You have to keep it and free it only at the end.

Or you can make a strdup of each return of strtok to store it in your array to make a real copy of each token, but in this case, you shall have to free each token at the end.

The second solution would looks like this :

void tokenize(char **arrToStoreTokens, char *delimitedString, char *delimiter, int expectedTokenArraySize) {
    //Create a clone of the original string to prevent making permanent changes to it
    char *tempString = (char *)malloc(strlen(delimitedString) + 1);
    strcpy(tempString, delimitedString);

    if (expectedTokenArraySize >= 1) {
    arrToStoreTokens[0] = strdup(strtok(tempString, delimiter)); // Here is the new part : strdup

        int x;
        for (x = 1; x < expectedTokenArraySize; x++ ) {
            arrToStoreTokens[x] = strdup(strtok(NULL, delimiter)); // Here is the new part : strdup
        }
    }

    //Dispose of temporary clone
    free(tempString); 
}

And after use of this array, you shall have to delete it, with a function like this :

void deleteTokens(char **arrToStoreTokens, int arraySize)
{
    int x;
    for (x = 0; x < arraySize; ++x)
    {
        free(arrToStoreTokens[x]);
    }
}
like image 80
Aracthor Avatar answered Oct 11 '22 13:10

Aracthor