如何从C中的文件中读取和打印十六进制数字

时间:2016-10-21 11:17:16

标签: c

我试图从文件中读取14位长的十六进制数字,然后打印它们。我的想法是使用long long int并使用fscanf读取文件中的行,就像它们是字符串一样,然后使用atoll将字符串转换为十六进制数字。问题是我根据valgrind得到了fscanf线上的seg值,我完全不知道为什么。这是代码:

#include<stdio.h>

int main(int argc, char **argv){

if(argc != 2){
    printf("error argc!= 2\n");
    return 0;
   }

char *fileName = argv[1];    
FILE *fp = fopen( fileName, "r");

if(fp == NULL){
   return 0;
}

long long int num;
char *line;

while( fscanf(fp, "%s", line) == 1 ){
    num = atoll(line);
    printf("%x\n", num);
 }

return 0;

}

3 个答案:

答案 0 :(得分:4)

您确定要将数字作为字符串读取吗?为什么不允许scanf为你做工作?

long long int  num;

while( fscanf(fp, "%llx", &num) == 1 ){  // read  a long long int in hex
    printf("%llx\n", num);               // print a long long int in hex
}

BTW,请注意ll%x转换为printf的{​​{1}}尺寸说明符 - 它定义的整数值为long long类型。

修改
下面是两个循环的简单示例,它读取3行输入(连续行中有两个,没有和三个数字),带有'hex int'格式和'string'格式:
    http://ideone.com/ntzKEi
rewind的调用允许第二个循环读取相同的输入数据。

答案 1 :(得分:1)

line变量未初始化,因此当fscanf()取消引用时,您会得到未定义的行为。

您应该使用:

char line[1024];

while(fgets(line, sizeof line, fp) != NULL)

进行加载。

如果您使用的是C99,则可能需要使用uint64_t来保存该号码,因为这样可以清楚地表明14位十六进制数字(4 * 14 = 56)是否合适。

答案 2 :(得分:0)

其他答案都很好,但我想澄清你所看到的崩溃的实际原因。问题是:

fscanf(fp, "%s", line)

...本质上意味着“从文件中读取一个字符串,并将其存储在line所指向的缓冲区中”。在这种情况下,您的line变量尚未初始化,因此它不会指向任何位置。从技术上讲,这是未定义的行为;在实践中,结果通常是你在进程的地址空间中的某个任意位置写入;此外,由于它经常指向非法地址,因此操作系统可以检测并将其报告为违规或类似行为,如您所见。

请注意,带有fscanf转换的%s不一定会读取整行 - 它会读取由空格分隔的字符串。如果它们为空,它可能会跳过行,并且它可能会从一行读取多个字符串。如果您知道输入文件的精确格式(例如,每行总是有一个值),这可能无关紧要。

虽然在这种情况下可能只是使用适当的修饰符来读取十六进制数字(fscanf(fp, "%llx", &num)),而不是读取字符串并尝试进行转换,但是在某些情况下你会这样做需要阅读字符串,特别是整行。根据您所使用的平台,该问题有各种解决方案。如果它是GNU系统(通常包括Linux)并且您不关心可移植性,则可以使用m修饰符,并将line更改为&line

fscanf(fp, "%ms", &line);

这会将指向line的指针传递给fscanf,而不是其值(未初始化),而m会导致fscanf分配缓冲区并存储其line中的地址。然后,当您完成缓冲时,您应该free缓冲区。有关详细信息,请查看Glibc手册。这种方法的好处是你不需要事先知道线长。

如果您没有使用GNU系统或者您关心可移植性,请使用fgets而不是fscanf - 这更直接,并允许您限制读取行的长度,这意味着你不会溢出一个固定的缓冲区 - 只要知道它会一次读取整行,不像fscanf,如上所述。您应该将line声明为char - 数组而不是char *,并为其选择合适的大小。 (请注意,您还可以为fscanf指定“最大字段宽度”,例如fscanf(fp, "%1000s", line),但您确实可以使用fgets)。