不确定为什么使用scanf时while循环的工作原理不同

时间:2019-06-13 13:29:17

标签: c

在学习C的过程中,我是一个新手,据我所知,我知道,如果有人给出诸如while (1 == 1)之类的条件,那么while循环将永远运行。

但是当我读一本书时,我注意到诸如

这样的代码
#include<stdio.h>

int main() {

    char a;
    int started = 0;
    puts("Scanning\n");
    while (scanf("%s[^\n]",&a) == 1)
    {
        if (a >= 65 && a <= 90)
        {
            printf("Char is capital\n");
        }
        else
        {
            printf("Not cap.\n");
        }

    }
    puts("Done\n");
    return 0;


}

命令行=> char.exe < file.txt

它从标准输入中获取输入,但是scanf返回参数的数目,即1,因此条件应在(1 == 1)时变为

但是为什么这不是永久循环,而是在读取文件后存在?

谢谢

5 个答案:

答案 0 :(得分:2)

char a;
...
while (scanf("%s[^\n]",&a) == 1)

您的格式无效,因为在您只想读取char时专用于字符串,因此您将至少在char中写出结尾的空char,从而产生未定义的行为

char a;
...
while (scanf(" %c",&a) == 1)

并注意格式中的空格,如果要管理所有字符,请将其删除

 if (a >= 65 && a <= 90)

使用ASCII码是错误的,它不可读并且与非ASCII不兼容

你可以做

if (a >= 'A' && a <= 'Z')

或更好地使用 isupper <ctype.h>),因为它不保证大写字母是连续的

您的 printf 可以替换为 puts ,删除字符串中的\ n或 fputs ,对于没有 printf 打印一个简单的字符串(没有%和arg)

  

但是为什么这不是永久循环,而是在读取文件后存在?

scanf 在EOF上不返回1,因此循环在EOF上停止,大约是 scanf 族:

  

这些函数返回成功匹配和分配的输入项的数量,该数量可以少于所提供的数量,或者在早期匹配失败的情况下甚至为零。

     

如果在第一次成功转换或匹配失败发生之前达到输入结束,则返回EOF值。如果发生读取错误,也会返回EOF,在这种情况下,将设置流的错误指示符(请参见ferror(3)),并设置errno来指示错误。

答案 1 :(得分:1)

  

但是为什么这不是永久循环,而是在读取文件后存在?

仅当scanf每次调用返回1时,它才会无限循环。循环在函数第一次返回不同结果时终止。 *

scanf的返回值传达 成功 已扫描和分配的输入字段的数量,并且在某些情况下还传达有关I / O错误的信息。特别是,scanf将在匹配任何字段之前到达宏EOF的值(如果它到达输入的末尾)。 EOF不等于1。


* 提供了该程序的行为的良好定义。由于注释和其他答案中所述的原因,您的程序不是。

答案 2 :(得分:0)

函数scanf返回以下值:

  • >0成功转换和分配的项目数。
  • 0-未分配任何项目。

  • <0-遇到读取错误,或者在读取错误之前达到文件结尾(EOF) 进行了分配。

答案 3 :(得分:0)

&a表示您正在尝试读取堆栈变量中的整行。

  

但是为什么这不是永久循环,而是在读取文件后存在?

尝试读取堆栈变量中的文件将导致堆栈崩溃,并且程序将崩溃。

在Internet上的C中寻找不同的存储类型和内存管理。 a是在程序堆栈上分配的字符变量,仅假定存储一个字符。如果使用它的地址并尝试放置更多数据,则它将破坏相邻的堆栈内存/变量,直到OS检测到该内存并杀死程序为止。您的格式表示它将读取整行,即直到换行为止。  scanf仍将返回1,但它将尝试将该行存储在a的地址中。

您是否像这样运行它?

cat <your file>| ./a.out

分配足够大的缓冲区,例如char a[4096];并将a传递为

while(scanf("%s[^\n]", a) == 1)

现在注意a现在是一个数组,不需要前面的&。文件结束后,循环仍将退出,但仍在EOF上。如果新行直到4Kb才出现,请尝试使用小于4 Kb的文件,这是最坏的情况。

读取更大文件/行的规定似乎超出了您的实验范围。

工作代码

#include<stdio.h>

int main() {

char a[4096];
int started = 0;
puts("Scanning\n");
while (scanf("%s[^\n]", a) == 1)
{
    if (a >= 65 && a <= 90)
    {
        printf("Char is capital\n");
    }
    else
    {
        printf("Not cap.\n");
    }

}
puts("Done\n");
return 0;
}

答案 4 :(得分:0)

输入字母时,条件(1==1)成立,并且while循环的主体被迭代。

while循环迭代之后,它进入下一个字母。 scanf等到您输入下一个字符。

再次满足条件(1==1)

此循环是不确定的循环,您可以继续输入字母,而永远不会到达puts语句。