C ++读取文件时未处理的异常

Posted

技术标签:

【中文标题】C ++读取文件时未处理的异常【英文标题】:C++ Unhandled exception when reading file 【发布时间】:2012-03-01 20:29:15 【问题描述】:

尝试编写 .ply 解析器以在 OpenGL 中使用 .ply 模型。

尝试开始读取 .ply 文件并写出它的所有行。 我的程序会这样做,但是当它打印出最后一行时,我得到未处理的异常:

PLY parser.exe 中 0x62aad540 (msvcr100d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。

这是我的代码:

#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>


using namespace std;


int main ()

    char buffer[10000];
    FILE * myFile;
    myFile = fopen("walkman.ply", "r");
    if(myFile != NULL)
    
        while (!feof(myFile))
        

               cout<<fgets(buffer, 10000, myFile);

        
        fclose(myFile);
    
    else
    
        cout<<"file not found"<<endl;
    

    system("pause");
    return 0;

这可能是我的代码中的愚蠢错误,但如果有人能发现导致此错误的错误,那就太好了。

【问题讨论】:

但是你根本没有使用&lt;fstream&gt; 【参考方案1】:

在我们深入了解错误是什么之前,您应该知道您收到的“未处理的异常...访问冲突读取位置0x00000000”消息不是由C++异常引起的;它相当于 Windows 的“分段错误”。您的代码试图取消引用 NULL 指针。

现在,您在使用FILE 对象时犯了一个经典错误。当您到达文件末尾时,feof(fp) 不会变为真。只有在您尝试读取过去文件末尾至少一次后,它才会变为真。因此,您的读取循环将迭代直到 after fgets 尝试读取文件末尾。当fgets 尝试读取文件末尾之后,它失败,并返回一个空指针,你盲目地将它传递给cout。卡布姆。

(顺便说一下,istream::eof() 也是这样工作的。)

这个循环的正确写法是

while (fgets(buffer, 10000, myFile))
    cout << buffer;

(或者,更好的是,其中之一:

while (fgets(buffer, 10000, myFile))
    fputs(buffer, stdout));

while(myFile.get(buffer, 10000))
    cout << buffer;

stdio.h FILEs 和iostreams 混合在一起有点奇怪。)

【讨论】:

【参考方案2】:

feof() 告诉您您已尝试读取文件末尾,而不是您已到达文件末尾。 fgets() 在文件末尾且没有更多数据可读取时返回 NULL。这就是异常的来源。在文件末尾,feof() 将返回 false,fgets() 将返回 NULL,这将在您的程序尝试执行 cout &lt;&lt; NULL; 时导致异常。

这是用 C 风格编写的惯用方式:

char buffer[10000];
FILE* myFile = fopen("walkman.ply", "r");
if (myFile != NULL) 
    while (fgets(buffer, sizeof(buffer), myFiles) 
        fputs(buffer, stdout);
    
    fclose(myFile);

或 C++ 风格:

std::string buffer;
std::ifstream myFile("walkman.ply");
if (myFile.is_open()) 
    while (std::getline(myFile, buffer)) 
        std::cout << buffer << '\n';
    

【讨论】:

fgets 不会修剪终止换行符,因此您必须将其与 fputs 配对,而不是 puts @Zack:谢谢。自从我编写生产 C 代码以来已经有好几年了。【参考方案3】:

编辑:我的预测是错误的,但如果您打算使用流,请阅读以下内容。

另外请考虑使用流(in )和向量,这些方法更不容易出错,并且符合 C++ 风格和精神。

std::ifstream in("walkman.ply", std::ios::binary);
std::vector<char> v(istream_iterator<char>(in),
                    istream_iterator<char>( ));

或者如果那应该是一个字符串值。

std::ifstream in("walkman.ply");
std::string str(istream_iterator<char>(in),
                istream_iterator<char>( ));
std::cout << str << std::endl;

【讨论】:

这可能会发生,但它会为访问冲突提供不同的地址。现在它指向 0x0000000,这意味着程序在某处取消引用 NULL 指针。 @MatteoItalia 直言不讳,我认为这是一个 C 问题,而不是 C++,如果我在上面给出的流实现中仍然存在错误,请告诉我。 我并不是说您的解决方案是错误的,而是您的诊断不正确。 投反对票,因为“char[] 不会以空结尾”是不正确的:fgets 保证如果成功,它将返回一个以空结尾的字符串。 @MatteoItalia 对不起,我之前遇到过严厉的。你是对的,Ferruccio 给出了一个很好的技术答案,我个人仍然会使用流,并且从问题的标记和措辞来看,我认为 OP 打算使用流,但由于某种原因没有。

以上是关于C ++读取文件时未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章

错误及异常处理-[PathTooLongException]指定的路径或文件名太长

Pyspark 在读取目录中的所有 parquet 文件时失败,但在单独处理文件时成功

java文件流stream,拷贝复制文件,读取文件,写入文件,及抛出异常的处理

Head First Python 学习笔记-Chapter3:文件读取和异常处理

gnuplot 如何从文件读取数据

用C语言编写程序处理图片bmp文件 1.读取图片的宽度,高度,每个像素所需的位数,水平分辨率,垂直