memcpy вызывает сбой программы с инициализированным назначением

Я работал над более крупной программой, и 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;
}

Я не уверен, почему это происходит. Может кто-нибудь объяснить, почему это происходит сбой?

Спасибо!

1

Решение

Обе программы имеют неопределенное поведение. Так что, если первый не дает сбоя (он разыменовывает неинициализированный указатель!), Просто вам не повезло.

Пункт назначения (первый аргумент 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

2

Другие решения

Причина memcpy вызывает ошибку в том, что вы пытаетесь скопировать содержимое s1 в память, указанную строковым литералом, что является неопределенным поведением, потому что строковые литералы не доступны для записи, и даже если бы они были, места не было бы достаточно.

Ваш первый код тоже недействителен, потому что он делает memcpy в память, указанную неинициализированным указателем — снова неопределенное поведение.

Вы можете исправить первый фрагмент кода, добавив вызов new, как это:

char* s2 = new char[strlen(s1)+1];

Второй кусок кода можно исправить так:

char s2[5] = "";
2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector