我正在做一项大学作业(job),当我的循环呼叫gets()时,它会打印我想打印两次的行.这只会在第二个循环中发生.如果您在第一个循环中输入三角形并输入一些数字,则在循环结束并重新启动后,它将打印提示序列两次,而不是一次.

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

void main() {
    const float pi = 3.1415926535;  // Constant for pi
    char choice[100] = "";          // String for inputted, also used for exiting loop
    float height, width, base, area, radius, radians, verticalHeight;
    int i = 1;

    while (i < 2) {
        puts("Area Calculator - Please choose one of the choices listed below\n----------------------------------------------------\nTriangle, Rectangle, Circle, Trapezium\n----------------------------------------------------");
        printf("Enter choice: ");
        gets(choice);
        
        if (strcmp(choice, "Done") == 0 || (strcmp(choice, "done") == 0)) {
            i++;
        }
        else if (strcmp(choice, "Triangle") == 0 || (strcmp(choice, "triangle") == 0)) {
            printf("\nEnter vertical height: ");
            scanf_s("%f", &verticalHeight);
            printf("Enter base: ");
            scanf_s("%f", &base);
            printf("Area = %.2f\n\n", (0.5) * verticalHeight * base);
            strcpy_s(choice, 100, "");
        }
        else if (strcmp(choice, "Rectangle") == 0 || (strcmp(choice, "rectangle") == 0)) {
            puts("\nrectangle");
        }
        else if (strcmp(choice, "Circle") == 0 || (strcmp(choice, "circle") == 0)) {
            puts("\ncircle");
        }
        else if (strcmp(choice, "Trapezium") == 0 || (strcmp(choice, "trapezium") == 0)) {
            puts("\ntrapezium");
        } 
    }
}

我试着用scanf_s()代替gets(),我可以让它像那样工作,但我的分配规定我必须使用gets().

任何帮助都将不胜感激.谢谢:)

推荐答案

使用gets()绝对是一个糟糕的要求,因为该函数本质上是不安全的,并且已从最新版本的C标准中删除.

然而,这就是正在发生的事情:

  • 在第一次迭代中,gets()预期输入以换行符结尾,您键入triangle并按Enter,因此choice收到字符串"triangle".
  • 然后,程序要求用户输入2个带scanf_s的浮点数:对于每个请求,用户键入数字并按Enter键,scanf_s使用任何前导空格(包括换行符)并解析输入流中离开换行符的数字.
  • 对于下一次迭代,gets()读取这个挂起的换行符,并立即返回choice中的空字符串,这不会导致任何输出,并且下一次迭代将再次提示输入.这就解释了为什么会出现重复的提示.

要解决此问题,请避免将getsfgetsscanf_sscanf()混为一谈:使用fgets()读取用户输入,判断文件结尾,并一次一行地将其与sscanf()解析,以判断是否成功转换.

以下是修改后的版本:

#ifdef _MSC_VER
// prevent warnings about the use of standard function sscanf
#define _CRT_SECURE_NO_WARNINGS
#endif

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

int main() {
    const float pi = 3.1415926535;  // Constant for pi
    char line[100];
    char choice[20];
    float height, width, base, area, radius, radians, verticalHeight;

    for (;;) {
        puts("Area Calculator - Please choose one of the choices listed below\n"
             "----------------------------------------------------\n"
             "Triangle, Rectangle, Circle, Trapezium\n"
             "----------------------------------------------------");
        printf("Enter choice: ");
        if (!fgets(line, sizeof line, stdin))
            break;
        if (sscanf(line, "%19s", choice) != 1)
            continue;

        // set the command to lowercase
        for (int i = 0; choice[i]; i++) {
            choice[i] = tolower((unsigned char)choice[i]);
        }

        if (!strcmp(choice, "done")) {
            break;
        } else
        if (!strcmp(choice, "triangle")) {
            printf("Enter vertical height: ");
            if (!fgets(line, sizeof line, stdin))
                break;
            if (sscanf(line, "%f", &verticalHeight) != 1) {
                printf("input error\n");
                continue;
            }
            printf("Enter base: ");
            if (!fgets(line, sizeof line, stdin))
                break;
            if (sscanf(line, "%f", &base) != 1) {
                printf("input error\n");
                continue;
            }
            printf("Area = %.2f\n\n", 0.5 * verticalHeight * base);
        } else
        if (!strcmp(choice, "rectangle")) {
            puts("rectangle");
        } else
        if (!strcmp(choice, "circle")) {
            puts("circle");
        } else
        if (!strcmp(choice, "trapezium") || !strcmp(choice, "trapezoid")) {
            puts("trapezium");
        } else {
            printf("unsupported shape: %s\n", choice);
        }
    }
    return 0;
}

C++相关问答推荐

我应该如何解决我自己为iOS编译的xmlsec1库的问题?转换Ctx.first在xmlSecTransformCtxPrepare()之后为空

__VA_OPT__(,)是否可以检测后面没有任何内容的尾随逗号?

在没有动态内存分配的情况下,用C语言最快地将各种数组复制到单个较大的数组中

拥有3x3二维数组并访问数组[1][3]等同于数组[2][0]?

调用mProtection将堆栈上的内存设置为只读,直接导致程序SIGSEGV

加密解密工作正常,但返回错误0x80090005

1处的解析器错误:yacc语法的语法错误

&;(str[i])和(&;str)[i]有什么区别?

是否需要包括<;errno.h>;才能使用perror?

处理来自浏览器的HTTP请求

如何在C++中安全地进行浮点运算

为什么我无法访问C语言中的文件

即使我在C++中空闲,也肯定会丢失内存

为什么<到达*时不会转换为>?

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

使用 GCC 将一个函数中初始化的 struct 体实例通过指针传递到 C 中的另一个函数会产生不同的结果

从管道读取数据时丢失

与 C 相比,C++ 中无副作用的无限循环的好处是 UB?

将十六进制值或十进制值分配给 uint16_t 有什么区别?

计算 e^x 很好.但不是 x 的罪