【问题标题】:Scanf text overflow in CC中的Scanf文本溢出
【发布时间】:2015-01-19 02:43:11
【问题描述】:

我刚刚开始学习 C。这是我正在试验的一些示例代码。它只是为了获取用户名。如果我为第一个需要字符的答案输入一个字符串,则第一个字母将保存到 middleInitial,但后续的 scanf 将读取并保存字符串的其余部分,而不是被忽略。这意味着输入“Jacob”然后输入“Pat Smith”会导致输出“Your name is acob J Pat”。为什么会这样?

char middleInitial; 
printf("What is your middle initial?");

scanf(" %c", &middleInitial);

char firstName[30], lastName[30];

printf("What is your name? ");

scanf(" %s %s", firstName, lastName);

printf("Your name is %s %c %s", firstName, middleInitial, lastName);

【问题讨论】:

    标签: c overflow scanf


    【解决方案1】:

    我对 C 中的字符串 (char*) 用法有一些建议。 首先,正如 sumithdev 所说,在输入任何信息之前,使用 fflush(stdin) 清理输入流缓冲区。 其次,尽量使用统一的样式来存储所有的字符串数据。例如,您的 middleInitial 也可以定义为 char 数组,但长度可能为 2(middleInitial[0] 将是一个字符,middleInitial[1] 将是一个'\0')。 最后一条建议——尝试使用强大的函数来防止内存违规和数据丢失。 代码:

    scanf(" %s %s", firstName, lastName);
    

    我看到了潜在的问题:

    a) 通常用户的名字或姓氏可以多于一个单词,但 scanf 中的一个 %s 读取字符直到空格;

    b) 名字或姓氏可以大于 29 个字母,数组的 30 个元素不足以存储输入,这会导致运行时问题;

    c) 当您想更改名称不同部分的输入顺序或添加一些检查时,您的代码中会有很多硬修改。

    考虑以下版本:

    char middleInitial[2]; 
    char firstName[30], lastName[30];
    // asking for middle part
    printf("What is your middle initial? ");
    fflush(stdin); // delet all previous inputs
    scanf("%1s", middleInitial); // wait new inputs and take only 1 character
    // asking for first part
    printf("What is your first name? ");
    fflush(stdin);
    scanf("%29s", firstName); // wait new inputs and take not more than 29 characters
    // asking for last part
    printf("What is your last name? ");
    fflush(stdin);
    scanf("%29s", lastName); // wait new inputs and take up to 29 characters
    // output result
    printf("Your name is %s %s %s\n", firstName, middleInitial, lastName);
    

    并且还尝试使用 fgets 而不是 scanf。例如:

    fflush(stdin);
    fgets(firstName, 30, stdin); // this allows input of strings with spaces
    // but adds 'new line' (\n) in the end of string
    

    【讨论】:

      【解决方案2】:

      根据代码:

      scanf(" %c", &middleInitial);
      

      middleInitial 获取输入的唯一第一个字符。

      例如:您输入“Jacob”,然后输入“John Smith”:

      middleInitial = J
      firstName = acob
      lastName = John
      

      你应该试试:

      char middleInitial;
      char str[30];
      printf("What is your middle name?");
      
      scanf(" %c", &middleInitial); // get "J"
      scanf(" %s", &str);  // get "acob"
      char firstName[30], lastName[30];
      
      printf("What is your name? ");
      
      scanf(" %s %s", firstName, lastName);
      
      printf("Your name is %s %c %s", firstName, middleInitial, lastName);
      

      【讨论】:

        【解决方案3】:

        原因是第一个scanf 未获取的剩余字符留在STDIN 缓冲区中,然后被后续scanf 感染。 flush STDIN 在您阅读 firstnamelastname 之前。 由于fflush 不是删除 STDIN 缓冲区中不需要的字符的可靠方法,因此解释了手动方法here

        【讨论】:

        • fflush(stdin) 的建议是特定于平台的——有关更多信息,请参阅Using fflush(stdin)
        猜你喜欢
        • 2010-12-19
        • 1970-01-01
        • 2011-11-18
        • 2010-12-09
        • 1970-01-01
        • 2015-03-16
        • 1970-01-01
        • 2021-10-02
        • 1970-01-01
        相关资源
        最近更新 更多