scanf不会第二次执行

2023-11-27

我正在尝试:- 如果用户输入无效值,则重新读取该值。但问题是scanf()只执行一次,不会执行任何其他时间,程序会陷入无限循环。

#include<stdio.h>
#include<math.h>
main()
{
    unsigned int a;
    unsigned int b = pow(2,M-1);
    unsigned int c;
    int x;

    printf("b = %i",b);

    input:
    fflush(stdin);
    fflush(stdout);
    printf("\nEnter any integer: ");
    x = scanf("%u",&a);

    printf("%u",a);
    if(x==0) 
        goto input;

    printf("\na = %i",a);

    c = a & b;

    printf("\nc = %i",c);

    if(c)
        printf("\nthe bit %i is set",M);
    else
        printf("\nthe bit %i is not set",M);
}

我之前尝试过使用添加空间%u并且也尝试过fflush(stdin)但没有任何作用。

编辑:我知道不建议使用 goto 但我必须这样做。 (不能选择使用循环)。 M 是我在编译时使用 gcc 命令行定义的宏。


警告:fflush(stdin);可能是未定义的行为。读:Why fflush(stdin)是错的?

int fflush(FILE *ostream);
The ostream指向输出流或更新流,其中 最近一次操作未输入,则fflush函数导致任何 该流的未写入数据将被传送到主机环境 写入文件;否则,behavior is Undefined.

您可以尝试循环并阅读直到EOF or \n given 此常见问题解答条目代替fflush(stdin)正如我在下面的回答中所建议的。

编辑:感谢@乔纳森·莱夫勒:

有一些平台fflush(stdin)已完全定义(作为该平台上的非标准扩展)。主要的例子是一个众所周知的系统系列,统称为 Windows。微软的规范int fflush( FILE *stream ); If the stream开放输入,fflush清除缓冲区的内容.

我对你的代码还有更多疑问;什么是M在表达中unsigned int b = pow(2,M-1);?如果你不定义它应该是一个错误。你发布完整的代码吗?

关于错误检测的逻辑:

如果用户输入无效,则重新读取该值

No, scanf()不返回错误代码。它返回成功转换的数量。

int scanf ( const char * format, ... );
返回值
成功时,该函数返回成功填充的参数列表的项目数。这个计数可以匹配 预期的项目数量或由于匹配而更少(甚至为零) 失败、读取错误或到达文件结尾。

如果发生读取错误或到达文件末尾 读数,设置正确的指示器(feof or ferror)。并且,如果有一个 在成功读取任何数据之前发生,EOF被返回。

如果解释宽字符时发生编码错误, 功能集errno to EILSEQ.

因此,实际上根据遇到的错误,返回值可能为零,即 EOF。你应该使用int ferror ( FILE * stream ); and errno用于错误检测的宏(检查链接中给出的示例)。

可能出现错误的原因是输入无效可:

EILSEQ:输入字节序列不形成有效字符。
EINVAL:没有足够的论据;或格式为 NULL。
ERANGE:整数转换将超出相应整数类型可以存储的大小。

Check 扫描手册以获得完整列表。

无限循环的原因:

系统会跟踪到目前为止已看到的输入。每次致电scanf从最后一个停止匹配输入的位置开始。这意味着如果之前发生错误scanf,它无法匹配的输入仍然未读,就好像用户提前输入了一样。如果不小心丢弃错误输入,并且使用循环来读取输入,则您的程序可能会陷入无限循环。

例如在您的代码中:

x = scanf("%u", &a);
      //   ^
      //  need a number to be input

但是假设您没有输入数字,但输入了无效字符串,例如"name"(而不是像你所说的数字)。这将导致scanf()尝试匹配无符号整数时函数失败("%u"),以及这个词"name"未读。所以下一次循环时,scanf()不等待新的用户输入,它会尝试再次转换“名称”。

类似地,如果输入是29.67, the "%u" 将仅匹配前两个字符(29),留下.67作为下次调用的未读输入scanf().

即使输入正确,如29,结束输入的换行符仍然未读。通常这不是问题,因为大多数转换会自动跳过前导空白,例如上一行的尾随换行符。然而一些转换("%c" and "%[")不要跳过任何前导空格,因此您必须手动执行此操作。

为了避免这种无限循环,一个建议是:

(记住:正如我建议使用ferror(),错误值更适合检测无效输入。此外,它仅用于学习目的,如果您需要实现一个严肃的应用程序,您应该使用fgets(str)代替scanf()接下来是解析str输入验证输入是否有效)

input:
    //fflush(stdout); //use if needed, as \n used in printf no need of fflush-stdout
    printf("\nEnter any integer: ");
    x = scanf("%u", &a); // always wait for new symbols
    printf("%u", a);

    if(x == 0){ // x=0, if error occurred
        // read all unread chars 
        while ((ch = getchar()) != '\n' && ch != EOF);
        goto input;
    }

