C strtok () разделяет строку на токены, но сохраняет старые данные без изменений

У меня есть следующий код:

#include  #include  int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = str; strcpy(fname, strtok(str, "|")); strcpy(lname, strtok(NULL, "|")); strcpy(city, strtok(NULL, "|")); strcpy(zip, strtok(NULL, "|")); strcpy(country, strtok(NULL, "|")); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); return 0; } 

Выход выполнения:

 $ ./str Firstname: John Lastname: Doe City: Melbourne Zip: 6270 Country: AU STR: John OLDSTR: John 

Почему я не могу хранить старые данные и ни str ни oldstr , что я делаю неправильно, и как я не могу изменить данные или сохранить их?

когда вы выполняете strtok(NULL, "|") strtock, найдите токен и поместите нуль на место ( замените токен на \0 ) и измените строку.

вы str , становится:

 char str[] = John0Doe0Melbourne062700AU; Str array in memory +------------------------------------------------------------------------------------------------+ |'J'|'o'|'h'|'n'|0|'D'|'o'|'e'|0|'M'|'e'|'l'|'b'|'o'|'u'|'r'|'n'|'e'|0|'6'|'2'|'7'|'0'|0|'A'|'U'|0| +------------------------------------------------------------------------------------------------+ ^ replace | with \0 (ASCII value is 0) 

Рассмотрим диаграмму, потому что char '0' и 0 являются неустойчивыми (в строке 6270 указаны символы char в фигуре в скобках, где ' где для \0 0 – это число»)

когда вы печатаете str, используя %s печатайте символы до первого \0 , а именно John

Чтобы ваша исходная строка не изменилась, вы должны скопировать str в некоторую переменную tempstr, а затем использовать эту строку tempstr в strtok() :

 char str[] = "John|Doe|Melbourne|6270|AU"; char* tempstr = calloc(strlen(str)+1, sizeof(char)); strcpy(tempstr, str); 

Теперь используйте эту строку tempstr вместо str в вашем коде.

Поскольку oldstr – это просто указатель, присваивание не создаст новую копию вашей строки.

Скопируйте его перед передачей str в strtok :

  char *oldstr=malloc(sizeof(str)); strcpy(oldstr,str); 

Ваша исправленная версия:

 #include  #include  #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); ................... free(oldstr); return 0; } 

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

Как отметил @CodeClown, в вашем случае лучше использовать strncpy . И вместо того, чтобы фиксировать размеры fname т. Д., Вы можете иметь указатели на своем месте и выделять память, как требуется, не больше и не меньше. Таким образом, вы можете избежать записи в буфер за пределами …

Другая идея: было бы назначить результат strtok указателям *fname , *lname и т. Д. Вместо массивов. Кажется, что strtok предназначен для использования таким образом после просмотра принятого ответа.

Внимание: таким образом, если вы измените str дальше, что будет отражено в fname , также lname . Потому что они просто указывают на данные str но не на новые блоки памяти. Итак, используйте oldstr для других манипуляций.

 #include  #include  #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char *fname, *lname, *city, *zip, *country; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); fname=strtok(str,"|"); lname=strtok(NULL,"|"); city=strtok(NULL, "|"); zip=strtok(NULL, "|"); country=strtok(NULL, "|"); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); free(oldstr); return 0; } 

strtok требует записываемой входной строки и изменяет входную строку. Если вы хотите сохранить входную строку, вам нужно сначала сделать ее копию.

Например:

 char str[] = "John|Doe|Melbourne|6270|AU"; char oldstr[32]; strcpy(oldstr, str); // Use strncpy if you don't know // the size of str 

Вы просто скопируете указатель на строку, но не самую строку. Используйте strncpy() для создания копии.

 char *oldstr = str; // just copy of the address not the string itself!