首页 > 解决方案 > Scanf 防止 C 程序循环

问题描述

我正在尝试编写一个程序,将罗马数字作为输入,然后将它们转换为十进制值。用户必须首先声明他们要输入多少个罗马数字(一个或两个)。

我正在使用一个 for 循环,它重复罗马数字的次数。如果只有一个数字,它不应该循环,或者如果有两个,它应该循环两次,因为我们需要一次将一个字母作为输入。

我遇到的问题是 for 循环内的 scanf 语句不断阻止程序循环。一旦我删除了 scanf 并静态分配了值,它就可以正常工作了。然后,在尝试解决该问题时,我尝试通过将其分配给一个新变量来打印出 scanf 正在返回的值,例如char snf = scanf("%s", &numeral);,由于某种原因,它开始工作,正是我希望它工作的原因。我完全不知道它为什么现在工作以及为什么它阻止循环之前循环。谁能向我解释发生了什么事?

// A program to convert Roman Numerals to Decimals system.

#include <stdio.h>


int convert_numerals(char numeral){
    switch(numeral){
        case 'I':
        return 1;
        case 'V':
        return 5;
        case 'X':
        return 10;
        case 'L':
        return 50;
        case 'C':
        return 100;
        case 'D':
        return 500;
        case 'M':
        return 1000;
        default :
        printf("\nError! You did not enter a valid numeral\n");
        return 0;}}

int main(){
    int Decimal_Val = 0; //Initializing the variable with 0 to avoid issues at check.
    int Numeral_Count;

    printf("How many characters does your Roman numerals have? 1 or 2\n");
    scanf("%d",&Numeral_Count);


    for (int i = 1; i < 1+Numeral_Count; ++i)
    {   
        char numeral = 'O';
        int converted_val;

        printf("\n\nEnter numeral %d : ",i);

        scanf("%s", &numeral); // The problematic line.

        converted_val = convert_numerals(numeral);


        if (Decimal_Val != 0)
        {   
            if (Decimal_Val < converted_val)
            {
                Decimal_Val = converted_val - Decimal_Val;
            }else{
                Decimal_Val += converted_val;
            }

        }else{
            Decimal_Val = converted_val;
        }

    }


    printf("\nThe Roman numerals you entered are equal to %d in Decimals\n", Decimal_Val);

    return 0;
}

标签: cscanf

解决方案


Scanf 可能是一个有问题的函数,尤其是对于字符。相反,尝试使用fgets来读取一行,然后使用第一个字符。如果我们把它分解成一个单独的函数。(分解问题对于解决任何编程语言中的复杂问题都至关重要。

char get_roman_numeral(const char *prompt, const char * error_msg) {
    while (1) {
        printf("%s: ", prompt);

        char input[20] = {};

        fgets(input, 19, stdin);
        input[strcspn(input, "\n")] = '\0';

        if (strlen(input) > 0) {
            switch (input[0]) {
                case 'i': case 'I':
                case 'v': case 'V':
                case 'x': case 'X':
                case 'l': case 'L':
                case 'c': case 'C':
                case 'd': case 'D':
                case 'm': case 'M':
                return input[0];

                default:
                printf("%s\n", error_msg);
            }
        }
        else {
            printf("%s\n", error_msg);
        }
    }
}

把它分开,我们无限循环。每次我们打印我们提供的提示时,然后从stdinchar 缓冲区input中读取一行,该缓冲区可以容纳 20 个字符(其中一个必须是空终止字符)。

input[strcspn(input, "\n")] = '\0';

这将在输入字符串中找到第一个换行符并将其设置为'\0'. fgets这有效地删除了输入字符串中包含的换行符。

如果输入字符串长于 0 个字符,我们将评估第一个字符。如果它是一个罗马数字,我们返回它。功能完成!

如果它不是罗马数字,或者字符串长度为零字符,我们将打印错误消息,然后循环重新开始。

希望以这种方式获取您的输入,没有问题scanf将帮助您解决更大的问题。


推荐阅读