运行时fscanf()的“访问冲突”,但调试时不会

kqlmhetl  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(166)

这是怎么回事
我得到
myProgram.exe中0x 5081 f508(msvcr100d.dll)处的未处理异常:0xC0000005:访问冲突写入位置0x 041 e0010。
在这一行:

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的着色,你在fscanf()调用中看到的vertices是一个数组:

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

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

分配数组

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

vcount是正确的。

mo49yndu

mo49yndu1#

1)您的“fscanf()”语法看起来没问题。
2)“_UNICODE”消息(在您进入的MSVC内部)只是表示您正在使用所有Win32代码的16位Unicode版本,这些代码需要16位Unicode格式字符串(而不是8位ASCII格式字符串)。
这是正常的,也是意料之中的。如果你是从Visual Studio内部的源代码编译所有东西,这不应该是一个问题。
3)我将集中精力确保您的数组元素“vertices[i]”已成功分配。
建议:
在“fscanf()”处放入断点,并在调试器中调用fscanf之前查看变量。
此外,您可能希望在fscanf之前添加this,并将断点放在此调试行:

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

krugob8w2#

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

7cwmlq89

7cwmlq893#

在过去,当我遇到在调试版本中没有重现的bug时,几乎总是缓冲区溢出或某种指针错误。
调试构建可能会以稍微不同的方式构建堆栈;堆栈上可能有多余的东西,有时当你写缓冲区的末尾时,写操作会进入调试程序,没有明显的错误发生。当然,这假设缓冲区是在堆栈上分配的。或者,如果缓冲区在堆中,那么您的调试构建可能在堆中有额外的东西(可能是额外的字符串)。
所以,检查变量i,确保它没有索引到数组的末尾。检查你的变量fp,确保它指向某个合理的地方;如果它是由指针运算确定的,请确保指针运算正确。
如果它在调试版本中没有重现,那么你应该检测你的发布版本来打印i的值,fp的值,也许还有一些其他的东西(比如,如果fp是一个指向缓冲区内部的指针,则是该缓冲区的当前地址和当前长度,这样你就可以看到fp是否在缓冲区内)。
P.S.我听说过这种虫子叫“海森虫”。尝试调试它会改变它的行为!

相关问题