2015-01-03 713 views
1

我正在研究一個更大的程序和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; 
} 

我不知道爲什麼會這樣。有人能解釋爲什麼它會崩潰嗎?

謝謝!

+0

如果編碼在C++中,你應該避免原始的'char *'指針,並使用'std :: string'和C++智能指針。 –

回答

2

這兩個程序都有undefined behavior。所以,如果第一個不會崩潰(它會解引用一個未初始化的指針!),這只是你不幸運而已。

目的地(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

順便說一句,要非常小心,以避免buffer overflows。上面的代碼工作,因爲在這種情況下strlen(s1)小於31

+0

感謝您的幫助!這修復了崩潰,並因此幫助我修復了另一個錯誤! – Xerif917

2

原因memcpy導致一個錯誤是,您要的s1內容拷貝到存儲指向一個字符串常量,這是不確定的行爲,因爲字符串文字不可寫,即使它們是,也沒有足夠的空間。

你的第一個代碼也是無效的,因爲它使得memcpy進入一個未初始化指針指向的內存 - 一個未定義的行爲。

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

代碼的第二片可以是固定的這樣的::

可以通過添加到new的呼叫時,類似這樣的固定的第一塊代碼

char s2[5] = "";