You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++读取.pnm文件触发SIGSEGV崩溃,求内存问题排查修复方案

Hey Augusto, let's break down why your code is hitting that SIGSEGV error with larger PNM files—there are two critical issues here, both tied to memory management and incorrect parsing logic. Let's walk through them and fix the code step by step.

1. Stack Overflow (The Immediate Crash Cause)

Your current code allocates huge arrays directly on the stack (the small, fixed-size memory region used for local variables):

  • string imgBody[BODY_SIZE]: For a 500x281 image, BODY_SIZE is 5002813 = 421,500. Each std::string on a 64-bit system takes at least 24 bytes, so this array alone uses ~9.9MB of stack space.
  • unsigned char numericBody[BODY_SIZE]: Adds another 421KB of stack usage.

Most Linux systems default to an 8MB stack size—you're already exceeding that with just these two arrays, which triggers a stack overflow and the SIGSEGV crash.

Fix: Use Heap Allocation with std::vector

Instead of stack arrays, use std::vector which allocates memory on the heap (your 8GB RAM is more than enough for this). Vectors also handle dynamic sizing automatically, which fixes our next problem.

2. Incorrect PNM Parsing Logic

PNM P3 (ASCII) files don't store each pixel value on its own line—lines can contain multiple values separated by whitespace. Your code uses getline to read entire lines into imgBody elements, so imgBody will have way fewer elements than BODY_SIZE. When numericParser tries to access imgBody[i] where i exceeds the actual number of elements, it's accessing out-of-bounds memory, which also causes SIGSEGV.

Fix: Read Individual Values, Not Lines

Skip header lines, then read every numeric value directly from the file (ignoring whitespace and comments), regardless of which line they're on. We'll also dynamically fetch the image dimensions from the PNM header instead of hardcoding them.

Modified Working Code

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm> // For std::min

#define IO_ERROR (5)
#define C_DIMENSION (3)
#define HEADER_SIZE (3)

using namespace std;

int readImage(string fileName, vector<string>& imgHeader, vector<string>& imgBody, int& xDim, int& yDim) {
    ifstream inputFile(fileName);
    if (!inputFile.is_open()) return IO_ERROR;
    
    string line;
    int headerCount = 0;
    // Read header lines, skipping comments
    while (headerCount < HEADER_SIZE) {
        getline(inputFile, line);
        if (line.empty() || line[0] == '#') continue;
        imgHeader.push_back(line);
        headerCount++;
    }
    
    // Extract image dimensions from header
    xDim = stoi(imgHeader[1]);
    yDim = stoi(imgHeader[2]);
    
    // Read all pixel values, skipping inline comments
    string value;
    while (inputFile >> value) {
        if (value[0] == '#') {
            // Skip the rest of the comment line
            getline(inputFile, line);
            continue;
        }
        imgBody.push_back(value);
    }
    
    inputFile.close();
    return 0;
}

void numericParser(const vector<string>& imgBody, vector<unsigned char>& numericBody) {
    numericBody.reserve(imgBody.size());
    for (const string& valStr : imgBody) {
        numericBody.push_back(static_cast<unsigned char>(stoi(valStr)));
    }
}

void rgbParser(const vector<unsigned char>& numericBody, vector<vector<vector<unsigned char>>>& rgbMatrix, int xDim, int yDim) {
    // Initialize 3D vector for RGB data
    rgbMatrix.resize(xDim, vector<vector<unsigned char>>(yDim, vector<unsigned char>(C_DIMENSION)));
    int idx = 0;
    for (int i = 0; i < xDim; i++) {
        for (int j = 0; j < yDim; j++) {
            for (int c = 0; c < C_DIMENSION; c++) {
                if (idx >= numericBody.size()) break; // Guard against incomplete files
                rgbMatrix[i][j][c] = numericBody[idx];
                idx++;
            }
        }
    }
}

void printInfo(const vector<string>& header, const vector<string>& body) {
    cout << "#-*- Image Header -*-" << endl;
    for (const string& headerLine : header) {
        cout << headerLine << endl;
    }
    cout << "#-*- Image Body -*-";
    int printMax = min(static_cast<int>(body.size()), 5 * C_DIMENSION);
    for (int i = 0; i < printMax; i++) {
        if (i % 3 == 0) cout << endl << "R: " << body[i];
        else if (i % 3 == 1) cout << " G: " << body[i];
        else cout << " B: " << body[i];
    }
    cout << endl << ". . ." << endl;
}

int main() {
    string fileName;
    cout << "File name: ";
    cin >> fileName;
    
    vector<string> imgHeader;
    vector<string> imgBody;
    int xDim, yDim;
    
    if (readImage(fileName, imgHeader, imgBody, xDim, yDim) == IO_ERROR) {
        cerr << "Error: Could not open file!" << endl;
        return IO_ERROR;
    }
    
    printInfo(imgHeader, imgBody);
    
    vector<unsigned char> numericBody;
    numericParser(imgBody, numericBody);
    
    vector<vector<vector<unsigned char>>> rgbMatrix;
    rgbParser(numericBody, rgbMatrix, xDim, yDim);
    
    cout << "Successfully parsed image of size " << xDim << "x" << yDim << endl;
    
    return 0;
}

Key Improvements

  • Heap Allocation: All large data structures use std::vector, avoiding stack overflow entirely.
  • Dynamic Sizing: Image dimensions are read from the PNM header, so the code works with any valid P3 file, not just fixed 500x281 ones.
  • Correct Parsing: Reads individual pixel values instead of lines, handling comments and whitespace properly.
  • Safety Checks: Added guards against incomplete files to prevent out-of-bounds access.

Extra Notes

  • You can verify your system's stack size with ulimit -s (Linux) — modifying this isn't a fix, since larger files will still overflow.
  • If you need to handle binary PNM (P6) files, you'll need to adjust the parsing logic to read raw bytes instead of ASCII values.
  • stoi is safer than atoi because it throws exceptions for invalid inputs—you could add try/catch blocks to handle malformed PNM files gracefully.

内容的提问来源于stack exchange,提问作者Augusto Dias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:12:27