Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中不使用scanf()函数将十六进制输入存储到int变量中_C_Integer_Hex_Scanf - Fatal编程技术网

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

在C中不使用scanf()函数将十六进制输入存储到int变量中,c,integer,hex,scanf,C,Integer,Hex,Scanf,史前: 我有一个问题,getchar函数没有得到正确的处理,因为没有对任何给定输入的请求,程序只是继续进一步处理 我在互联网上搜索了这个问题,发现如果scanf函数在getchar函数之前实现到一个程序中,getchar函数的行为就不正确,并且会像我的问题一样 引文: 我敢打赌100美元,只有在调用getchar之前加上scanf时,您才会看到这个问题 不要将scanf用于交互式程序。这主要有两个原因: 1 scanf无法从格式错误的输入中恢复。每次都必须正确地获取格式字符串,否则它会丢弃任何无

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

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

引文:

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

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

1 scanf无法从格式错误的输入中恢复。每次都必须正确地获取格式字符串,否则它会丢弃任何无法匹配的输入,并返回一个表示失败的值。如果在解析固定格式的文件时,格式不好是不可恢复的,那么这可能很好,但这与您希望对用户输入执行的操作完全相反。使用fgets和sscanf、fgets和strtok,或者使用getchar和putchar编写自己的用户输入例程

1.5即使正确使用,scanf也不可避免地丢弃有时可能很重要的输入空白

2 scanf有一个坏习惯,就是在输入流中留下换行符。如果您只使用scanf,这是很好的,因为scanf通常会跳过任何空白字符,以急切地查找下一步需要的内容。但是如果您将scanf与fgets/getchar混合使用,那么很快就会变得一团糟,试图弄清楚输入流中可能会或可能不会有什么悬而未决的内容。特别是如果您执行任何循环,输入流在第一次迭代时出现差异是很常见的,这会导致潜在的奇怪错误,甚至更奇怪的修复尝试

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

以下是指向该线程的链接:

scanf具有:

scanf("%x",integer_variable); 
对我来说,作为一个新手,这似乎是唯一可能从键盘输入十六进制数的方法,或者更好地说是从stdin文件输入十六进制数并将其存储到int变量

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

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

unsigned int v ;
if ( scanf("%x", &v) == 1 ) {
   // do something with v.
}
信息:我在Stackoverflow上读过很多关于C的线程,都是关于类似的问题,但没有一个能很好地回答我的明确问题。所以我已经发布了这个问题

我在Linux Ubuntu下工作。

根据scanf手册页,您可以使用scanf将十六进制数从stdin读入无符号整数变量

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

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

如您发布的链接中所述,使用fgets和sscanf是处理此问题的最佳方法。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);
}    

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

起初你说

scanf与…%D对我来说,作为一个新手,这似乎是唯一可以从键盘输入十六进制数的方法

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

scanf%d,整型变量(&U); 你说得对,这是表面上最简单的方法

char-buf[100]; fgetsbuf、sizeofbuf、stdin; 整数_变量=atoibuf; 我认为,这是不使用scanf的最简单的方法。但是现在大多数人都不赞成使用atoi,因为它没有做很多有用的错误检查

char-buf[100]; fgetsbuf、sizeofbuf、stdin; 整数_变量=strtolbuf,NULL,10; 这与以前几乎相同,但避免了atoi,而是选择了首选的strtol

char-buf[100]; fgetsbuf、sizeofbuf、stdin; sscanfbuf,%d和整型变量; 这将读取一行,然后使用sscanf解析它,这是另一种流行且通用的技术

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

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

scanf%x,整型变量(&U)

char-buf[100]; fgetsbuf、sizeofbuf、stdin; 整数_变量=strtolbuf,NULL,16

char-buf[100]; fgetsbuf、sizeofbuf、stdin; sscanfbuf,%x和整型变量

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

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

正如你所看到的,这有点让人大吃一惊。我,虽然我几乎从不使用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)
通常,我不是使用getchar从stdin解析十六进制数字,而是从字符串解析十六进制数字。我经常使用字符指针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的函数版本,而不适用于宏,因为宏会多次计算其参数

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

用户点击Return而不键入任何内容。 用户在数字之前或之后键入空格。 用户在数字后键入额外垃圾。 用户键入非数字输入,而不是数字。 代码到达文件末尾;根本没有要读取的字符。 然后你如何处理这些取决于你使用的是什么输入技术。以下是基本规则:

A.如果您正在调用scanf、fscanf或sscanf,请始终检查返回值。如果它不是1,或者在您有多个%说明符的情况下,它不是您希望读取的值的数量,这意味着出现了问题。这通常会捕捉到问题4和5,并将优雅地处理案例2。但它通常会悄悄地忽略问题1和3。特别是,scanf和fscanf处理额外的\n就像处理前导空格一样

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

C.如果你打电话给atoi,它会优雅地处理问题2,但它会忽略问题3,它会悄悄地将问题4变成数字0,这就是为什么通常不再推荐atoi的原因

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


最后,如果你在做一些下流肮脏的事情,比如我的hardway两位数十六进制转换器,你通常必须自己解决所有这些问题。如果您想跳过前导空格,您必须这样做,中的isspace函数可以提供帮助,如果可能存在意外的非数字字符,您也必须检查这些字符。这就是在我的hardway两位数十六进制转换器中,对isascii和isxdigit的调用所做的。

@RobertS你可能想澄清这个问题。我在回答“是否有其他方法可以从stdin输入十六进制值并将其存储到整数变量中?”+奖金。很抱歉,我在编写代码时出错,我在scanf命令中将%x与%d弄乱了。现在它总是有这些方面的困惑。我又写错代码了。谢谢史蒂夫,我在我的问题中编辑了它。这是如此多精彩的信息,非常感谢。我并不是想用这句话来破坏一天的时间:-@RobertS谢谢,你可以随意接受答案,但是:毁灭?不
一点也不。如果我真的不喜欢这样做,你认为我会花时间写这样的答案吗?@xOneca这是为了解决一个字符可能是负数的可能性,但我忘了这可能不是正确的方式。我喜欢区分尾随空格和其他额外字符,尽管做出这样的区分显然更令人讨厌。如果strtol也能处理尾随空格,那就太好了。