有没有人知道这里会发生什么?
我得到了
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
是正确的。
答案 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”的虫子。尝试调试它会改变它的行为!