【问题标题】:How to verify input format without using arrays, ex input "OIL2932"如何在不使用数组的情况下验证输入格式,例如输入“OIL2932”
【发布时间】:2021-05-24 16:53:07
【问题描述】:

您好,我很难以特定方式阅读 C 中的用户输入...

我想读取用户输入,在这种情况下,我的程序将验证前三个字符为字符,最后四个数字为数字。 而且我不知道如何确保他们的输入是 总共 7 个字符(3 个字符,4 个整数)例如:ULI0788。

我不想使用数组,例如 arr[12];

目前我正在学习内存分配和指针,因此鼓励我尽可能使用它而不是数组

例如

char itemID;
printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
scanf("%s", itemID);

我已经进行了一些谷歌搜索并尝试了用户建议,但没有人能同时满足我的要求,验证每个字符/数字并设置最多 7 个字符/数字。或者我只是不明白如何正确使用这些建议

googled
googled2
googled3
googled4
googled5
googled6
googled7
googled8
googled9
googled10

【问题讨论】:

  • 不确定“不想使用数组”是什么意思。这是你的导师强加的人为限制吗?在您发布的代码片段中,itemID 可能是一个数组
  • In C, the definition of a string is "以空字符 '\0' 结尾的一维字符数组。"。说你想使用非数组字符串就像要一杯水,但不要弄湿。
  • 如果不允许使用数组,可以使用指针并调用malloc。不确定这是否会违反您人为限制的文字或精神。
  • @ryyker 说你想使用非数组字符串就像要一杯水,但不要弄湿。那只是脱水水。就加水。 ;-)
  • @AndrewHenle - 哈哈,我一直在等待有人对此发表评论,但我想这会是这样的,冰呢?

标签: c


【解决方案1】:

“我想读取用户输入,在这种情况下,我的程序将验证前三个字符为字符,最后四个数字为数字。我不知道如何确保他们的输入是总共 7 个字符(3 个字符,4 个整数)...我不想使用数组”

由于无法使用C strings,以上内容仅限于简单地输入一系列字符,然后将它们视为离散项进行测试:

bool test7char(void)
{
    int Char;

    for(int i=0;i<7;i++)
    {
        Char = getc(stdin);
        if(i<3)
        {
             if(!isalpha(Char)) return false;
        }
        else if(!isdigit(Char)) return false;
    }
    return true;
}

用法:

int main(void)
{
    printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
    while(!test7char())
    {
        printf("Mistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
    }
    
    return 0;
}

编辑 - “我只是想弄清楚如何使用内存分配和指针来回答我的问题”

使用指针:(在内存中,此指针将指向一系列以\0 结尾的字母数字字符,即一个字符串。)

#define STR_SIZE 7 + 1
BOOL test7char(const char *str);

int main(void)
{
    char *str = calloc(STR_SIZE, 1);
    if(str)
    {
        printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
        if(fgets(str, STR_SIZE, stdin))
        {
            while(!test7char(str))
            {
                printf("\nMistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
                if(!fgets(str, STR_SIZE, stdin))
                {
                    //message user of error
                    break;
                }
            }
        }
        free(str);
    }
    
    return 0;
}

bool test7char(const char *str)
{
    if(!str) return false;
    if(strlen(str) != STR_SIZE -1) return false; 

    for(int i=0;i<7;i++)
    {
        if(i<3)
        {
             if(!isalpha(str[i])) return false;
        }
        else if(!isdigit(str[i])) return false;
    }
    return true;
}

    

【讨论】:

    【解决方案2】:

    我建议你同时使用fgetssscanf

    • fgets 允许您读取一定数量的字符(可以从stdin 读取)。
    • sscanf 允许您从字符串(您从fgets 获得)读取格式化输入。

    通过组合它们,您可以从标准输入中读取 7 个字符(如果添加 \0,则为 8 个字符),然后解析这些字符以获得您要查找的两个值。

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    int main()
    {
        // 8 chars long for string and terminating `\0`
        char *ID = calloc(8, 1);
        
        // extra char for same reason as above
        char *IDchar = calloc(4, 1);
        int IDnum, processed;
        
        // get the string and verify it's 7 characters long
        if (fgets(ID, 8, stdin) && strlen(ID) == 7) 
            sscanf(ID, "%3s%4d%n", IDchar, &IDnum, &processed);
        if (processed == 7)
            printf("success");
        else
            printf("failure");
    }
    

    %n 将收集sscanf 处理的字符数,确保您解析正确的字符数。 请注意,这是一个非常危险的参数,您应该始终在使用它之前验证您的输入长度。

    编辑:

    如果您根本不想使用数组,而只想验证输入格式不存储或重复使用它,您可以使用getc 一次读取一个字符,然后验证它们的价值:

    #include <stdio.h>
    #include <ctype.h>
    int isEnd(int c)
    {
        return c == '\n' || c == EOF;
    }
    void main()
    {
        int tmp;
        int valid = 1;
        //check the first 3 characters
        for(int v = 0; v < 3 && valid; v++)
        {
            // read a char on standard input
            tmp = fgetc(stdin);
            // check if tmp is a letter
            valid = islower(tmp) || isupper(tmp);
        }
        //check the next 4 characters
        for(int v = 0; v < 4 && valid; v++)
        {
            // read a char on standard input
            tmp = fgetc(stdin);
            // check if tmp is a numeral
            valid = isdigit(tmp);
        }
        if (valid)
        {
            printf("format OK\n");
            // Check that the input is finished (only if format is OK)
            tmp = fgetc(stdin);
            if (isEnd(tmp))
                printf("length OK\n");
            else
                printf("length KO: %d\n", tmp);
        }
        else
        {
            printf("format KO\n");
        }
    }
    

    正如我之前所说,这只会检查输入的有效性,不会存储它或允许您重复使用它。但它不使用数组。

    编辑 2:

    使用fgetcgetc 需要注意的另一件事是,虽然它可以正确管理更长的输入,但如果没有足够的字符,它会在等待提供字符时卡住。因此,请确保在您读取到错误字符时退出(如果它是行尾字符,则不会再出现)

    编辑 3:

    我当然忘记了 malloc。 编辑了第一个答案。

    【讨论】:

    • 你试过编译你的代码吗?此外,OP 对使用数组不感兴趣。
    • @QuibbleCoinbiter 我添加了一个潜在的解决方案。它没有实际用途,但它解决了你的问题
    • @QuibbleCoinbiter 只需检查最后一次编辑,因为代码不起作用(交换了 sscanf 的第一个和第二个输入)。另请记住,第一个不会验证前 3 个字符是字母还是数字或任何东西,它只会读取它们
    • 1. fgetc() 返回 int,而不是 char。如果将返回值塞进char,则无法可靠地检查EOF。 2.isUpperCaseLetter()?你在重新创建isupper()isdigit() 等标准C 函数?
    • @QuibbleCoinbiter 输入验证非常重要,所以这将永远有用。嗯,是的,也不是。 Adalcar 的回答作为对具有人为约束的学习练习的回答没有任何问题。但是对于真正的程序来说,比scanf 家族的任何成员都更好地进行输入验证。 (特别是,在实际程序中,您可能希望使用真正的正则表达式解析器,而不是有限的伪正则表达式处理 scanfsscanf。)
    猜你喜欢
    • 2022-07-28
    • 1970-01-01
    • 2019-09-21
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多