在C ++中使用fscanf的正确方法

时间:2017-06-16 05:43:56

标签: c++ io segmentation-fault scanf

我正在尝试使用以下格式从csv文件中读取数据:

a_x,a_y,v_x,o_rear,o_front,theta,type
-0.040,10.206,-0.000,0.000,-0.000,-0.002,plane
1.269,9.813,0.011,0.043,0.091,-0.002,plane
1.266,9.985,0.021,0.086,0.177,-0.002,plane
1.257,10.002,0.032,0.130,0.265,-0.002,plane
1.256,10.004,0.043,0.173,0.353,-0.002,plane
1.257,10.003,0.053,0.216,0.440,-0.002,plane
1.258,10.002,0.064,0.259,0.527,-0.002,plane
1.258,10.002,0.074,0.302,0.615,-0.002,plane

我写了以下代码: -

FILE *in_file = fopen(argv[1], "r");
        int i=0, s=0;

        char *temp;
        fscanf(in_file,"%s",temp);
        printf("%s\n",temp);
        while(i<100){
            float a_x,a_y,v_x,o_rear,o_front,theta;
            char *type;
            if((s = fscanf(in_file,"%f,%f,%f,%f,%f,%f,%[^,]",&a_x,&a_y,&v_x,&o_rear,&o_front,&theta,type))!=7)
                printf("%7d,%d,%f,%f,%f,%f,%f,%f,%s\n",++i,s,a_x,a_y,v_x,o_rear,o_front,theta,type);
            else{
                printf("ALL GOOD: %7d\n",++i);
            }
        }

我遇到了分段错误。在运行gdb时,我发现它出现在fscanf(in_file,"%s",temp);行,并出现以下错误: -

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff71c6f64 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffda48, errp=errp@entry=0x0)
    at vfscanf.c:1107
1107    vfscanf.c: No such file or directory.

堆栈跟踪: -

#0  0x00007ffff71c6f64 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffda48, 
    errp=errp@entry=0x0) at vfscanf.c:1107
#1  0x00007ffff71cce47 in ___vfscanf (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffda48) at vfscanf.c:3066
#2  0x00007ffff71d47b7 in __fscanf (stream=<optimized out>, format=<optimized out>) at fscanf.c:31
#3  0x0000555555555186 in main (argc=2, argv=0x7fffffffdc58) at data_handler.cpp:23

令人惊讶的是,当我使用type变量转储第一行时,我没有遇到任何seg错误。相反,fscanf第一次返回7,然后返回0。因此,我可以正确读取第二行,但不能读取其他行。我究竟做错了什么?我想了解为什么会发生这种行为。

3 个答案:

答案 0 :(得分:4)

从C ++中读取文件的惯用方法是istream::operator>>,您可以找到here的详细文档。

它工作得更好,并且更难以获得分段错误和未定义的行为。

如果你打算解决这个问题 C way ,你应该使用C编译器(而不是C ++编译器),这段代码应该使用.c扩展名这个问题应该使用[c]标记。

尽管如此,无论您是C ++程序员还是C程序员,您都预期 阅读手册。例如,an fscanf manual会告诉您如何正确使用fscanf,从而回答这个问题。它说:

  

s匹配不是空格字符的字节序列。应用程序应确保相应的参数是指向 charsigned charunsigned char 数组的初始字节的指针,该数组足以接受序列和一个终止的空字符代码,应自动添加。

虽然手册页提供了重点,但我强调了您需要了解的最重要的部分:temp需要指向某些内容

目前情况下,您的变量temp可能指向任何没有例如,它可能包含空指针值,意味着它指向 nothing ;你还没有告诉它不这样做,对吗?

更改temp的声明,如下所示:

char temp[512];             // ... or
char *temp = new char[512]; // ... etc

其中任何一项都会确保temp中的fscanf(in_file, "%s", temp);表达位于数组

答案 1 :(得分:3)

您在temp的调用中使用fscanf,但未确定它指向可以读取数据的某个有效内存。这会导致未定义的行为。

您可以使用:

// Use any number that is big enough for your needs
char temp[200];

// Make sure you provide the maximum number of characters to
// read to temp, always leaving space for the null terminator.
fscanf(in_file, "%199s", temp);

答案 2 :(得分:1)

正如@PaulMcKenzie指出的那样,我没有初始化我的指针。所以我在所有地方使用了char x[100]而不是char *x。另一个问题是错误的格式字符串:它应该是"%f,%f,%f,%f,%f,%f,%s"而不是"%f,%f,%f,%f,%f,%f,%[^,]"