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

问题描述 投票:0回答:3

这里可能发生了什么?

我明白了

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
是正确的。

c struct access-violation scanf
3个回答
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
投票
问题出在代码中的某个地方,它甚至可能与您的 fscanf 调用无关,某个内存位置写入的字节数可能超过了它所能容纳的字节数。当您在调试模式下运行时,它会分配比所需更多的内存,因此您通常不会在调试模式下看到错误,但一个好的调试器应该告诉您何时写入超过缓冲区的长度。


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

调试构建可能会稍微不同地构建堆栈;堆栈上可能有额外的内容,有时当您写出缓冲区末尾时,写入会进入调试内容,并且不会发生明显的不良情况。当然,这假设缓冲区是在堆栈上分配的。或者,如果缓冲区位于堆中,那么您的调试版本可能在堆上有额外的内容(可能还有其他字符串)。

因此,检查您的变量

i

 并确保它没有在数组末尾进行索引。并检查你的变量
fp
并确保它指向某个合理的地方;如果是通过指针算术确定的,请确保指针算术正确。

如果它在调试版本中没有重现,那么您应该检测您的发布版本以打印

i

 的值、
fp
 的值,以及可能的其他一些内容(例如,如果 
fp
 是指向缓冲区内部的指针、该缓冲区的当前地址和当前长度,以便您可以查看 
fp
 是否在缓冲区内)。

附注我听说过这种错误称为“Heisenbug”。尝试调试它会改变它的行为!

© www.soinside.com 2019 - 2024. All rights reserved.