运行时使用fscanf()进行“访问冲突”,但在调试时则不行

时间:2012-06-22 19:04:32

标签: c struct access-violation scanf

有没有人知道这里会发生什么?

我得到了

Unhandled exception at 0x5081f508 (msvcr100d.dll) in myProgram.exe: 0xC0000005: Access violation writing location 0x041e0010.

在这一行:

fscanf(fp, " %lf %lf %lf\n", &vertices[i].x, &vertices[i].y, &vertices[i].z );

运行我的程序时,但是当我在调试模式(Visual Studio 2010)中逐步执行它时,一切都很顺利; fscanf()按预期读取文件。

该异常实际上是在input.c行:

#else  /* _UNICODE */
       _FASSIGN( longone-1, (char*)pointer , pFloatStr, (char)decimal, _loc_update.GetLocaleT());
#endif  /* _UNICODE */

如果我没有弄错的话。我不知道关于UNICODE的这些评论是什么意思,这就是为什么我把它们包括在这里。


其他信息

调用堆栈:

msvcr100d.dll!_fassign_l(int flag, char * argument, char * number, localeinfo_struct * plocinfo)  Line 258 + 0x6 bytes  C++   

>msvcr100d.dll!_input_l(_iobuf * stream, const unsigned char * format,    localeinfo_struct * plocinfo, char * arglist)  Line 1281 + 0x21 bytes C++

msvcr100d.dll!vfscanf(int (_iobuf *, const unsigned char *, localeinfo_struct *, char *)* inputfn, _iobuf * stream, const char * format, localeinfo_struct * plocinfo, char * arglist)  Line 61 + 0x13 bytes    C

msvcr100d.dll!fscanf(_iobuf * stream, const char * format, ...)  Line 99 + 0x18 bytes   C

myProgram.exe!main(int argc, char * * argv)  Line 166 + 0x49 bytes  C++

myProgram.exe!__tmainCRTStartup()  Line 555 + 0x19 bytes    C

myProgram.exe!mainCRTStartup()  Line 371    C

其他一些信息

该程序与OpenGL的着色有关,您在vertices调用中看到的fscanf()是这些的数组:

typedef struct _Vertex {
    double  x, y, z;
    int polygonsThisPartOf; // Number of polygons this vertex is a part of
    Point normal;
} Vertex;

在我的程序的第一个版本中,vertices是一个数组数组,一切运行正常;在我修改代码以使用vertices作为上述struct的数组后,此异常开始发生。

数组的分配

    //                                              ˇ THIS is the mistake
vertices = (Vertex *) malloc(vcount * sizeof(Vertex *));
if (vertices == NULL) exit(-2);

vcount是正确的。

3 个答案:

答案 0 :(得分:1)

1)您的“fscanf()”语法看起来没问题。

2)“_UNICODE”消息(在你进入的MSVC内部)里只是意味着你正在使用所有Win32代码的16位Unicode版本,它们需要16位Unicode格式字符串(而不是8位) ASCII格式字符串)。

这是正常的和预期的。如果您正在从Visual Studio中的源代码编译所有内容,那么它应该不是问题。

3)我会集中精力确保您的数组元素“vertices [i]”已成功分配。

建议:

在“fscanf()”中输入一个断点,然后在调试器中调用fscanf之前查看变量

此外,您可能希望在fscanf之前添加它,并将断点放在此调试行:

 vertices[i].x = vertices[i].y = vertices[i].z = 0;

答案 1 :(得分:1)

问题出现在代码中的某个地方,甚至可能与你的fscanf调用无关,在某个地方写入的内存位数比它最有可能的字节数多。当你在调试模式下运行时,它会分配超过必要的内存,所以你通常不会在调试模式下看到错误,但是一个好的调试器应该告诉你何时写入缓冲区的长度。

答案 2 :(得分:1)

过去,当我遇到在调试版本中没有重现的错误时,它几乎总是缓冲区溢出或某种指针错误。

调试版本可能会略微不同地构建堆栈;堆栈中可能有额外的东西,有时当你写下缓冲区的末尾时,写入调试内容并没有明显的错误发生。当然,这假设缓冲区已在堆栈上分配。或者,如果缓冲区在堆中,那么您的调试版本可能在堆上有额外的东西(可能还有其他字符串)。

因此,检查变量i并确保它没有在数组末尾编入索引。并检查您的变量fp并确保它指向一个合理的位置;如果是通过指针算法确定的,请确保指针数学是正确的。

如果它没有在调试版本中重新编写,那么您应该检测版本构建以打印i的值,fp的值,以及其他一些内容(例如,如果fp是指向缓冲区内的指针,该缓冲区的当前地址和当前长度,那么您可以看到fp是否在缓冲区内。

P.S。我听说过这种叫做“Heisenbug”的虫子。尝试调试它会改变它的行为!