2013-12-16 49 views
6
#include<iostream> 
#include<string.h> 
#include<stdio.h> 


int main() 
{ 
    char left[4]; 
    for(int i=0; i<4; i++) 
    { 
     left[i]='0'; 
    } 
    char str[10]; 
    gets(str); 
    strcat(left,str); 
    puts(left); 
    return 0; 
} 

對於任何輸入它應該連接0000與該字符串,但在一臺電腦上顯示「0000」和輸入字符串之間的菱形符號...!我的程序在不同的機器上給出不同的輸出。

+5

你超越了緩衝區的末端。這確實是未定義的行爲。 –

+3

函數[gets()](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used)被棄用和危險,不要不會使用它。 – this

+2

left不是以零結尾的字符串。你需要定義 char left [5]; 然後在循環結束後添加[4] = 0; //注意0而不是'0' –

回答

6

您可以將一個可能的九個(或更多,gets沒有邊界檢查)字符串添加到三個字符的字符串(其中包含四個字符並且沒​​有字符串終止符)。根本沒有字符串終止。因此,當您使用puts進行打印時,它將繼續打印,直到找到一個字符串終止字符,這可能是在內存中的任何地方。這一點,在短,緩衝區溢出,和緩衝區溢出的學校書例如通常會導致未定義行爲這是你看到的。

在C和C++中,所有C風格的字符串都必須被終止。它們被特殊字符終止:'\0'(或純粹的ASCII零)。您還需要在strcat調用中爲目標字符串提供足夠的空間。


正確,工作程序:

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

int main(void) 
{ 
    /* Size is 4 + 10 + 1, the last +1 for the string terminator */ 
    char left[15] = "0000"; 
    /* The initialization above sets the four first characters to '0' 
    * and properly terminates it by adding the (invisible) '\0' terminator 
    * which is included in the literal string. 
    */ 

    /* Space for ten characters, plus terminator */ 
    char str[11]; 

    /* Read string from user, with bounds-checking. 
    * Also check that something was truly read, as `fgets` returns 
    * `NULL` on error or other failure to read. 
    */ 
    if (fgets(str, sizeof(str), stdin) == NULL) 
    { 
     /* There might be an error */ 
     if (ferror(stdin)) 
      printf("Error reading input: %s\n", strerror(errno)); 
     return 1; 
    } 

    /* Unfortunately `fgets` may leave the newline in the input string 
    * so we have to remove it. 
    * This is done by changing the newline to the string terminator. 
    * 
    * First check that the newline really is there though. This is done 
    * by first making sure there is something in the string (using `strlen`) 
    * and then to check if the last character is a newline. The use of `-1` 
    * is because strings like arrays starts their indexing at zero. 
    */ 
    if (strlen(str) > 0 && str[strlen(str) - 1] == '\n') 
     str[strlen(str) - 1] = '\0'; 

    /* Here we know that `left` is currently four characters, and that `str` 
    * is at most ten characters (not including zero terminaton). Since the 
    * total length allocated for `left` is 15, we know that there is enough 
    * space in `left` to have `str` added to it. 
    */ 
    strcat(left, str); 

    /* Print the string */ 
    printf("%s\n", left); 

    return 0; 
} 
+3

我稱它爲「school-book *緩衝區溢出的例子*「。不太一般的術語。 – jrok

0

問題#1 - 不是一個合法的字符串:

char left[4]; 
for(int i=0; i<4; i++) 
{ 
    left[i]='0'; 
} 

字符串必須以零字符結尾,'\0''0'。 這會導致您描述的內容。問題2 - fgets。你在一個小緩衝區上使用它。非常危險。

問題#3 - strcat。然後再次嘗試填充超級小緩衝區,該緩衝區應該已經充滿了額外的字符串。

此代碼查看緩衝區溢出攻擊的邀請。

0

在C中,我們所說的字符串是一個以NULL結束的字符數組。字符串庫中的所有函數都基於這個空字符數組的末尾。您的字符數組不是空終止的,因此是不是字符串,所以你不能在這裏使用字符串庫函數strcat。

2

有代碼問題。

首先,left沒有以nul結尾,所以strcat最終將超出數組末尾來尋找適當的位置來附加字符。在陣列的末尾放置一個。

其次,left是不是大到足以容納調用strcat的結果。結果字符串必須有足夠的空間,包括nul終止符。這樣的left應該至少4 + 9的大小,以允許三個字符(加上NUL終止子),其left開始時用,和9個字符從str到來(假設gets沒有造成溢出)。

每一個未定義的行爲,佔在不同平臺上不同的結果,這些錯誤的結果。

1

我不知道爲什麼你在包含<iostream>,因爲你沒有在代碼中使用任何C++特性。整個程序會更短,如果你有:

#include <iostream> 
#include <string> 

int main() 
{ 
    std::string line; 
    std::cin >> line; 
    std::cout << "You entered: " << line; 
    return 0; 
} 

由於std::string將是空值終止,沒有理由迫使它是4無效終止。

相關問題