【问题标题】:"Access violation" with fscanf() when running, but not when debugging运行时 fscanf() 出现“访问冲突”,但调试时没有
【发布时间】:2012-06-22 19:04:31
【问题描述】:

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

我明白了

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 的 cmets 是什么意思,这正是我将它们包括在这里的原因。


其他信息

调用栈:

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 作为上述structs 的数组后,此异常开始发生。

数组的分配

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

vcount 是正确的。

【问题讨论】:

  • 你能把它归结为minimal test case吗?即出现此问题的 10 行程序?
  • 向我们展示你是如何初始化vertices的。
  • @Bloke - 换句话说(正如我在回复中暗示的那样),我们不知道您是否在开始将数据读入数组之前成功地为数组分配空间。我希望我下面的建议对您有所帮助...
  • 分配顶点数组的代码是什么样的?
  • 对,分配。对不起,就这样吧。检查编辑。

标签: c struct access-violation scanf


【解决方案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;

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      调试版本构建堆栈的方式可能略有不同;堆栈上可能有额外的东西,有时当您注销缓冲区的末尾时,写入会进入调试内容,并且没有任何明显的坏事发生。当然,这假设缓冲区是在堆栈上分配的。或者,如果缓冲区在堆中,那么您的调试版本可能在堆上有额外的东西(可能是额外的字符串)。

      因此,请检查您的变量 i 并确保它没有从数组末尾索引。并检查您的变量fp 并确保它指向合理的地方;如果它是由指针算法确定的,请确保指针数学是正确的。

      如果它没有在调试版本中重现,那么您应该检测您的发布版本以打印 i 的值、fp 的值,以及可能的其他一些内容(例如,如果 fp是指向缓冲区内部的指针,该缓冲区的当前地址和当前长度,因此您可以查看fp 是否在缓冲区内。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多