繁体   English   中英

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

[英]if my scanf variable is a float and a user inputs a character how can i prompt them to input a number? assuming the scanf is inside a do while loop

我曾尝试使用 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;
}

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

我一般不会使用scanf -family 函数从stdin读取。

fgets更好,因为它将输入作为您指定长度的字符串,避免缓冲区溢出,您可以稍后将其解析为所需的类型(如果有)。 对于float值, strtof有效。

但是,如果您的可交付成果或家庭作业的规范要求使用scanf%f作为格式说明符,您可以做的是检查其返回值,该值将包含格式字符串中格式说明符的数量的计数已成功扫描:

第 7.21.6.2 节

如果在第一次转换(如果有)完成之前发生输入失败,[scanf] 函数将返回宏 EOF 的值。 否则,该函数返回分配的输入项的数量,如果早期匹配失败,该数量可能少于提供的数量,甚至为零。

从那里,您可以诊断输入是否有效。 此外,当scanf失败时, stdin不会被清除,随后对scanf调用(即在循环中)将继续查看其中的内容。 这个问题有一些关于处理这个问题的信息。

就像 Govind Parmar已经建议的那样,使用fgets()读取整行输入更好/更容易,而不是使用scanf()等。 用于人机交互输入。

根本原因是交互式标准输入在默认情况下是行缓冲的(并且更改它很重要)。 因此,当用户开始输入他们的输入时,它不会立即提供给您的程序; 仅当用户按下Enter 时

如果我们确实使用fgets()读取输入的每一行,那么我们可以使用sscanf()对其进行扫描和转换,其工作方式与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;
}

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

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

(但是,同样,因为printf("...\\n");在它以换行符结束之前, \\n ,并且我们没有更改标准输出缓冲,因此不需要fflush(stdout); 。 )

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

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

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

  • char buffer[MAX_LINE_LEN + 1];+1 char buffer[MAX_LINE_LEN + 1]; 是因为 C 中的字符串以空字符'\\0'结尾。 所以,如果我们有一个 19 个字符的缓冲区,它最多可以保存一个 18 个字符的字符串。

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

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

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

    在这种情况下,我们可以使用MAX_LINE_LEN + 1来代替( fgets()的第二个参数是给定缓冲区中的字符数,包括对字符串结尾字符的保留)。

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

    也因为sizeof不是函数而是运算符很重要:它不评估其参数,它只考虑参数的大小(类型)。 这意味着如果你做一些像sizeof (i++)这样愚蠢的事情,你会发现i没有增加,并且它产生与sizeof i完全相同的值。 同样,这是因为sizeof是一个运算符,而不是一个函数,它只返回其参数的大小。

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

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

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

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

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

    如果我们包含<string.h> ,我们可以使用例如if (strchr(line, 'q') || strchr(line, 'Q'))来查看所提供的行中是否有qQ strchr(string, char)返回指向字符串中第一次出现的 char 的指针,如果没有则返回 NULL; 并且除 NULL 之外的所有指针在逻辑上都被认为是正确的。 (也就是说,我们可以等效地写if (strchr(line, 'q') != NULL || strchr(line, 'Q') != NULL) 。)

    我们可以在<string.h>声明的另一个函数是strstr() 它的工作原理类似于strchr() ,但第二个参数是一个字符串。 例如, (strstr(line, "exit"))仅当line在某处有exit时才为真。 (不过,它可能是brexitexitology ;这只是一个简单的子字符串搜索。)

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

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

  • EXIT_SUCCESSEXIT_FAILURE<stdlib.h>定义的标准退出状态代码。 大多数人更喜欢将0用于 EXIT_SUCCESS(因为在大多数操作系统中都是这样),但我认为像这样拼写成功/失败可以更容易阅读代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM