Я работал над более крупной программой, и memcpy вызывал ее сбой. Я воспроизвел ситуацию в небольшой программе, и она делает то же самое. Я заметил, что по какой-то причине эта программа работает нормально
// Runs fine
#include <iostream>
int main() {
char* s1 = "TEST"; // src
char* s2; // dest
memcpy(s2, s1, strlen(s1) + 1);
std::cout << s2 << std::endl; // Should print "TEST"
return 0;
}
Но эта программа вылетает
// Crashes
#include <iostream>
int main() {
char* s1 = "TEST"; // src
char* s2 = ""; // dest - Note the small change
memcpy(s2, s1, strlen(s1) + 1);
std::cout << s2 << std::endl; // Should print "TEST"
return 0;
}
Я не уверен, почему это происходит. Может кто-нибудь объяснить, почему это происходит сбой?
Спасибо!
Обе программы имеют неопределенное поведение. Так что, если первый не дает сбоя (он разыменовывает неинициализированный указатель!), Просто вам не повезло.
Пункт назначения (первый аргумент memcpy
) должна быть выделенной и доступной для записи зоной. Либо локальный массив (или некоторый указатель на локальные данные в стеке, возможно, в кадре некоторого вызывающего) — или некоторый указатель на глобальные или статические данные -:
char arr[32];
memcpy (arr, s1, strlen(s1)+1);
или выделенная куча зона:
char*ptr = malloc(32);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
memcpy (ptr, s1, strlen(s1)+1);
Обратите внимание, что в общем случае буквенные строки "ABC"
являются не доступен для записи. Они находятся в сегменте данных только для чтения.
Выше C код. Если вы хотите код C ++, используйте new
(но в C ++ вы должны использовать std::string
)
Кстати, будьте очень осторожны, чтобы избежать переполнение буфера. Код выше работает, потому что в этом случае strlen(s1)
меньше 31
Причина memcpy
вызывает ошибку в том, что вы пытаетесь скопировать содержимое s1
в память, указанную строковым литералом, что является неопределенным поведением, потому что строковые литералы не доступны для записи, и даже если бы они были, места не было бы достаточно.
Ваш первый код тоже недействителен, потому что он делает memcpy
в память, указанную неинициализированным указателем — снова неопределенное поведение.
Вы можете исправить первый фрагмент кода, добавив вызов new
, как это:
char* s2 = new char[strlen(s1)+1];
Второй кусок кода можно исправить так:
char s2[5] = "";