Ошибка сегментации при использовании strcpy()?

У меня есть глобальная структура:

struct thread_data{
   char *incall[10];
   int syscall arg_no;
   int client_socket;
};

и в основном()

char buffer[256];
char *incall[10];
struct thread_data arg_to_thread;

strcpy(incall[0],buffer);   /*works fine*/
strcpy(arg_to_thread.incall[0],buffer); /*causes segmentation fault*/

Почему так происходит и подскажите пожалуйста выход.

Благодарность


person Lipika Deka    schedule 09.06.2011    source источник
comment
где вы выделяете память для хранения этих строк?   -  person Mat    schedule 09.06.2011
comment
не будет ли он автоматически сохраняться в стеке   -  person Lipika Deka    schedule 09.06.2011
comment
нет, все, что выделено, это 10 указателей.   -  person Mat    schedule 09.06.2011


Ответы (3)


Segfault означает, что что-то не так. Но отсутствие segfault не означает, что что-то исправно неправильно. Если две ситуации в основном одинаковы, и в одной возникает ошибка сегментации, а в другой нет, это обычно означает, что они обе неверны, но только одна из них вызывает ошибку сегментации.

Глядя на строку char* incall[10], это означает, что у вас есть массив из 10 указателей на char. По умолчанию эти указатели будут указывать на случайные места. Следовательно, strcpying в incall[0] будет копировать строку в случайное место. Это, скорее всего, приведет к segfault! Сначала вам нужно инициализировать incall[0] (используя malloc).

Итак, более важный вопрос: почему не первая строка segfault? Я бы предположил, что причина в том, что просто так получилось, что все, что было в памяти раньше, было действительным указателем. Таким образом, strcpy не segfault, он просто перезаписывает что-то еще, что позже приведет к совершенно неожиданному поведению. Поэтому вы должны исправить обе строки кода.

Еще одна проблема (после того, как вы это исправите) заключается в том, что strcpy сам по себе очень опасен - поскольку он копирует строки до тех пор, пока не найдет 0 байт, а затем останавливается, вы никогда не можете точно знать, сколько он собирается скопировать (если только вы не используете strlen для выделить память назначения). Поэтому вместо этого вы должны использовать strncpy, чтобы ограничить количество копируемых байтов размером буфера.

person mgiuca    schedule 09.06.2011
comment
«Осторожно»? Возможно, вы имели в виду «подозрительный» или «опасный» или... Если используется кем-то, кто знает, что делает (что означает, среди прочего, какова длина исходной строки и сколько места в буфере назначения) , strcpy() совершенно безопасно. Не все уверены, что они безопасны. (Есть аргумент, что если вы знаете длину строк, вы можете использовать memmove(), а иногда и memcpy(), чтобы сделать копирование строки более эффективным.) Помните, что strncpy() не гарантирует нулевое завершение вашего струны. (Использование strncat() еще более опасно!) - person Jonathan Leffler; 09.06.2011
comment
@Jonathan Leffler Это правда, но я даю совет тем, кто не знает, что делает (и я сказал, если вы не используете strlen для выделения целевой памяти). Но это очень хороший момент о strncpy - я не уверен, что хуже: перезапись буфера или наличие строки, не заканчивающейся нулем. (Я бы все же сказал, что первый хуже, поэтому предпочтите strncpy, а не strcpy.) - person mgiuca; 09.06.2011
comment
Это сложно. Стандартные строковые функции C оставляют желать лучшего (но они стандартны, широко доступны и могут безопасно использоваться с осторожностью). Отсутствие нулевого завершения в короткой копии настолько серьезно, что другие преимущества strncpy(), IMNSHO, перевешиваются плохим поведением в том случае, когда вам действительно нужно, чтобы оно вело себя разумно. Я бы смирился с его нулевым дополнением, если бы оно гарантировало нулевое завершение. В своем первоначальном применении ненулевое завершение было положительным достоинством, но теперь это древняя история. (Он был разработан для копирования 14-символьных имен файлов в каталогах Unix.) - person Jonathan Leffler; 09.06.2011

Вы не инициализировали указатель incall[0], так что одному Богу известно, куда пишет первый strcpy(). Вам не повезло, что ваша программа не падает сразу.

Вы не инициализировали указатель arg_to_thread.incall[0], поэтому только Бог знает, куда пишет второй strcpy(). Вам повезло, что ваша программа падает сейчас, а не позже.

Ни в том, ни в другом случае это не вина компилятора; вы всегда должны убедиться, что вы инициализируете свои указатели.

person Jonathan Leffler    schedule 09.06.2011

  1. Убедитесь, что у вас достаточно памяти, выделенной для ваших строковых буферов.
  2. Держитесь подальше от strcpy. Вместо этого используйте strncpy. strcpy — печально известный источник уязвимостей переполнения буфера — кошмар безопасности и обслуживания, которому на самом деле нет оправдания.
person tdammers    schedule 09.06.2011
comment
Помните, что strncpy() не гарантирует нулевое завершение ваших строк, если исходный код слишком длинный. Это также гарантирует нулевое заполнение вашей строки, если источник короче, чем место назначения. (Использование strncat() еще более опасно! Какой размер вы указываете в параметре длины? Ответ: не размер целевой строки!) - person Jonathan Leffler; 09.06.2011
comment
Я хочу сказать, что полагаться исключительно на дозорный для определения длины строки небезопасно. Явный перенос длин строк невозможен, хотя вы, конечно, все еще можете создавать ошибки. - person tdammers; 09.06.2011