这只是一个可能适用于您的代码的建议(对我有用,您的代码+ gcc)。但如果您错误地使用此技术,可能会在代码中留下错误:

Read 如何刷新输入缓冲区?

如果您确定输入流中存在不需要的数据,则可以使用 下面的一些代码片段可以删除它们。但是,如果您 当输入流中没有数据时调用这些,程序将 等到出现为止,这会给您带来不良结果。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

scanf不会第二次执行 的相关文章

  • 必须打开存储才能执行此操作 - System.IO.Packaging.Package

    我正在使用 System IO Packaing Package 类来压缩文件 我的应用程序的多个实例可以同时运行 并读取和保存文件 当处理小文件时 一切似乎都很好 但是当涉及大文件时 如果应用程序的两个实例同时保存 我会收到一个异常 消息
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • 如何将pdf页面设置设置为打印属性对话框?

    大家好 我想知道如何设置 pdf 页面设置到打印属性对话框 例如 如果我的 PDF 页面设置为横向 则布局会自动显示横向而不是纵向 如果我的 PDF 页面设置为纵向 则布局会自动显示纵向 我在这个主题上做了很多研发 但没有找到任何满意的链接
  • 在运行时设置 DataGridView 上的 DataFormatString?

    是否可以在运行时设置 ASP NET DataGridView 中的列或单元格的 DataFormatString 属性 这应该有效 BoundField priceField grid Columns 0 as BoundField pr
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • C 中的模仿函数重写

    具体来说 函数重写能够调用基本重写方法 这有两部分 一个是预编译的库代码 1 另一个是库的用户代码 2 我在这里实现了一个尽可能最小的经典 Person 和 Employee 示例 非常感谢了解 OOP 概念的铁杆 C 开发人员的回应 我正
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 导出到 CSV 时 Gridview 出现空行

    这个问题是由进一步讨论引发的这个问题 https stackoverflow com questions 6674555 export gridview data into csv file 6674589 noredirect 1 com
  • 线程安全的 C++ 堆栈

    我是 C 新手 正在编写一个多线程应用程序 不同的编写者将对象推入堆栈 读者将它们从堆栈中拉出 或至少将指针推入对象 C 中是否有任何内置结构可以在不添加锁定代码等的情况下处理此问题 如果没有 那么 Boost 库呢 EDIT 你好 感谢您
  • QThread - 使用槽 quit() 退出线程

    我想在线程完成运行时通知对象 但是 我无法让线程正确退出 我有以下代码 处理器 cpp thread new QThread tw new ThreadWorker connect tw SIGNAL updateStatus QStrin
  • 如何不在类中实现接口的功能?

    面试时面试官问了我以下问题 但我不知道这个问题的答案是什么 请帮忙 如果我不想 我必须做什么 在我的类中实现一个函数 在接口中声明为 由我班实施 Edited 我正在使用 NET 和 C 如果有人可以提供 C 示例代码示例 那就太好了 Th
  • 在 .NET 中记录 StackOverflowException

    最近 我的 NET 应用程序 asp net 网站 中出现了堆栈溢出异常 我之所以知道该异常是因为它出现在我的 EventLog 中 我知道 StackOverflow 异常无法被捕获或处理 但是有没有办法在它杀死您的应用程序之前记录它 我
  • 理解 C++11 中的 std::atomic::compare_exchange_weak()

    bool compare exchange weak T expected T val compare exchange weak 是 C 11 中提供的比较交换原语之一 它是weak即使对象的值等于 它也会返回 falseexpected
  • 有没有更好的方法来获取每个项目与谓词匹配的子序列?

    假设我有一个 IEnumerable 例如 2 1 42 0 9 6 5 3 8 我需要获得与谓词匹配的项目的 运行 例如 如果我的谓词是 bool isSmallerThanSix int number 我想得到以下输出 2 1 0 5
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 展开路径中具有环境变量的文件名

    最好的扩张方式是什么 MyPath filename txt to home user filename txt or MyPath filename txt to c Documents and settings user filenam
  • 在何处将 CFLAG(例如 -std=gnu99)添加到 (Eclipse CDT) 自动工具项目中

    我有一个简单的 Autotools C 项目 不是 C 其框架是由 Eclipse CDT Juno 为我创建的 CFLAG 通过检查 似乎是 g O2 我希望所有生成的 make 文件也具有 std gnu99附加到 CFLAG 因为我使
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标
  • 如何确定给定方法可以抛出哪些异常?

    我的问题和这个真的一样 找出 C 中方法可能抛出的异常 https stackoverflow com questions 264747 finding out what exceptions a method might throw in

随机推荐