2011-01-10 107 views
5

我有一個小問題,下面的代碼。這是一個簡單的程序,它讀取兩個char和一個int數組。然後將所有內容存儲到另一個字符串中並打印出來。錯誤:圍繞堆棧變量「串」被損壞

#include <stdio.h> 
#include <string.h> 

int main() 

{ 
    char string [50]; 
    char first [11]; 
    char last [16]; 
    int age = 0; 


    printf("Please type in your first name: "); 
     scanf("%s", first); 

    printf("Please type in your last name: "); 
     scanf("%s", last); 

    printf("Please type in your age: "); 
     scanf("%d", &age); 

    sprintf(string, "Your name is %s %s and you are %d years old.", first, last, age); 
     puts(string); 

    getchar(); 
    getchar(); 

    return 0; 
} 

現在程序運行良好,但是當我關閉它,我得到以下錯誤: 運行時檢查失敗#2 - 圍繞堆棧變量「字符串」已損壞。 這有點令人困惑,我找不出問題出在哪裏。我會感謝 任何建議。

+1

不相關,但如果您有C99(或保證其某些部分),則應該使用`snprintf`來代替以防止發生這種問題。 – 2011-01-10 07:21:44

回答

13

你寫更多的字符轉換成比它的房間分配給「串」(即大於50)

有在"Your name is %s %s and you are %d years old." 37個字符之前,您爲先,最後和年齡的增加值。這三個變量只剩下13個字符。所以它會溢出到棧上的變量'string'之後聲明的其他變量中。

正如喬恩所說,它是使用限制多少,他們寫的(「N」個變種)功能的最佳實踐,否則這些都可以bufferoverrun攻擊的來源。

順便說一句「字符串」是一個可變的一個非常可憐的名字。

1

我猜這是什麼做的事實string數組的長度爲50個字符,你在sprintf的37(如果我算右),加上隨後長達11 first另有16 last ,加上年齡可能爲2或3。總計超過50個。一切正常,但你很可能覆蓋超過50個字符分配的結尾。正如你所觀察到的那樣,這將「起作用」,但會腐蝕堆棧。

從別的
4

除此之外,你允許的最多10個字符的名字和最多15個字符的姓氏。如果這些限制達到(但不超過)和年齡是一個兩位數,這將需要66個字符 - 這樣你就必須聲明string是67個字符數組來應付(包括空終止符)。

除此之外,你應該使用函數或格式字符串,它允許你限制輸入的大小 - 目前如果有人輸入超過10個字符的名字(等等),你會踐踏其他位的內存。我寫了C語言已經有一段時間了,但使用格式字符串「%10s」和「%15s」可能會有所幫助,或者使用fgets

同樣,我會建議使用snprintf(或snprintf_s如果它提供給你),而不是sprintf避免超速輸出問題。使用所有這些方法的返回值來檢測錯誤,太:)

+0

您可以使用`scanf`限制尺寸,但在達到上述限制時恢復到正常狀態會造成不必要的困難,因此建議使用+1來實現其他功能。 – 2011-01-10 07:20:29

2

您可以限制字符的scanf函數讀取量與

scanf("%9s", foo) 

將讀取最多9個字符,然後附加一個NUL,這適用於大小爲10的緩衝區。