【问题标题】:why the for-loop is running infinite?为什么for循环无限运行?
【发布时间】:2021-10-28 12:07:17
【问题描述】:

我尝试从用户添加值并存储在 char k 中,但 for 循环将无限循环,我想知道循环有什么问题。

#include <stdio.h>
#include <math.h>

void main() {

  char k[5];
  for(int i=0;i<5;i++){

    printf("enter char");
    scanf("%s",&k[i]);
   
  }    
}

【问题讨论】:

  • 我不建议您使用scanf 进行基于行的输入。函数fgets 更适合此目的。有关更多信息,请参阅本指南:A beginners' guide away from scanf()
  • 我试过了,但我在字符串末尾得到了垃圾值我如何删除它 char k[5]; k[5]="\0"; for(int i=0;i
  • 在描述软件问题时,请始终提供示例输入、针对该输入观察到的输出以及针对该输入的预期输出。您的代码中没有无限循环。它将调用scanf 五次。 scanf 将在收到一些非空格字符后跟一个空格字符后立即完成。如果您没有输入任何非空格字符,例如只按回车键而不输入任何内容,那么scanf 将继续扫描。
  • @IndratejReddy:带有%s 格式说明符的函数printf 需要一个以空字符结尾的字符序列。但是,您传递给 printf 的字符序列不是以 null 结尾的。
  • @IndratejReddy:使用"%c" 时,scanf 将提取它在输入流中看到的第一个字符,这可能是换行符。但是,如果您改用" %c",则scanf 将首先从流中提取并丢弃所有空白字符(空格、制表符、换行符等),然后再将字符提取并写入您指定的变量。因此,它永远不会将空格字符写入该变量。

标签: c scanf infinite-loop


【解决方案1】:

正如在 cmets 部分中已经指出的那样,问题在于该行

scanf("%s",&amp;k[i]);

错了。当使用scanf%s 格式说明符时,它将读取输入的整个单词并将该单词写入字符数组k(在您的情况下导致buffer overflow)。

如果您只想读取单个字符,则应使用%c 格式说明符而不是%s

但是,使用"%c" 的问题是它总是会读取输入流上的第一个字符,这可能是换行符。如果您不希望 scanf 将换行符写入变量,则可以改用格式字符串 " %c"。这将导致scanf 首先从输入流中提取并丢弃所有空白字符(空格、制表符、换行符等),然后再提取字符并将其写入变量。这样,scanf 将永远不会向您的变量写入换行符。

上述解决方案描述了如何使用scanf 解决您的问题。但是,对于基于行的输入,使用scanfgenerally not recommended。请参阅本指南了解一些替代方案:

A beginners' guide away from scanf()

使用scanf 不好的一个原因例如如下:

假设您想输入用户的两个字符。使用scanf,您的代码可能如下所示:

char first, second;

printf( "Please enter the first character: " );
scanf( " %c", &first );
printf( "Please enter the second character: " );
scanf( " %c", &second );

如果用户在按下 ENTER 之前通过输入多个字符来响应第一个提示,则scanf 将接受此输入为有效并返回用户输入的第一个字符。第二次调用scanf 将返回用户输入的第二个字符。它不会等待用户输入新的输入行。换句话说,scanf 会将用户对第一个提示的响应作为对第二个提示的回答。

这个例子表明scanf 不是为可靠地从用户那里获取基于行的输入而设计的。因此,我建议您改用函数fgets。这样,例如,如果用户在每个响应行中输入了多个字符,您就可以拒绝用户输入。

在您的情况下,我建议创建一个函数get_char_from_user,它使用fgets 而不是scanf,例如:

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

//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt )
{
    for (;;) //infinite loop
    {
        char buffer[1024], *p;

        //prompt user for input
        fputs( prompt, stdout );

        //attempt to read exactly one line of input
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            printf( "Error reading input from user!\n" );
            exit( EXIT_FAILURE );
        }

        //find the newline character, if it exists
        p = strchr( buffer, '\n' );

        //make sure that entire line was read into buffer
        if ( p == NULL && !feof(stdin) )
        {
            int c;

            printf( "The line was too long to fit buffer.\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    printf( "Unrecoverable error when reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //remove the newline character from string
        *p = '\0';

        //verify that exactly one character was entered
        if ( strlen( buffer ) != 1 )
        {
            printf( "Error: Please enter exactly one character!\n" );
            continue;
        }

        return buffer[0];
    }
}

使用这个函数,上面从用户那里读取两个字符的例子可以改成如下:

char first, second;

first  = get_char_from_user( "Please enter the first character: " );
second = get_char_from_user( "Please enter the second character: " );

现在,代码更简单,输入验证更好。

但是,就您的原始代码而言,如果能够以允许您编写提示的方式编写代码,那就太好了

Please enter the first character:
Please enter the second character:
Please enter the third character:
Please enter the fourth character:
Please enter the fifth character:

在一个循环中。这需要将get_char_from_userprompt 参数更改为printf 格式字符串。之后,您将能够编写如下代码:

int main()
{
    const char * const nth_strings[] =
        { "first", "second", "third", "fourth", "fifth" };

    char k[5];

    for ( int i = 0; i < 5; i++ )
    {
        k[i] = get_char_from_user(
            "Please enter the %s character: ",
            nth_strings[i]
        );
    }

    printf( "You entered the following characters:\n" );
    for ( int i = 0; i < 5; i++ )
    {
        putchar( k[i] );
    }
}

这是可能的,通过将函数 get_char_from_user 设为 variadic function,如下所示:

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

//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt, ... )
{
    for (;;) //infinite loop
    {
        char buffer[1024], *p;
        va_list vl;

        //prompt user for input
        va_start( vl, prompt );
        vprintf( prompt, vl );
        va_end( vl );

        //attempt to read exactly one line of input
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            printf( "Error reading input from user!\n" );
            exit( EXIT_FAILURE );
        }

        //find the newline character, if it exists
        p = strchr( buffer, '\n' );

        //make sure that entire line was read into buffer
        if ( p == NULL && !feof(stdin) )
        {
            int c;

            printf( "The line was too long to fit buffer.\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    printf( "Unrecoverable error when reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //remove the newline character from string
        *p = '\0';

        //verify that exactly one character was entered
        if ( strlen( buffer ) != 1 )
        {
            printf( "Error: Please enter exactly one character!\n" );
            continue;
        }

        return buffer[0];
    }
}

如果将最后两个代码块(函数main和函数get_char_from_user)合并到一个程序中,您将得到程序与用户之间的以下交互:

Please enter the first character: Hello
Error: Please enter exactly one character!
Please enter the first character: H
Please enter the second character: e
Please enter the third character: l
Please enter the fourth character: l
Please enter the fifth character: o
You entered the following characters:
Hello

如您所见,程序在同一行中同时输入多个字符时拒绝输入,并再次提示用户。

【讨论】:

    【解决方案2】:

    问题的原因可能是您使用带有 %s 的 scanf 来获取“字符串 - 以空字符结尾的字符”。 如果您只输入一个字符,我建议您尝试将 scanf 与“% c”一起使用。请注意,空格不是错误,它的存在是为了说忽略任何空格,如果你想接受空格,请删除 c 之前的空格。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 2021-09-03
      相关资源
      最近更新 更多