[英]Heap corruption from memory allocation using malloc: why did it happen?
好的,我試圖像編程練習一樣實現memmove,當我嘗試使用malloc時,我在memmove函數中遇到了內存訪問沖突。 這是函數:
//Start
void* MYmemmove (void* destination, const void* source, size_t num) {
int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
for (int i = 0;num >= i;i++) {
refdes[i] = *(midbuf + i); // Copy midbuf to destination
}
free(midbuf); // free midbuf
refdes = NULL; // Make refdes not point to destination anymore
refsrc = NULL; // Make refsrc not point to source anymore
return destination;
}
順便說一句,我是指針的新手,所以如果有一些錯誤,請不要感到驚訝。 我究竟做錯了什么?
請注意其他建議! 答案取決於如何使用記憶。 其他答案指出,您應該更改malloc調用以考慮int的大小。 但是,如果將您的memmove函數用於表示“移動此字節數”,則實現將是錯誤的。 相反,我將繼續使用char *,因為它可以一次性解決多個問題。
另外,一個int
通常為4個字節,而char
通常為1個字節。 如果收到的void*
地址不是字對齊的(不是4個字節的倍數),則將出現問題:要復制一個非字對齊的int,您將需要進行多次讀取和昂貴的位屏蔽。 這是低效的。
最終,發生內存訪問沖突,因為您每次都增加了midbuf int
指針,並且一次向前移動了4個字節 。 但是,您僅分配了num 個字節 ,因此最終將嘗試訪問分配的區域末尾的內容。
/** Moves num bytes(!) from source to destination */
void* MYmemmove (void* destination, const void* source, size_t num) {
// transfer buffer to account for memory aliasing
// http://en.wikipedia.org/wiki/Aliasing_%28computing%29
char * midbuf = (char *) malloc(num); // malloc allocates in bytes(!)
char * refdes = (char *) destination;
char * refsrc = (char *) source;
for (int i = 0; i < num; i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
for (int i = 0; i < num; i++) {
refdes[i] = *(midbuf + i); // Copy midbuf to destination
}
free(midbuf); // free midbuf
// no need to set the pointers to NULL here.
return destination;
}
通過逐字節復制,可以避免對齊問題,以及num本身不是4個字節的倍數的情況(例如3,因此int對於該移動太大)。
將字符串替換為malloc:
int* midbuf = (int *) malloc(num*sizeof(int));
問題是,你不分配num
INT但元素num
字節。
int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
你malloc
只num
個字節,但在循環中,您嘗試復制num
int
秒。 由於int
通常占用一個以上的字節,因此您訪問的范圍超出限制。
內存訪問沖突?
您正在嘗試訪問您無權訪問的內存。 也許您有一個空指針,或者該指針指向另一個程序或代碼段。
問題是,你mallocing num
字節到midbuf
,然后復制num
整數進去。 由於在大多數平台上int
都大於字節,因此您遇到了問題。 將您的malloc
更改為num*sizeof(int)
,您將不會遇到此問題。
有兩個問題需要研究
1.內存空間
(前提是MYmemmove
了自定義實現以按問題提示移動ints
)
int* midbuf = (int *) malloc(num * sizeof(int));
malloc
基於字節,並且將分配num個字節。 int *
是一個指向ints
的指針。 意味着midbuf[x]
將通過midbuf + sizeof(int)*x
訪問內存。 您要改為分配num ints
( ints
的大小取決於體系結構,通常為4或2個字節)。 因此, malloc(num * sizeof(int))
。
2.數組索引
for (int i = 0;num > i;i++) {
在C(和C ++)數組中,數組是從0開始的,即第一個索引是0
。 你做對了。 但這也意味着,如果保留num ints
,則可用索引將為0
到num-1
。 在您的循環中,由於條件num >= i
, i
將在0
到num
變化,這意味着您將訪問num+1
項目。 因此, num > i
(或i < num
) for
條件更好。
#include <stdlib.h> // did you included this?
void* MYmemmove (void* destination, const void* source, size_t num) {
char *Source = source, *Destination = destination;
char *Middle = malloc( sizeof(char) * num ); // midbuf
for (int i = 0; i < num ; i++) {
Middle[i] = Destination[i]; // Copy source to midbuf
}
for (int i = 0; i < num ; i++) {
Destination[i] = Middle[i]; // Copy midbuf to destination
}
free(Middle); // free memory allocated previously with malloc
return destination;
}
違反Acces可能是因為您沒有包括malloc所需的庫(如果忘記了函數定義,標准c不會在您的面前拋出錯誤)。 您不需要將指針標記為NULL,因為C中沒有垃圾回收(指針就是-指針。指向內存中某個點的地址,而不是內存本身)。
考慮像這樣的指針
指針的地址0x1243 0x4221地址-> {某種數據}
目標= 0x1243 *目標=當前地址為0x4221的任何值
您也不能索引空指針。 您必須首先將它們轉換為某種類型,以便編譯器知道它們需要多少偏移量。
Destination [x] = *(Destination + x)
一個char是1個字節,所以char指針實際上將被移動x個字節,但是一個int是4個字節,並且一個int指針將被移動4 * x個字節。 如果聽起來很技術,請不要太擔心,當您掌握到很低的水平時,這將很重要;)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.