【问题标题】:C programming: Switch running twiceC编程:开关运行两次
【发布时间】:2014-09-14 09:30:54
【问题描述】:

我正在编写一个程序,它输入三个数字,然后计算一些不同的东西(每个东西都必须是它自己的函数)。程序开始告诉用户他们的选择并等待他们的输入。在任何情况下执行后,程序将再次打印菜单,但它将使用默认情况,然后它将打印菜单并要求输入。任何帮助将不胜感激。

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

void greeting() {
    printf("Welcome to Dr. Computer's Mathatorium \n"); // this is a seperate function just because
    printf("Remember to use capital letters when selecting \n");
}

//This getNum function is used to the get the number
int getNum () 
{
    int a;

    printf("Enter your first integer:"); //tells user to input number
    scanf("%i", &a); //input

    return a;
}

// gets the sum of the numbers
int getSum (int f, int g, int h) 
{
    return (f + g + h);
}

// gets the sum of the numbers
int getPro (int f, int g, int h) 
{
    return (f * g * h);
}

// gets the sum of the numbers
int getAvg (int f, int g, int h) 
{
    return (f * g * h)/3;
}

// gets the sum of the numbers
int getLow (int f, int g, int h) 
{
    return (f + g + h); //NEEDS ADJUSTING
}

main()
{
    int first, second, third, sum, pro, avg, low;

    char choice;
    greeting ();
    do {
        printf("Main Menu\n");
        printf("A) Get Three Integers\n");
        printf("B) Display the Sum\n");
        printf("C) Display the Product\n");
        printf("D) Display the Average\n");
        printf("E) Display the lowest\n");
        printf("F) Quit\n");
        scanf("%c", &choice);

        //here comes the switches to route the choices
        switch(choice){  
        case 'A':
            first = getNum ();
            second = getNum ();
            third = getNum ();
            printf("first is: %i\n", first);
            printf("second is: %i\n", second);
            printf("third is: %i\n", third);
            break;

        case 'B':
            sum = getSum (first, second, third);
            printf("sum is: %i\n", sum);
            break;

        case 'C':
            pro = getPro (first, second, third);
            printf("product is: %i\n", pro);
            break;

        case 'D':
            avg = getAvg (first, second, third);
            printf("average is: %i\n", avg);
            break;

        case 'E':
            avg = getAvg (first, second, third); //NOT DONE YET
            printf("average is: %i\n", avg); //REMEMBER TO FIX
            break;

        default: 
            printf("INVALID CHOICE!\n");
            break;    
        }
    } while (choice != 'F');

    return 0;
}

【问题讨论】:

  • 问题不太清楚。你能重新定义你的问题吗?
  • do{...}while() 实际上执行循环然后检查条件。可以找while(){..}
  • 当您输入“A”并按换行符时,终端会发送两个字符:“A”和“\n”(换行符)。换行符可能会导致 switch 的第二次执行。只需忽略换行符。
  • 你真的应该完全避免使用scanfc-faq.com/stdio/scanfprobs.html
  • 请不要编辑您的问题以添加“已修复”或“已解决”。 Stack Overflow 的方法是将答案标记为已接受(如果您自己找到答案,您甚至可以标记自己的答案)。请拨打Friendly Introductory Welcome To Stack Overflow Tour

标签: c switch-statement default


【解决方案1】:

有很多方法可以解决这个问题。这是一种适用于这种有限环境的解决方案 - 将第 58 行更改为:

scanf(" %c", &choice);

我在 % 说明符之前添加了一个空格。这意味着“跳过标准输入中的任何空白字符,然后读取下一个非空白字符并将其存储在 'choice' 变量的内存地址中”。

还值得指出的是,选择“F”会导致程序打印“INVALID CHOICE!”在关闭之前。这是因为 'F' 没有 switch-case,所以在退出 do-while 循环之前它会变成默认的无效 case。


为什么?

让我们进行桌面检查。假设您有一个输入流,例如:

{ 'A', '\n', '1', '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0'  }

您会注意到每个输入的格式都很好 - 只有一个字符后跟一个换行符,并且流在终止字符之前有一个换行符。如果您想处理未格式化的输入,我建议您不要使用scanf() 开头,因为scanf 代表扫描格式化字符串

原发帖者代码中输入流的第一次阅读是第58行的这条语句:

scanf("%c", &choice);

这意味着“从标准输入读取下一个字符并将其存储在'choice'变量的内存地址中”。

在该行之后,choice='A' 并且您的输入流如下所示:

{ '\n', '1', '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0' }

如果我们遵循代码,switch 语句会在 case 'A' 处停止,并且下一次读取是在第 63 行对 getNum() 的函数调用期间。这会跳转到第 15 行,我们会看到该语句:

