Я пишу функцию, которая получает переменную среды пути системы, разделяет каждый путь, а затем объединяет некоторые другие дополнительные символы в конец каждого пути.
Все работает нормально, пока я не использую функцию strcat() (см. Код ниже).
char* prependPath( char* exeName )
{
char* path = getenv("PATH");
char* pathDeepCopy = (char *)malloc(strlen(path) + 1);
char* token[80];
int j, i=0; // used to iterate through array
strcpy(pathDeepCopy, path);
//parse and split
token[0] = strtok(pathDeepCopy, ":"); //get pointer to first token found and store in 0
//place in array
while(token[i]!= NULL) { //ensure a pointer was found
i++;
token[i] = strtok(NULL, ":"); //continue to tokenize the string
}
for(j = 0; j <= i-1; j++) {
strcat(token[j], "/");
//strcat(token[j], exeName);
printf("%s\n", token[j]); //print out all of the tokens
}
}
Вывод моей оболочки такой (я объединяю "/ which" на все):
...
/usr/local/applic/Maple/bin/which
which/which
/usr/local/applic/opnet/8.1.A.wdmguru/sys/unix/bin/which
which/which
Bus error (core dumped)
Мне интересно, почему strcat отображает новую строку, а затем повторяет which/which.
Еще меня интересует Bus error (core dumped) в конце.
Кто-нибудь видел такое раньше при использовании strcat()?
И если да, то кто нибудь знает как исправить?
Спасибо
В вашем коде отсутствует какой-то 'символы: char pathDeepCopy = (char) malloc (strlen (path) + 1); токен char [80];
@ bk1e: OP действительно ввел их, но SO интерпретировал их как форматирование курсивом.





strtok () токенизируется на месте. Когда вы начинаете добавлять символы к токенам, вы перезаписываете данные следующего токена.
Кроме того, как правило, небезопасно просто объединять с существующей строкой, если вы не знаете, что размер буфера, в котором находится строка, достаточно велик для хранения результирующей строки. Это основная причина ошибок в программах на C (включая ужасные ошибки безопасности, связанные с переполнением буфера).
Таким образом, даже если strtok () вернет совершенно новые строки, не связанные с вашей исходной строкой (а это не так), вы все равно будете переполнять строковые буферы при объединении с ними.
Некоторые более безопасные альтернативы strcpy () / strcat (), которые вы, возможно, захотите изучить (вам может потребоваться отслеживать реализации для некоторых из них - они не все стандартные):
strncat ()
strlcpy () - похож на strncpy (), но призван быть более простым в использовании и более надежным (http://en.wikipedia.org/wiki/Strlcat)
strlcat ()
strcpy_s () - варианты этих функций от Microsoft
И API, который вы должны стремиться использовать, если можете использовать C++: класс std :: string. Если вы используете класс C++ std :: string, вам практически не нужно беспокоиться о буфере, содержащем строку - класс управляет всем этим за вас.
strtok не дублирует токен, а просто указывает на него в строке. Поэтому, когда вы помещаете '/' в конец токена, вы пишете '\ 0' либо в начале токена следующий, либо после конца буфера.
Также обратите внимание, что даже если strtok сделал возвращает копии токенов вместо оригиналов (чего не делает), он не выделяет дополнительное пространство для добавления символов, поэтому это все равно будет ошибкой переполнения буфера.
strtok () не дает вам новую строку. Он искажает входную строку, вставляя символ '\ 0' там, где был разделенный символ.
Таким образом, использование strcat (token [j], "/") поместит символ '/' вместо '\ 0'.
Также последний токен начнет добавлять «который» за пределами выделенной памяти в неизведанную память.
Вы можете использовать strtok () для разделения строки на части. Но если вы хотите добавить что-нибудь к токену, вам нужно сделать копию токена, иначе то, что вы добавляете, перетечет на следующий токен.
Также вам нужно больше заботиться о распределении памяти, вы теряете память повсюду :-)
PS. Если вам необходимо использовать C-Strings. используйте strdup (), чтобы скопировать строку.
char* prependPath( char* exeName )
{
char* path = getenv("PATH");
char* pathDeepCopy = strdup(path);
char* token[80];
int j, i; // used to iterate through array
token[0] = strtok(pathDeepCopy, ":");
for(i = 0;(token[i] != NULL) && (i < 80);++i)
{
token[i] = strtok(NULL, ":");
}
for(j = 0; j <= i; ++j)
{
char* tmp = (char*)malloc(strlen(token[j]) + 1 + strlen(exeName) + 1);
strcpy(tmp,token[j]);
strcat(tmp,"/");
strcat(tmp,exeName);
printf("%s\n",tmp); //print out all of the tokens
free(tmp);
}
free(pathDeepCopy);
}
Обратите внимание, что strdup () не является частью стандарта C, хотя он является частью POSIX.
замените это на
strcpy (pathDeepCopy, путь);
//parse and split
token[0] = strtok(pathDeepCopy, ":");//get pointer to first token found and store in 0
//place in array
while(token[i]!= NULL) { //ensure a pointer was found
i++;
token[i] = strtok(NULL, ":"); //continue to tokenize the string
}
// use new array for storing the new tokens
// pardon my C lang skills. IT's been a "while" since I wrote device drivers in C.
const int I = i;
const int MAX_SIZE = MAX_PATH;
char ** newTokens = new char [MAX_PATH][I];
for (int k = 0; k < i; ++k) {
sprintf(newTokens[k], "%s%c", token[j], '/');
printf("%s\n", newtoken[j]); //print out all of the tokens
}
это заменит перезапись содержимого и предотвратит дамп ядра.
Если вы используете C++, рассмотрите boost :: tokenizer, как обсуждалось в здесь.
Если вы застряли на C, подумайте об использовании strtok_r, потому что он реентерабелен и потокобезопасен. Не то чтобы вам это нужно в данном конкретном случае, но это хорошая привычка.
Да, и используйте strdup, чтобы создать дублирующую строку за один шаг.
Хорошо, во-первых, будь осторожен. Вы теряете память. Strtok () возвращает указатель на следующий токен, и вы сохраняете его в массиве символов. Вместо char token [80] должен быть char * token. Будьте осторожны также при использовании strtok. strtok практически уничтожает массив символов с именем pathDeepCopy, потому что он заменяет каждое вхождение ":" на '\ 0'. Как Майк Ф. сказал вам выше. Обязательно инициализируйте pathDeppCopy, используя memset из calloc. Поэтому, когда вы кодируете токен [i], нет способа узнать, на что указывает. А поскольку в токене нет действительных данных, он может выбросить дамп ядра из-за того, что вы пытаетесь выполнить конкатенацию. строка для другой, не имеющей данных валидации (токена). Perphaps th, что вы ищете, - это массив указателей на char, в котором будет храниться весь указатель на токен, возвращаемый strtok, и в этом случае токен будет похож на char * token [];
Надеюсь это немного поможет.
Я думаю, что «токен» на самом деле является символом * [80], но SO интерпретировал «*» как курсивное форматирование.
и не забудьте проверить, возвращает ли malloc NULL!
Это я или на SO много незарегистрированных Стивов?