strtok () со странным поведением reallo c () - PullRequest
0 голосов
/ 18 января 2020

У меня есть следующая программа, написанная на C:

    ...
    char *answer = NULL;
    char *pch = strtok(phrase, " "); // phrase is a string with possibly many words
    while (pch) {
        char *tmp = translate_word(pch); // returns a string based on pch
        void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000); // allocate space to answer
        if (!ptr) // If realloc fails
             return -1;
        strcat(answer, tmp); // append tmp to answer
        pch = strtok(NULL, " "); // find next word
    }
    ...

Проблема в том, что strtok () показывает странное поведение, возвращает слово, которого нет в фразе строка, но является частью ответа строки.

С другой стороны, когда я изменяю следующую строку:

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1000);

на:

void *ptr = realloc(answer, sizeof(answer) + sizeof(tmp) + 1);

strok () работает как положено.

Как это возможно, что reallo c () влияет на strtok () в этом случае? Они даже не используют одни и те же переменные. Ждем ваших идей.

Ответы [ 3 ]

5 голосов
/ 18 января 2020

Функция realloc может перемещать память, которая была ранее выделена. После вызова возвращается указатель на выделенную память и значение указателя, переданное ему, если оно отличается, больше не действует. Поэтому, когда вы вызываете strcat(answer, tmp);, вы потенциально пишете в освобожденную память, которая вызывает неопределенное поведение , и в этом случае это проявляется как странный вывод, который вы видите.

После проверки верните значение realloc, присвойте это значение обратно answer.

Кроме того, sizeof(answer) и sizeof(tmp) дают вам размер указателя, а не размер того, на что он указывает. Вместо этого вы хотите использовать strlen, чтобы получить длину строки, а затем содержать. И пока мы это делаем, давайте просто добавим к этому 1 вместо 1000, потому что это все, что вам действительно нужно.

    void *ptr = realloc(answer, strlen(answer) + strlen(tmp) + 1);
    if (!ptr)
         return -1;
    answer = ptr;
    strcat(answer, tmp);

Еще одна проблема: при первом вызове realloc память полностью неинициализируется , Впоследствии вызов strcat зависит от answer, содержащего завершенную нулем строку. Это не так, это также вызывает неопределенное поведение.

Это может быть исправлено с помощью malloc - для запуска одного байта и установки его в 0, таким образом, вы начинаете с пустой строки.

char *answer = malloc(1);
if (!answer) return -1;
answer[0] = 0;
2 голосов
/ 18 января 2020

sizeof (ответ) & sizeof (tmp) дает вам размеры указателей.

Вам нужно использовать strlen вместо

0 голосов
/ 18 января 2020

дополнительно ...

char *answer = NULL;

... либо:

... strlen(answer) ...
strcat(answer, tmp);

Эти СЛЕДУЕТ завершить с нарушением сегментации, но могут не зависеть от ОС. Разыменование NULL никогда не является хорошей идеей.

Короче говоря, вам нужно либо знать, что вы присвоили что-то для answer, либо проверить, равен ли NULL ответ.

...