当前位置: 首页 > 知识库问答 >
问题:

在C中不使用scanf()函数将十六进制输入存储到int变量中

缪成天
2023-03-14

史前:我有一个问题,getchar()函数没有得到正确的处理,因为没有对任何给定输入的请求,程序只是继续进一步处理。

我在互联网上搜索了这个问题,发现如果scanf()函数在getchar()函数之前被实现到一个程序中,getchar()函数就不会以正确的方式运行,并且会像我的问题一样。

引用:

我敢打赌100美元,只有在调用getchar()之前加上scanf()时,您才会看到这个问题。

不要将scanf用于交互式程序。这主要有两个原因:

1)scanf无法从格式错误的输入中恢复。您必须每次都正确设置格式字符串,否则它只是丢弃了它无法匹配的任何输入,并返回一个指示失败的值。如果您正在解析一个固定格式的文件,而糟糕的格式无论如何都是不可恢复的,这可能是好的,但是这与您想要对用户输入进行的操作正好相反。使用fget()和sscanf()、fget()和strtok(),或者使用getchar()和putchar()编写自己的用户输入例程。

1.5)即使使用得当,scanf也不可避免地丢弃有时可能很重要的输入(空白)。

2)scanf有在输入流中留下换行符的坏习惯。如果你只使用scanf,这很好,因为scanf通常会跳过任何空白字符,急于找到它下一步想要的东西。但是如果你把scanf和fget/getchar混合在一起,试图弄清楚输入流中可能会或不会留下什么,很快就会变得一团糟。特别是如果您执行任何循环--输入流在第一次迭代时不同是很常见的,这会导致潜在的奇怪错误,甚至更奇怪的修复尝试。

tl; dr--scanf用于格式化输入。用户输入未格式化。//

以下是指向该线程的链接:https://bbs.archlinux.org/viewtopic.php?id=161294

scanf()与:

scanf("%x",integer_variable); 

对我来说,作为一个新手,这是从键盘输入十六进制数字(或者更好地说是标准输入文件)并将其存储到int变量的唯一方法。

是否有其他方法从标准输入十六进制值并将其存储到整数变量中?

额外挑战:如果我能将负值(当然是通过负十六进制输入)写入一个有符号的int变量,那也太好了。

信息:我在Stackoverflow上读过很多关于C的线程,都是关于类似的问题,但没有一个能很好地回答我的明确问题。所以我已经发布了这个问题。

我在Linux Ubuntu下工作。

共有3个答案

易阳云
2023-03-14

正如您发布的链接中所述,使用fgetssscanf是处理此问题的最佳方法fgets将读取整行文本,sscanf将解析该行。

例如

char line[100];
fgets(line, sizeof(line), stdin);

int x;
int rval = sscanf(line, "%x", &x);
if (rval == 1) {
    printf("read value %x\n", x);
} else {
    printf("please enter a hexadecimal integer\n");
}

因为您只读取一个整数,所以也可以使用strtol而不是sscanf。这还具有检测是否输入了任何其他字符的优点:

char *ptr;
errno = 0;
long x = strtol(line, &ptr, 16);
if (errno) {
    perror("parsing failed");
} else if (*ptr != '\n' && *ptr != 0) {
    printf("extra characters entered: %s\n", ptr);
} else {
    printf("read value %lx\n", x);
}    
衡丰茂
2023-03-14

在scanf手册页中,您可以使用scanf将十六进制数从stdin读入(无符号)整数变量。

unsigned int v ;
if ( scanf("%x", &v) == 1 ) {
   // do something with v.
}

根据手册页,%x始终未签名。如果要支持负值,则必须添加显式逻辑。

淳于博文
2023-03-14

关于百元赌注的报价是准确的。将scanfgetchar混合几乎总是一个坏主意;它几乎总是导致麻烦。但这并不是说它们不能一起使用。它们可以一起使用——但通常情况下,这太难了。有太多的琐碎细节和“明白了!”这是要跟踪的。麻烦太多了。

起初你说

