簡體   English   中英

C編程輸入錯誤

[英]C Programming Input Error

int main(void) {
    char *input;
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

提示>輸入

RUN FAILED(退出值138,總時間:3秒)

代碼有什么問題? 必須是scanf()或第二個printf()。 輸入的長度未知。 很多人說過只需創建一個長度為'X'的char數組來保存輸入。 只是想知道為什么此代碼有效。

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}

您的特定問題是您在input沒有存儲空間。 這是一個未初始化的指針,指向內存中的隨機點,不太可能有用。

您可以使用類似:

char *input = malloc (100);
// check that input != NULL
// use it
free (input);

要么:

char input[100];

但是您使用scanf遇到了嚴重問題(請參見下文)。


切勿scanf使用無限制的%s (或其任何變體,除非您完全控制輸入)。 這是一種危險的做法,容易造成緩沖區溢出,越早擺脫習慣,越好。 類似於gets()

根據我的較早答案,下面的這段代碼(以及合並到其中的主要代碼)提供了一種獲取用戶輸入的安全方法。 您傳入一個可選提示,要加載輸入內容的緩沖區以及緩沖區的大小。

它將輸入返回到緩沖區的大小(如果有,則將其換行),然后在必要時清除其余行,以免影響下一個輸入操作。 如果文件結束或輸入時間過長,它將返回OK或錯誤指示(如果您想對它做一些事情,您仍然會得到輸入的第一部分)。

有了線路,就可以安全地sscanf到您的內心。 但是,在您的情況下,這不是必需的,因為您只是嘗試獲取字符串。 只需使用直接返回的緩沖區即可。

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

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

int main(void) {
    char input[10];
    int rc = getLine ("prompt> ", input, sizeof (input));
    switch (rc) {
        case NO_INPUT: printf ("\nNo input recieved\n"); break;
        case TOO_LONG: printf ("Too long, truncated input below:\n");
        default: printf("Your input was [%s]\n", input);
    }
    return 0;
}

試一試,它比scanf("%s")使用scanf("%s")更加強大。


至於您的更新,請問這為什么起作用:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}

這是未定義的代碼。 期。 您只為字符分配空間,但是掃描字符串。 由於字符串是所有字符的字符數組, 后跟一個零字符 ,因此您唯一可以安全輸入的字符串將為空。

任何其他內容都會寫入該字符以及堆棧上與該字符相鄰的任何字符。

這與分配char input[100]然后輸入200個字符沒有什么不同,它仍然是緩沖區溢出,應該避免。

下面的討論基於C的特定實現 ,不一定基於所有實現。

很有可能,您在這里很幸運。 編譯器可能會生成使堆棧指針對齊的代碼,以便即使您要求一個字節,也可能會為四個分配空間(甚至更多,這取決於體系結構-為了簡單起見,我將假定大多數類型為四個字節) )。

此外,您可能會發現還可以安全地覆蓋argc整數和argv指針的八個字節(即使您不使用它們,它們也可能仍然存在,沒有意義的是,只有兩套不同的啟動代碼可以在堆棧上保存幾個字節)。

如果您編寫的內容超出此范圍,最終將覆蓋從main到您的啟動代碼的返回地址。 然后您將了解它,因為當main出口退出時,您的代碼將進入la-la land。

具有不確定的行為, 任何事情都會發生。 有時, 任何事情都包括它可能完美運行的可能性(類似於“經常在空中扔一副紙牌,它們最終會落入一個整齊,整齊的分類堆中”,但隨機性要小一些)。

這樣做不會使未定義的行為成為一件壞事。

  char *input;

只是一個指針-沒有分配的數據空間存儲scanf收集的數據。

試試這個代替

char input[100];

您可能希望在具有分隔字符的while循環內嘗試scanf("%c", input) 您還應該使輸入成為數組char input[X] ,其中X是足以容納輸入的最可能值的數量。 我會嘗試首先使輸入成為數組。

您使用什么編譯器? 在Turbo C 3.0中,它可以工作。 試試這個變體:

#include <stdio.h>
#include <alloc.h>
int main(void) 
{
    char *input = (char*)calloc(100, sizeof(char));
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    free(input);
    return 0;
}

您忘記了在使用指針之前分配內存。

試試吧:

int main(void) {
    char input[256];
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

甚至:

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    char *input = (char *) malloc(sizeof(char) * 256));
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

嘗試:-

int main(void) { 
char input[100]; 
printf("prompt>"); 
scanf("%99s", input); 
printf("%s", input); 
return 0; 

}

這會將字符串限制為99個字節。 注意“%s” ==用空格或換行符分隔的字符串,即。 您只會得到第一個字!

我認為您真正想要的是:

#include <stdio.h>
int main(void) { 
    char input[99]; 
    printf("prompt>"); 
    fgets(input,99,stdin);
    printf("->%s<-", input); 
    return 0; 
} 

您可能需要添加一些代碼來擺脫不需要的換行符!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM