2011-10-30 70 views
3

我是一個新手程序員,但通常我可以解開我自己的問題。這一次我解決了這個問題,但它仍然困擾着我。一位朋友建議我向這個社區徵求意見。sprintf緩衝區大小

我試圖在C中打印數字。我有一個函數使用sprintf來執行此操作。數字不能超過2位,所以我使用2個字符的緩衝區。不知何故,這是我的邏輯失敗的地方,因爲這會通過修改傳遞給sprintf的變量之一導致無限循環,但增加緩衝區大小可解決問題。

這裏的失敗代碼:

#include <stdio.h> 

void printarray(int array[][4]) { 
    int y; 
    int z; 
    char buf[2]; 
    for (y=0; y<4; y++) { 
    for (z=0; z<4; z++) { 
     sprintf(buf, "%d", array[y][z]); 
     printf("buf is %s, y is %d and z is %d\n",buf,y,z); 
    } 
    } 
} 

int main() { 
    int arr[4][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0} }; 

    printarray(arr); 

    return 0; 
} 

儘快爲y到達2,它被重置爲0,這樣無限循環。改變buf [2]到buf [8]解決了這個問題。

+2

當buf被溢出時,無限循環發生的原因是因爲sprintf將buf [2]設置爲'\ 0'。很可能在堆棧buf之後是z(小端)。因此,z的低字節被設置爲0,因爲高字節已經爲0,所以每次將z設置爲0。 – jstanley

回答

11

你忘記了NUL終結者。在C,strings需要終止一個額外的角色,所以char buf[2]應該是char buf[3]至10和99

順便之間容納號,你的代碼說明了爲什麼sprintf是危險的,因爲它可以寫過去的輸出緩衝區,並啓用stack smashing attacks。更好的選擇是使用snprintf

3

C字符串以null結尾。如果你有2個字符(例如「10」),你需要一個2 + 1的空終止符的緩衝區。

sprintf()將此添加到緩衝區的末尾;在你目前的情況下,你實際上有一個緩衝區溢出,因爲你沒有提供足夠的空間。

現代的,更安全的方法是使用您提供緩衝區長度的snprintf()

2

我假設sprintf在生成的字符串的末尾添加了一個\0。因此,例如,如果您打印號碼99,則會在緩衝區中獲得"99\0",因此對於長度爲2的緩衝區,會導致問題。