scanf("%i", &a); //input

这意味着“从标准输入读取下一个整数并将其存储在'a'变量的内存地址”。当我说“读取下一个整数”时,我的意思是“跳过任何空白字符,然后读取 '+' 或 '-' 符号(如果存在),然后继续读取字符,直到找到与集合 {'0 ','1','2','3','4','5','6','7','8','9'},然后转换为整数"[1].

如果我们遵循这个半复杂的过程,我们会跳过“\n”,因为它是一个空白字符,读取“1”,然后停止并将“1”字符转换为数值1 并存储它在变量a中。

所以现在输入流看起来像这样:

{ '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0' }

main()函数中的局部变量是:

choice = 'A'
first = 1

接下来,我们看到getNum() 在第 64 行和第 65 行又被调用了两次。继续关注,您将获得如下输入流:

{ '\n', 'B', '\n', 'F', '\n', '\0' }

而main函数中的局部变量如下:

choice = 'A'
first = 1
second = 2
third = 3

下一次读取是在我们循环回到第 58 行之后:

scanf("%c", &choice);

如果你记得的话,这意味着“从标准输入读取下一个字符并将其存储在 'choice' 变量的内存地址中”。下一个字符是'\n',因此在这一行之后输入流如下所示:

{ 'B', '\n', 'F', '\n', '\0' }

main()函数的局部变量如下:

choice = '\n'
first = 1
second = 2
third = 3

现在我们遇到了问题!如果我们按照代码进行操作,switch 语句会在case default 处停止,并且程序会打印“INVALID CHOICE!”。我们不想读取第 58 行的换行符,而是希望跳过任何空格,然后读取第一个字符。一种解决方案见上文。

[1] ISO/IEC 9899-1990 §7.9.6.2(第 135-136 页)

【讨论】:

  • 不,[^\n] 仅在以 % 为前缀时才具有该含义(并且应该进入字符串)。
【解决方案2】:

试试这个代码,它是你的程序,有一些变化:

#include <stdio.h>


void greeting() {

printf("Welcome to Dr. Computer's Mathatorium \n"); // this is a seperate function just because
printf("Remember to use capital letters when selecting \n");
}


int getNum () //This getNum function is used to the get the number
{
int a;

printf("Enter your first integer:"); //tells user to input number
scanf("%i", &a); //input

return a;
}
int getSum (int f, int g, int h) // gets the sum of the numbers
{ return (f + g + h);


}
int getPro (int f, int g, int h) // gets the sum of the numbers
{ return (f * g * h);


}
int getAvg (int f, int g, int h) // gets the sum of the numbers
{ return (f * g * h)/3;


}
int getLow (int f, int g, int h) // gets the sum of the numbers
{ return (f + g + h); //NEEDS ADJUSTING


}

int main(void)
{
   int first, second, third, sum, pro, avg;

char choice;
greeting ();
do {
printf("Main Menu\n");
printf("A) Get Three Integers\n");
printf("B) Display the Sum\n");
printf("C) Display the Product\n");
printf("D) Display the Average\n");
printf("E) Display the lowest\n");
printf("F) Quit\n");
fseek(stdin,0,SEEK_END); // change
choice = getc(stdin); // change
//scanf("%c", &choice);

//here comes the switches to route the choices
switch(choice){  
    case 'A':    
    case 'a': // change
        first = getNum ();
        second = getNum ();
        third = getNum ();
        printf("first is: %i\n", first);
        printf("second is: %i\n", second);
        printf("third is: %i\n", third);
        break;

    case 'B':
    case 'b': // change
        sum = getSum (first, second, third);
        printf("sum is: %i\n", sum);
        break;

    case 'C':
    case 'c': // change
        pro = getPro (first, second, third);
        printf("product is: %i\n", pro);
        break;

    case 'D':
    case 'd': // change
        avg = getAvg (first, second, third);
        printf("average is: %i\n", avg);
        break;

    case 'E':
    case 'e': // change
        avg = getAvg (first, second, third); //NOT DONE YET
        printf("average is: %i\n", avg); //REMEMBER TO FIX
         break;

    default: 
        printf("INVALID CHOICE!\n");
        break;

}
} while (choice != 'F' && choice != 'f'); // change

   return 0;
}

【讨论】:

  • 虽然您的代码可能正是 OP 所需要的,但如果您单独列出和描述您的更改会更有帮助。事实上,需要逐行比较才能找到您的更改;然后人们不知道为什么你改变了它。
  • 请说明解决方法
猜你喜欢
  • 2013-10-01
  • 2013-11-22
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 2014-03-27
相关资源
最近更新 更多