如果我的 scanf 变量是浮点数并且用户输入一个字符,我如何提示他们输入数字?假设 scanf 位于 do while 循环内

2024-02-28

我尝试使用 k = getchar() 但它也不起作用;

这是我的代码

#include<stdio.h>
int main()
{
    float height;
    float k=0;
    do 
    {
        printf("please type a value..\n");
        scanf("%f",&height);
        k=height;
    }while(k<0);// i assume letters and non positive numbers are below zero.
    //so i want the loop to continue until one types a +ve float.
    printf("%f",k);



    return 0;
}

我想要一个如果用户输入字母或负数或字符,应该提示他/她再次输入该值,直到他输入正数


像戈文德·帕尔玛已经建议了 https://stackoverflow.com/a/54370533/1475978,更好/更容易使用fgets()读取整行输入,而不是使用scanf()等人。用于人机交互输入。

The underlying reason is that the interactive standard input is line-buffered by default (and changing that is nontrivial). So, when the user starts typing their input, it is not immediately provided to your program; only when the user presses Enter.

如果我们确实使用读取每一行输入fgets(),然后我们可以使用扫描并转换它sscanf() http://man7.org/linux/man-pages/man3/sscanf.3.html,其工作原理很像scanf()/fscanf()做,除了sscanf()适用于字符串输入,而不是输入流。

这是一个实际的例子:

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

#define  MAX_LINE_LEN  100

int main(void)
{
    char   buffer[MAX_LINE_LEN + 1];
    char  *line, dummy;
    double value;

    while (1) {

        printf("Please type a number, or Q to exit:\n");
        fflush(stdout);

        line = fgets(buffer, sizeof buffer, stdin);
        if (!line) {
             printf("No more input; exiting.\n");
             break;
        }

        if (sscanf(line, " %lf %c", &value, &dummy) == 1) {
             printf("You typed %.6f\n", value);
             continue;
        }

        if (line[0] == 'q' || line[0] == 'Q') {
             printf("Thank you; now quitting.\n");
             break;
        }

        printf("Sorry, I couldn't parse that.\n");
    }

    return EXIT_SUCCESS;
}

The fflush(stdout);没有必要,但也没有坏处。它基本上保证了我们拥有的一切printf()或写信给stdout,将刷新到文件或设备;在这种情况下,它将显示在终端中。 (这里没有必要,因为标准输出默认也是行缓冲的,所以\n在 printf 模式中,打印换行符也会导致刷新。

我确实喜欢洒那些fflush()调用,无论何时我需要记住这一点,重要的是所有输出实际上都刷新到输出,而不是由 C 库缓存。在这种情况下,我们绝对希望在开始等待用户输入之前提示对用户可见!

(但是,再说一次,因为printf("...\n");在以换行符结束之前,\n,并且我们没有改变标准输出缓冲,fflush(stdout);那里不需要。)

The line = fgets(buffer, sizeof buffer, stdin);该行包含几个重要的细节:

  • 我们定义了宏MAX_LINE_LEN早些时候,因为fgets()只能读取给定缓冲区内的一行,并将在后续调用中返回该行的其余部分。

    (您可以检查读取的行是否以换行符结束:如果不是,则它是输入文件中的最后一行,最后一行的末尾没有换行符,或者该行比您拥有缓冲区,因此您只收到了初始部分,该行的其余部分仍在缓冲区中等待您。)

  • The +1 in char buffer[MAX_LINE_LEN + 1];是因为 C 中的字符串以 nul 字符终止,'\0',最后。因此,如果我们有一个 19 个字符的缓冲区,它最多可以容纳 18 个字符的字符串。

  • 请注意,NUL 或 nul 带 1 个 ell,是代码为 0 的 ASCII 字符的名称,'\0',并且是字符串结束标记字符。

    然而,NULL(或有时为 nil)是指向零地址的指针,在 C99 及更高版本中与(void *)0。当我们想要设置一个指向可识别的错误/未使用/无值的指针,而不是指向实际数据时,它是我们使用的哨兵和错误值。

  • sizeof buffer是变量使用的字符总数(包括字符串结尾 nul 字符)buffer.

    在这种情况下,我们可以使用MAX_LINE_LEN + 1相反(第二个参数fgets()是缓冲区中赋予它的字符数,包括字符串结尾字符的保留)。

    我使用的原因sizeof buffer在这里,是因为它太有用了。 (请记住,如果buffer是一个指针而不是一个数组,它将计算出指针的大小;不是该指针指向的可用数据量。如果您使用指针,则需要自己跟踪可用内存量,通常在单独的变量中。这就是 C 的工作原理。)

    也因为重要的是sizeof is not一个函数,但一个运算符:它不评估其参数,它只考虑参数的(类型)大小。这意味着如果你做了一些愚蠢的事情,比如sizeof (i++),你会发现i is not递增,并且它产生的值与sizeof i。再说一遍,这是因为sizeof是一个运算符,而不是一个函数,它只返回其参数的大小。

  • fgets()返回一个指向它存储在缓冲区中的行的指针,或者NULL如果发生错误。

    这也是我将指针命名为line,以及存储阵列buffer。他们描述了我作为程序员的意图。 (顺便说一句,在编写注释时这一点非常重要:不要描述代码的作用,因为我们可以阅读代码;但一定要描述代码应该做什么的意图,因为只有程序员知道这一点,但它如果试图理解、修改或修复代码,了解其意图很重要。)

  • scanf() 系列函数返回成功转换的数量。要检测正确数值后跟垃圾的输入,例如1.0 x, 我问sscanf()忽略数字后面的任何空格(空格表示制表符、空格和换行符;'\t', '\n', '\v', '\f', '\r', and ' '对于使用 ASCII 字符集的默认 C 语言环境),并尝试转换单个附加字符,dummy.

    现在,如果该行在数字后面包含除空格之外的任何内容,sscanf()将存储该内容的第一个字符dummy,并返回 2。但是,因为我只想要只包含数字且不包含虚拟字符的行,所以我期望返回值为 1。

  • 检测q or Q(但仅作为该行的第一个字符),我们只需检查第一个字符line, line[0].

    如果我们包括<string.h>,我们可以使用例如if (strchr(line, 'q') || strchr(line, 'Q'))看看是否有q or Q提供的行中的任何位置。这strchr(string, char) http://man7.org/linux/man-pages/man3/strchr.3.html返回指向字符串中第一次出现 char 的指针,如果没有则返回 NULL;除 NULL 之外的所有指针在逻辑上都被认为是正确的。 (也就是说,我们可以等效地写if (strchr(line, 'q') != NULL || strchr(line, 'Q') != NULL).)

    我们可以使用的另一个函数声明在<string.h> is strstr()。它的工作原理就像strchr(),但第二个参数是一个字符串。例如,(strstr(line, "exit"))只有当line has exit在它的某个地方。 (它可能是brexit or exitology, 尽管;这只是一个简单的子字符串搜索。)

  • 在一个循环中,continue跳过循环体的其余部分,并从头开始循环体的下一次迭代。

  • 在一个循环中,break跳过循环体的其余部分,并在循环后继续执行。

  • EXIT_SUCCESS and EXIT_FAILURE是标准退出状态代码<stdlib.h>定义。最喜欢使用0对于 EXIT_SUCCESS (因为这是大多数操作系统中的情况),但我认为像这样拼写成功/失败可以更轻松地阅读代码。

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

如果我的 scanf 变量是浮点数并且用户输入一个字符,我如何提示他们输入数字?假设 scanf 位于 do while 循环内 的相关文章

  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