使用多个提示和scanf运行C代码的更好方法

时间:2018-02-18 05:02:04

标签: c loops printf scanf

我正在使用C编写一个简单的程序,我需要计算平均值等。我的第一个函数是提示用户参数(我假设)存储在全局变量中以便我可以使用它们在其他功能中,例如"计算MIPS"等

我的问题是,当我调用该函数来收集用户的输入时,程序会在第一次提示后停止。共有7个提示。有谁知道我做错了什么?我可以做些什么建议,以便能够询问我的所有提示和存储值?我在考虑使用while循环,但是我不确定当值全部存储在全局变量中时如何终止循环。我确定我在解决一个简单的问题。

我的节目如下:

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

/* declare global var's */
int intr_class = 0;
int freq = 0;
int class1 = 0;
int cpi_1 = 0;
int class2 = 0;
int cpi_2 = 0;
int class3 = 0;
int cpi_3 = 0;

void params(){

    printf("Enter the number of instruction classes: ");
    scanf("%s", intr_class);

    printf("Enter the frequency of the machine (MHz): ");
    scanf("%s", freq);

    printf("Enter CPI of class 1: ");
    scanf("%s", cpi_1);

    printf("Enter instruction count of class 1 (millions): ");
    scanf("%s", class1);

    printf("Enter CPI of class 2: ");
    scanf("%s", cpi_2);

    printf("Enter instruction count of class 2 (millions): ");
    scanf("%s", class2);

    printf("Enter CPI of class 3: ");
    scanf("%s", cpi_3);

    printf("Enter instruction count of class 3 (millions): ");
    scanf("%s", class3);
}

int main() {
    /* declare local var's */
    char menuChoice[0];

    /* until user quits, loop */
    /* print out menu list */
    printf("Menu of Options:\n______________\n"
           "a) Enter Parameters\n"
           "b) Calculate average CPI of a sequence of instructions\n"
           "c) Calculate total execution time of a sequence of instructions\n"
           "d) Calculate MIPS of a sequence of instructions\n"
           "e) Quit\n\n"
           "Enter selection: ");
    scanf("%s", menuChoice);

    /* prompt for selection & choose appropriate procedure using either a case statement of if-else if-else statements or switch scanf for character input */
    while(menuChoice[0] != 'e'){
        switch(menuChoice[0]){
            case 'a':
                params();
                break;
            case 'b':
                //avgCPI();
                break;
            case 'c':
                //calcExTime();
                break;
            case 'd':
                //calcMIPS();
                break;
            case 'e':
                exit(0);
            default:
                printf("Menu of Options:\n______________\na) Enter Parameters\nb) Calculate average CPI of a sequence of instructions\nc) Calculate total execution time of a sequence of instructions\nd) Calculate MIPS of a sequence of instructions\ne) Quit\n\nEnter selection: ");
        }
    }
    return(0);
}

4 个答案:

答案 0 :(得分:2)

您遇到UB,因为这不是使用scanf的方式。

scanf ("%d", &variable_name)用于整数,但就这样做,你使用错误的格式("%s")+传递变量值(... variable_name)而不是变量adrress( &variable_name 请注意&amp;

答案 1 :(得分:2)

虽然您发现错误地使用格式说明符并且需要指向scanf中变量的指针是您的主要问题,但使用{{1>还有另一个方面还没有解决。

如果没有验证返回,您不能简单地编写scanf来接收用户输入,以确保成功转换为发生的整数。您必须这样做才能确信scanf ("%d", &intr_class);完全拥有有效值。 (在您尝试使用intr_class之前,如果您有任何此类要求,您还需要确保该值在可接受的范围内)

这适用于所有用户输入,无论您使用哪种功能,但它尤其适用于intr_class。如果响应您的提示,用户输错了怎么办?例如

scanf

然后呢?除非您检查返回,否则永远不会知道Enter the number of instruction classes: rabbits 未设置,如果未初始化,任何访问该值的尝试都是未定义行为

此外,intr_class在遇到错误时会停止阅读,而scanf中仍然无法读取任何字符。那么当你尝试阅读其他内容时会发生什么?让我们考虑一个例子:

stdin

此条目是成功还是失败? (答案:失败)为什么? Enter the frequency of the machine (MHz): 800 仍然包含stdin(每次用户按 Enter 时都会添加"rabbits\n800\n",并且每次输入都不会失败的唯一原因是{'\n' 1}}格式说明符使用前导空格),但'%d'不是空格...)

因此,使用"rabbits"进行用户输入时,必须非常小心,不仅要考虑转换是成功还是失败,还要考虑输入缓冲区中剩余的任何字符(scanf如果你的话下一类输入不会消耗前导空格,也不会消耗转换失败后输入缓冲区中剩余的任何字符。

您管理此方法的一种方法是在每次调用'\n'后手动删除stdin中保留的所有字符。 (注意:应该检查返回值是否也不是scanf)。在您致电EOF并检查返回不是scanf之后,您只需调用一个简单的函数来读取并丢弃所有剩余的字符,例如:

EOF

避免使用全局变量以及使用/* function to empty remaining characters in stdin before next input * to help avoid the pitfalls associated with using scanf for user input. */ void emptystdin() { int c = getchar(); for (; c != '\n' && c != EOF; c = getchar()) {} } 保存所有参数的非常好的建议也应该得到解决。如果你定义一个struct(称之为struct),在struct parameters_t中创建并声明它的一个实例(比如一个叫main()),那么你需要做的就是传递地址将parameters添加到parameters函数中,并填写params()中的值。您只需更改函数声明,以包含指向结构类型的指针params,然后在void params (stuct parameters_t *p)函数中提示并填充p->intr_class等。

为了简单起见(并且不必一直为类型键入params,您只需创建一个struct parameters_t(别名),将typedef定义为{的别名{1}}减少打字。

您还应该将返回类型从parameters_t更改为可以在struct parameters_t

中有意义地指示输入成功/失败的内容

在一个简短的例子中将这些部分放在一起,你可以做类似以下的事情:

void

示例使用/输出

params

看看结束了。当你刚刚学习时,有很多东西需要消化。如果您有任何问题,请发表评论,我很乐意进一步提供帮助。

答案 2 :(得分:1)

https://www.tutorialspoint.com/c_standard_library/c_function_scanf.htm

这应该可以帮助您了解scanf的工作原理。正如另外两个人所说,你应该使用%d而不是%s,并且在变量之前需要一个&符号。如果你已经学过指针,你就会知道为什么你需要&符号,如果不是现在不担心它,你以后会学到它。

我给你的链接也为你提供了其他数据类型的%命令。大多数数据类型都有不同的字母,例如%s用于字符串(字符数组),而您将%lf用于双字母。

希望这有帮助!

答案 3 :(得分:0)

对整数使用scanf("%d",&VariableName),对字符数组(字符串)使用scanf(" %s",&arrCHar)

此外,您必须在调用函数之前声明函数原型。