Разбор строк в C с помощью strtok

У меня есть этот небольшой исходный код, созданный для тестирования синтаксического анализа строки, похожей на переменную string, которую мне нужно использовать в другом проекте.

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


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;


    s = (char*) calloc(1, sizeof(char));
    hand[1] = (char*) calloc(3, sizeof(char));
    hand[2] = (char*) calloc(3, sizeof(char));
    hand[3] = (char*) calloc(3, sizeof(char));
    usr = (char*) calloc(21, sizeof(char));

    s = strtok (string,"-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    hand[3] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);

    return 0;
}

Проблема в том, что я получил эти 3C:AC:2C:3C:BOB в результате printf вместо C:AC:2C:3C:BOB.

-------РЕДАКТИРОВАТЬ-----

Код без утечек памяти. Проблема остается

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


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;

    s = strtok (string,"-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    hand[3] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);

    return 0;
}

person Arrigo Pierotti    schedule 12.08.2013    source источник
comment
У вас есть утечки памяти в ваших программах. Сначала вы выделяете память и назначаете набор указателей, затем вы перезаписываете эти указатели результатом из strtok.   -  person Some programmer dude    schedule 12.08.2013
comment
Хорошо, редактирование всей части распределения с помощью calloc не решает основную проблему.   -  person Arrigo Pierotti    schedule 12.08.2013
comment
@ArrigoPierotti удалите все строки calloc(), затем скомпилируйте и запустите снова   -  person Grijesh Chauhan    schedule 12.08.2013
comment
Код @GrjeshChauhan отредактирован, но проблема осталась   -  person Arrigo Pierotti    schedule 12.08.2013
comment
Массивы в C имеют индекс 0.   -  person alk    schedule 12.08.2013


Ответы (5)


Вы объявляете массив hand состоящим из трех элементов, затем индексируете его, используя индексы с 1 по 3. Но массивы в C имеют индексы от 0 до size-1 (например, 2 в вашем случае).

Таким образом, вы пишете/читаете в/из массива, что приводит к неопределенному поведению.

Измените индексы вашего массива на 0-2, и все должно работать нормально.

person Some programmer dude    schedule 12.08.2013
comment
О блин ›_› Не заметил этой дурацкой ошибки ›_› Программа теперь работает корректно, спасибо - person Arrigo Pierotti; 12.08.2013

В вашем коде у вас есть проблема вне индекса, которая вызывает неопределенное поведение во время выполнения:

hand[3] = strtok (NULL, "-"); 
     ^

printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);
                                                     ^
                                                 wrong index value   

Помните, что значение индекса в массиве начинается с 0 в соответствии с объявлением char* hand[3]; значения индекса могут быть от 0 до 2

person Grijesh Chauhan    schedule 12.08.2013
comment
О блин ›_› Не заметил этой дурацкой ошибки ›_› Программа теперь работает корректно, спасибо - person Arrigo Pierotti; 12.08.2013
comment
@ArrigoPierotti еще одна вещь: strtok() изменяет входную строку и заменяет все разделители на \0 - person Grijesh Chauhan; 12.08.2013
comment
@ArrigoPierotti проверьте этот ответ Что я хочу сказать, если вы готовы изменить свою строку, просто замените - на : в исходной строке. - person Grijesh Chauhan; 12.08.2013

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


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;

    s = strtok (string,"-");
    hand[0] = strtok (NULL, "-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[0], hand[1], hand[2], usr);

    return 0;
}

Вам не нужно calloc ваши указатели, так как strtok() вернет действительный адрес памяти (фактически strtok() изменяет строку и заменяет разделитель нулевым символом). Другая проблема — это индексы массива: в C индекс начинается с 0. Первый элемент hand — это hand[0], а последний — hand[2].

person nouney    schedule 12.08.2013

Вот стек вашей программы:

+-----------------------+
|       ...
|
|0x***00 hand[0]
|
|
|           
|0x***04 hand[1]       
|
|
|     
|0x***08 hand[2]           
|                  
|
|
|0x***0C hand[3]    
|                       <---hander[1] pointer this address    
|    
|______  hand[3] end here 

Итак, рука[3] использует адрес, покрывающий *руку[1], это 3C приходите

person Lidong Guo    schedule 12.08.2013

Во-первых, вы должны аннотировать эти строки, чтобы избежать утечек памяти:

s = (char*) calloc(1, sizeof(char));
hand[1] = (char*) calloc(3, sizeof(char));
hand[2] = (char*) calloc(3, sizeof(char));
hand[3] = (char*) calloc(3, sizeof(char));
usr = (char*) calloc(21, sizeof(char));

Затем, после изменения кода, я создаю и запускаю результат в Windows и Linux, и ни один из них не получил вашего неожиданного результата печати.

person isayme    schedule 12.08.2013