[英]Need help with malloc in C programming. It is allocating more space than expected
讓我先說一下,我是一個新手,我在學校的入門級C班。
我正在編寫一個程序,要求我使用malloc和malloc在所有情況下分配8倍我期望的空間。 即使只是對malloc(1),它是分配8個字節而不是1,我很困惑為什么。
這是我測試過的代碼。 這應該只允許輸入一個字符加上轉義字符。 相反,我可以輸入8,所以它分配8 bytes
而不是1
,即使我只使用malloc()
的整數也是如此。 請忽略x
變量,它在實際程序中使用,但不在此測試中。 :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc ,char* argv[]){
int x = 0;
char *A = NULL;
A=(char*)malloc(sizeof(char)+1);
scanf("%s",A);
printf("%s", A);
free(A);
return 0;
}
A=(char*)malloc(sizeof(char)+1);
將分配至少2個字節(sizeof(char)始終為1)。 我不明白你是如何確定它分配8個字節,但是malloc被允許分配比你要求的更多的內存,只是永遠不會少。
您可以使用scanf將更長的字符串寫入A指向的內存這一事實並不意味着您已分配了該內存。 它會覆蓋那里的任何內容,這可能會導致程序崩潰或產生意外結果。
malloc
正在分配你所要求的內存。
如果您可以讀取超過分配的字節數(使用scanf
),那是因為scanf
也在您擁有的內存上讀取:它是緩沖區溢出。
您應該限制數據scanf
可以這樣讀取:
scanf( "%10s", ... ); // scanf will read a string no longer than 10
我正在編寫一個程序,要求我使用malloc和malloc在所有情況下分配8倍我期望的空間。 即使只是對malloc(1),它是分配8個字節而不是1,我很困惑為什么。
從理論上講,你在程序中做事的方式是不分配8 bytes
。
您仍然可以鍵入8個字節(或任意數量的字節),因為在C中沒有檢查,您仍然使用有效的寫入位置。
你看到的是Undefined Behaviour
,原因是你在內存中寫下你不應該這樣做。 在使用了您分配的n
個字節后,代碼中沒有任何內容可以停止程序。
您可能現在或稍后或從不會遇到Seg Fault
。 這是未定義的行為。 僅僅因為它似乎有效,並不意味着它是正確的。
現在,您的程序確實可以分配8個字節而不是1個字節。
原因是因為對齊
同一程序可能在不同的機器和/或不同的操作系統中分配不同的大小。
此外,由於你使用C
你真的不需要施放。 看一下這個開始。
在您的代碼中,使用scanf
可以加載多少數據沒有限制,從而導致緩沖區溢出(安全漏洞/崩潰)。 您應該使用格式字符串將讀取的數據量限制為您分配的一個或兩個字節。 malloc
函數可能會分配一些額外的空間來擴大規模,但你不應該依賴它。
你在運行什么系統? 如果是64位,系統可能會分配盡可能小的單位。 64位是8個字節。
編輯:只是一個感興趣的說明:
char *s = malloc (1);
導致在iOS 4.2(Xcode 3.2.5)上分配16個字節。
允許malloc分配比你要求的內存更多的內存。 它只需要提供至少與您要求的一樣多,或者如果不能提供則失敗。
使用malloc或在堆棧上創建緩沖區將以單詞分配內存。
在32位系統上,字大小為4字節,所以當你要求時
A=(char*)malloc(sizeof(char)+1);
(基本上是A=(char*)malloc(2);
系統實際上會給你4個字節。 在64位計算機上,您應該獲得8個字節。
您使用scanf
的方式很危險,因為如果字符串大於分配的大小,它會溢出緩沖區,從而在程序中留下堆溢出漏洞。 在這種情況下, scanf
會嘗試將任意長度的字符串填充到該內存中,因此使用它來計算分配的大小將不起作用。
如果你輸入8
如果只是分配2個字節sizeof(char) == 1 (unless you are on some obscure platform)
,你將把你的數字寫給那個char。 然后在printf
輸出你存儲在那里的數字。 因此,如果存儲數字8,它將在命令行上顯示8。 它與分配的字符數無關。 除非您在調試器或其他地方查找它實際上是在分配8個字節。
scanf
不知道目標緩沖區實際有多大。 它只知道緩沖區的起始地址。 C沒有邊界檢查,因此如果你傳遞一個大小為2個字符的緩沖區的地址,並輸入一個長度為10個字符的字符串, scanf
會在緩沖區末尾后將這8個字符寫入內存。 這稱為緩沖區溢出,這是一種常見的惡意軟件漏洞。 無論出於何種原因,緊跟緩沖區后的六個字節不是“重要”,因此您最多可以輸入8個字符,沒有明顯的不良影響。
您可以通過在轉換說明符中包含顯式字段寬度來限制scanf
調用中讀取的字符數:
scanf("%2s", A);
但是仍然需要確保目標緩沖區足夠大以容納該寬度。 不幸的是,沒有辦法像printf
一樣動態指定字段寬度:
printf("%*s", fieldWidth, string);
因為%*s
表示scanf
完全不同的東西(基本上,跳過下一個字符串)。
您可以使用sprintf
來構建格式字符串:
sprintf(format, "%%%ds", max_bytes_in_A);
scanf(format, A);
但你必須確保緩沖區format
足夠寬以保存結果等,等等。
這就是我通常建議用於交互式輸入的fgets()
原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.