scanf()与<代码>%d。。。对我来说,作为一个新手,这似乎是唯一可以从键盘输入十六进制数的方法

这里有一些混乱,因为当然%d是十进制输入。但由于在你纠正这个问题时我已经写了这个答案,现在让我们继续小数点。(目前我还不考虑错误检查——也就是说,如果用户没有键入请求的数字,这些代码片段不会检查或执行任何优雅的操作。)无论如何,这里有几种读取整数的方法:

>

  • scanf(“%d”,

    char buf[100];
    fget(buf, sizeof(buf), stdin);
    integer_variable=atoi(buf);
    我认为这是不使用scanf的最简单方法。但是现在大多数人不喜欢使用atoi,因为它没有做很多有用的错误检查。

    char buf[100];
    fget(buf, sizeof(buf), stdin);
    integer_variable=strtol(buf, NULL,10);
    这几乎和以前一样,但避免了有利于的首选strtol

    char buf[100];
    fget(buf, sizeof(buf), stdin);
    sscanf(buf,"%d",

    所有这些都将起作用;所有这些都将处理负数。不过,考虑错误条件是很重要的——我稍后会对此有更多要说的。

    如果要输入十六进制数,技术类似:

    scanf(“%x”,

    char buf[100];
    fget(buf, sizeof(buf), stdin);
    integer_variable=strtol(buf, NULL,16);

    char buf[100];
    fget(buf, sizeof(buf), stdin);
    sscanf(buf,"%x",

    这些也都应该有效。不过,我不一定期望它们处理“负十六进制”,因为这是一个不寻常的要求。大多数情况下,十六进制表示法用于无符号整数。(事实上,严格来说,%xwithscanfsscanf必须与声明为无符号int整型变量一起使用,而不是纯int

    有时“用手”做这类事情是有用的或必要的。这里有一个代码片段,它正好读取两个十六进制数字。我将从使用getchar的版本开始:

    int c1 = getchar();
    if(c1 != EOF && isascii(c1) && isxdigit(c1)) {
        int c2 = getchar();
        if(c2 != EOF && isascii(c2) && isxdigit(c2)) {
            if(isdigit(c1)) integer_variable = c1 - '0';
            else if(isupper(c1)) integer_variable = 10 + c1 - 'A';
            else if(islower(c1)) integer_variable = 10 + c1 - 'a';
    
            integer_variable = integer_variable * 16;
    
            if(isdigit(c2)) integer_variable += c2 - '0';
            else if(isupper(c2)) integer_variable += 10 + c2 - 'A';
            else if(islower(c2)) integer_variable += 10 + c1 - 'a';
        }
    }
    

    正如你所看到的,这有点让人大吃一惊。对我来说,虽然我几乎从不使用scanf家族的成员,但这是我有时使用的地方,正是因为“用手”做这件事需要做很多工作。通过使用辅助函数或宏进行数字转换,可以大大简化:

    int c1 = getchar();
    if(c1 != EOF && isascii(c1) && isxdigit(c1)) {
        int c2 = getchar();
        if(c2 != EOF && isascii(c2) && isxdigit(c2)) {
            integer_variable = Xctod(c1);
            integer_variable = integer_variable * 16;
            integer_variable += Xctod(c2);
        }
    }
    

    或者你可以把那些内心的表达压缩成

            integer_variable = 16 * Xctod(c1) + Xctod(c2);
    

    这些功能在辅助功能方面起作用:

    int Xctod(int c)
    {
        if(!isascii(c)) return 0;
        else if(isdigit(c)) return c - '0';
        else if(isupper(c)) return 10 + c - 'A';
        else if(islower(c)) return 10 + c - 'a';
        else return 0;
    }
    

    或者是宏观的(尽管这绝对是一种老派的东西):

    #define Xctod(c) (isdigit(c) ? (c) - '0' : (c) - (isupper(c) ? 'A' : 'a') + 10)
    

    我经常这样解析十六进制数字不是从stdin使用getchar(),而是从字符串。我经常使用字符指针(char*p)来遍历字符串,这意味着我最终得到的代码更像这样:

    char c1 = *p++;
    if(isascii(c1) && isxdigit(c1)) {
        char c2 = *p++;
        if(isascii(c2) && isxdigit(c2))
            integer_variable = 16 * Xctod(c1) + Xctod(c2);
    }
    

    省略临时变量和错误检查并进一步归结为:

    integer_variable = 16 * Xctod(*p++) + Xctod(*p++);
    

    但不要这样做!除了缺少错误检查之外,这个表达式可能是未定义的,而且它肯定不会总是做您想要做的事情,因为您读取字符的顺序不再有任何保证。如果您知道p位于两个十六进制数字的第一个,那么您不希望将其折叠到超过

    integer_variable = Xctod(*p++);
    integer_variable = 16 * integer_variable + Xctod(*p++);
    

    即使如此,这也只适用于函数版本的Xctod,而不适用于宏,因为宏会多次计算其参数。

    最后,让我们谈谈错误处理。有相当多的可能性需要担心:

    1. 用户点击Return而不键入任何内容
    2. 用户在数字之前或之后键入空格
    3. 用户在数字后键入额外垃圾
    4. 用户键入非数字输入,而不是数字
    5. 代码到达文件末尾;根本没有要读取的字符

    然后你如何处理这些取决于你使用的是什么输入技术。以下是基本规则:

    A.如果您正在调用scanffscanfsscanf,请始终检查返回值。如果它不是1(或者,在您有多个%说明符的情况下,它不是您期望读取的值的数量),这意味着出错了。这通常会抓住问题4和5,并优雅地处理案例2。但它往往会悄悄忽略问题1和3。(特别地,scanffscanf对待额外的\n就像领导空白一样。)

    B.如果您正在调用fgets,请再次检查返回值。在EOF(问题5)中,您将得到NULL。其他问题的处理取决于你如何处理你读到的那一行。

    C.如果您正在呼叫atoi,它将优雅地处理问题2,但它将忽略问题3,并将悄悄地将问题4变成数字0(这就是为什么atoi通常不再被推荐的原因)。

    D.如果您正在调用strtol或任何其他“strto”函数,它们将优雅地处理问题2,如果您让它们返回“结束指针”,您可以检查并处理问题3和问题4。(注意,我在上面的两个strtol示例中没有处理结束指针。)

    最后,如果你在做一些下流肮脏的事情,比如我的“hardway”两位数十六进制转换器,你通常必须自己解决所有这些问题。如果要跳过前导空格,必须这样做(来自

  •  类似资料:
    • 用户用十六进制或二进制输入一个数字(必须以0x或0b为前缀,如果没有给出错误信息) 我不能用基数,我只是用整数。parseInt(s) 我不知道怎样才能使这个计划奏效。。请帮帮我,我还缺什么?

    • 问题内容: 我是JavaScript和jQuery的新手,现在面临一个问题: 我需要将一些数据发布到PHP,并且其中一部分数据必须是div X的背景色十六进制。 jQuery具有css(“ background-color”)函数,通过它我可以将背景的RGB值转换为JavaScript变量。 CSS函数似乎返回了一个类似rgb(0,70,255)的字符串。 我找不到任何方法来获取背景颜色的十六进制

    • 问题内容: 如上面的标题。我想从一个十六进制数字 我想转换为。 问题答案:

    • 我有十六进制字符串,例如“0x103E”,我想将其转换为整数。意思是to我尝试了但它给出了数字格式异常。我如何实现这一点?

    • 问题内容: 如何将RGB格式的颜色转换为十六进制格式,反之亦然? 例如,转换为。 问题答案: 注 :这两个版本的期待整数值,并且,所以你需要,如果你有非整数值做自己的舍入。 以下将执行RGB到十六进制的转换,并添加任何所需的零填充: 转换另一种方式: 最后,在答案中讨论并在@cwolves的评论中建议使用的替代版本: 更新 这是它的一个版本,还解析了一个速记的三元组,例如“#03F”: