fgets在解析stl时抛出未处理的异常

时间:2014-05-29 03:21:14

标签: c++

我是c ++的新手,我正在尝试解析一个大约64MB且大约有18K行的stl文件。代码适用于前几百行,但随后fgets抛出异常:
"Unhandled exception at 0x77B0BAC5 (ntdll.dll) in STLparser.exe: 0xC0000024: There is a mismatch between the type of object required by the requested operation and the type of object that is specified in the request."
我已经手动检查了fgets抛出异常的行,那里没有任何异常。我现在没有选择权。任何帮助解决这个问题的人都将不胜感激。

===== CODE ==========================

#include<fstream>
#include<iostream>
#include"ParseString.h"
#include"Vectors.h"


using namespace std;

int main(void)
{
    //Define variables
    FILE *file;
    char *line = new char;
    parsestring oneline;
    int n_Vols = 0, n_Elms = 0, n_nods = -1, E = 0;
    Nod *nodes = new Nod();
    Nod dummy;
    Elm *elements = new Elm();
    int mycounter = 0;
    //Open file
    fopen_s(&file, "sample.stl", "r");
    while (fgets(line, 1024, file) != NULL) //**********Getting Error Here*************
    {
        // populate required data

    }

    fclose(file);
    printf("%d,%d,%d", n_Vols, n_Elms, n_nods);
    getchar();
    return 0;
}

===================

当破坏时,执行将在此功能(不是我的功能,内部功能)恢复

void __cdecl _unlock (
        int locknum
        )
{
        /*
         * leave the critical section.
         */
        LeaveCriticalSection( _locktable[locknum].lock );
}

6 个答案:

答案 0 :(得分:2)

而不是:

char* line = new char;

执行:

char[1024] line;

由于您没有分配任何内存,您可能会收到损坏的数据。

答案 1 :(得分:1)

char *line = new char;

这会在堆上分配一个字节,并使line指向它。

while (fgets(line, 1024, file) != NULL)

这会将最多1024个字节写入line指向的位置。 line只指向一个字节。这就是你的代码爆炸的原因。

答案 2 :(得分:1)

您应该为保存数据的行分配必要的内存空间。

char * fgets ( char * str, int num, FILE * stream );

<强> STR
指向复制字符串的字符数组的指针。
NUM
要复制到str的最大字符数(包括终止空字符)。

在代码中

,将num设置为1024,所以你的行应指向分配1024 * char size内存空间的位置。因此,您需要将代码修改为:

char *line = new char[1024];

顺便说一句。您应该在不再需要时释放堆资源。

delete nodes;  
delete elements;

答案 3 :(得分:1)

你在一个char上调用fgets,因为你做了:

char *line = new char;

您可能希望分配大小为1024的char数组

char line[1024]                // on the stack
char *line = new char[1024];   // or on the heap

答案 4 :(得分:1)

一个问题是:

char *line = new char;

您知道要制作数组有多大,因此需要调用new。其次,即使你打电话给new,上面那行也只为1个字符分配空间。

将上述内容更改为:

char line[1024];

再次,您确切地知道前面想要多少个字符,只需创建一个大小的数组。

此外,您在其他不需要的地方使用new

Nod *nodes = new Nod();
Elm *elements = new Elm();

通常这些错误来自:

  1. Java(或类似语言)程序员错误地认为他们必须使用new创建所有对象,或者
  2. 初学者C ++程序员,他们认为在向具有指针参数的函数提供参数时必须声明指针变量并分配内存。通常所需要的只是传递现有变量的地址(使用address-of运算符&)。
  3. 要创建对象,如果对象的生命周期在声明的块的范围内,则这就是必需的:

     Nod nodes;
     Elm elements;
    

    完成后,请使用.运算符代替->来访问nodeselements的成员。

    另一个问题是您没有检查对fopen_s的调用是否因NULL文件句柄而失败。如果使用NULL文件句柄调用fgets,则行为未定义(可能是崩溃)。在继续之前,请务必检查您是否已成功打开文件。

答案 5 :(得分:1)

你有几个正确的答案。但是,我认为你最好的方法是继续编写C ++:

#include <cstdio>
#include <fstream>
#include <string>
#include <vector>
#include "ParseString.h"
#include "Vectors.h"

int main()
{
    //Open file
    std::ifstream file("sample.stl");
    if (file.fail()) {
        std::fprintf(stderr, "Unable to open sample.stl\n");
        return 1;
    }

    int n_Vols = 0, n_Elms = 0, n_nods = -1;
    std::string buffer;
    while (std::getline(file, buffer)) {
        // populate required data
        // you can use buffer.c_str() to get a const char*
        parsestring oneline;
        int E = 0, mycounter = 0;

        // based on the name, I suspect you actually want multiple Nod's
        std::vector<Nod> nodes;
        Nod dummy;
        // based on the name, I suspect you actually want multiple Elm's
        std::vector<Elm> elements;
        ...
    }

    printf("%d,%d,%d", n_Vols, n_Elms, n_nods);
    getchar();
    return 0;
}

就个人而言,我喜欢std::,但其他人喜欢您最初使用的using namespace std方法。

我还应该提到fgets(和fgets_s)不会抛出C ++异常。有多种方法可以中止您的计划,您可以通过添加try { ... } catch块来解决您遇到的问题。

您可能遇到了段错误,但您可能会触发断言。您甚至可能遇到Windows结构化异常处理,与名称相反,它与C ++异常不同。你的程序最终会死掉,但它会因为不同的原因而死亡,你必须做不同的事情来处理异常,信号(段错误)或SEH。

不用担心,你最终会了解那些东西是什么;我只是想指出,#34;神秘地死亡&#34; 可以是由未捕获的异常引起的,但它可能由许多其他因素引起。