如何找到指针错误的根源

问题描述 投票:0回答:1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "splitter.h"

#define FOUR_K 4096

SplitResult split_join(int argc, char *argv[]) 
{
    SplitResult rs = E_NO_ACTION;

    if (argc < 7) 
    {
        return rs;
    }

    char* spiltOrJoin = argv[1];
    char* isSpiltOrJoin = spiltOrJoin;

    if (strcmp(isSpiltOrJoin, "-s") != 0 && strcmp(isSpiltOrJoin, "-j") != 0) 
    {
        return rs;
    }

    if (strcmp(isSpiltOrJoin, "-s") == 0) 
    {
        int smallChunkSize = atoi(argv[2]);

        const char* inputFileName = argv[6];
        const char* outputFilePrefix = argv[4];

        FILE* input = fopen(inputFileName, "rb");
        if (input != NULL) 
        {
            fseek(input, 0, SEEK_END);
            long fileSize = ftell(input);
            fseek(input, 0, SEEK_SET);

            int numChunks = (fileSize + smallChunkSize - 1) / smallChunkSize;

            char buffer[FOUR_K];

            int numOfPiecesOfChunk = smallChunkSize / sizeof(buffer);

            for (int i = 0; i < numChunks; i++) 
            {
                char outputFileName[256];
                snprintf(outputFileName, sizeof(outputFileName), "%s%s%d", outputFilePrefix, "000", i + 1);
                FILE* output = fopen(outputFileName, "wb");

                if (output == NULL)
                {
                    rs = E_BAD_DESTINATION;
                    fclose(input);
                    return rs;
                }

                char* chunkBuffer = (char*)malloc(FOUR_K);

                if (chunkBuffer == NULL)
                {
                    rs = E_NO_MEMORY;
                    fclose(input);
                    fclose(output);
                    return rs;
                }

                if (numOfPiecesOfChunk > 0)
                {
                    for (int j = 0; j < numOfPiecesOfChunk; j++)
                    {
                        size_t bytesRead = fread(chunkBuffer, 1, sizeof(buffer), input);
                        fwrite(chunkBuffer, 1, bytesRead, output);
                    }

                    int remainingBytesOfChunk = smallChunkSize - (sizeof(chunkBuffer) * numOfPiecesOfChunk);
                    size_t bytesRead = fread(chunkBuffer, 1, remainingBytesOfChunk, input);
                    fwrite(chunkBuffer, 1, bytesRead, output);
                }
                else
                {
                    size_t bytesRead = fread(chunkBuffer, 1, smallChunkSize, input);
                    fwrite(chunkBuffer, 1, bytesRead, output);
                }

                fclose(output); //Problem statement

                FILE* checkInput = fopen(outputFileName, "rb");

                if (checkInput == NULL)
                {
                    rs = E_BAD_DESTINATION;
                    free(chunkBuffer);
                    fclose(input);
                    return rs;
                }

                fseek(checkInput, 0, SEEK_END);
                long fileSize = ftell(checkInput);
                fseek(checkInput, 0, SEEK_SET);

                if (fileSize <= 0)
                {
                    rs = E_SMALL_SIZE;
                    free(chunkBuffer);
                    fclose(input);
                    fclose(checkInput);
                    return rs;
                }

                fclose(checkInput);

                free(chunkBuffer);
            }

            fclose(input);
            rs = E_SPLIT_SUCCESS;
        }
        else 
        {
            rs = E_BAD_SOURCE;
            return rs;
        }
    }
    else 
    {
        char* outputFile = argv[3];
        char* title = outputFile;
        int numOfFiles = argc - 5;
        FILE* output = fopen(title, "wb");

        if (output != NULL) 
        {
            for (int i = 0; i < numOfFiles; i++) 
            {
                FILE* chunkFile = fopen(argv[i + 5], "rb");

                if (chunkFile == NULL) 
                {
                    rs = E_BAD_SOURCE;
                    return rs;
                }

                fseek(chunkFile, 0, SEEK_END);
                long fileSize = ftell(chunkFile);
                int sizeOfFile = (int)fileSize;
                fseek(chunkFile, 0, SEEK_SET);

                int numOfFilePieces = 0;

                char* buffer = (char*)malloc(FOUR_K);

                if (buffer == NULL)
                {
                    rs = E_NO_MEMORY;
                    fclose(chunkFile);
                    fclose(output);
                    return rs;
                }

                if (sizeOfFile > sizeof(buffer)) 
                {
                    numOfFilePieces = sizeOfFile / sizeof(buffer);
                }

                if (chunkFile != NULL) {
                    if (numOfFilePieces > 0) 
                    {
                        for (int i = 0; i < numOfFilePieces; i++) 
                        {
                            size_t bytesRead = fread(buffer, 1, sizeof(buffer), chunkFile);
                            fwrite(buffer, 1, bytesRead, output);
                        }

                        int remainingBytesOfChunk = sizeOfFile - (sizeof(buffer) * numOfFilePieces);
                        size_t bytesRead = fread(buffer, 1, remainingBytesOfChunk, chunkFile);
                        fwrite(buffer, 1, bytesRead, output);
                    }
                    else 
                    {
                        size_t bytesRead = fread(buffer, 1, sizeOfFile, chunkFile);
                        fwrite(buffer, 1, bytesRead, output);
                    }

                    fclose(chunkFile);
                }

                free(buffer);
            }

            rs = E_JOIN_SUCCESS;

            fclose(output);
        }
        else if (output == NULL) 
        {
            rs = E_BAD_DESTINATION;
            return rs;
        }
    }

    return rs;
}

我正在尝试编写一个 C 程序,将文件分成较小的文件,然后将较小的文件合并为较大的文件。当我尝试运行该程序时,出现 munmap_chunk(): invalidpointer 错误,该错误导致了 fclose(output) 行(由问题语句指示)。为什么会出现这种情况?

起初我以为 malloc 导致了某些具有相同名称的变量出现问题,但事实并非如此。

c file pointers error-handling malloc
1个回答
0
投票

这段代码的“分割”部分有 100 行长(没有注释)。难怪存在一个看不见的错误(由@RetiredNinja 指出)。代码太多,变量太多!为什么

buffer[FOUR_K]
未使用,而另一个缓冲区 (
chunkBuffer
) 已从堆中分配?这没有任何意义。

下面是函数“split”部分未经测试的重写。当

cat
可以完成这项工作时,“加入”部分很愚蠢。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stat.h> // new
#include "splitter.h"

SplitResult splitOne( FILE *ifp, size_t smallChunkSize, int idx, char *prefix ) {
    FILE *ofp = NULL;
    size_t want = smallChunkSize; // size of each output file

    char ofn[256];
    snprintf( ofn, sizeof(ofn), "%s%06d", prefix, idx );
    if( ( ofp = fopen( ofn, "wb" ) ) == NULL ) // start a new file
        return E_BAD_DESTINATION;

    while( want ) { // while batch incomplete
        char buf[FOUR_K];

        // the minimum of buffer size or remaining in batch
        size_t maxToRead = min( sizeof buf, want );
        size_t got = fread( buf, 1, maxToRead, ifp );
        // Should test for unexpected EOF
        // N.B. Last read of source likely to be < expected.

        fwrite( buf, 1, got, ofp ); // obvious

        want -= got; // reduce count remaining for this batch
    }
    fclose( ofp );

    return E_SPLIT_SUCCESS;
}

SplitResult split( int argc, char *argv[] ) {
    int smallChunkSize = atoi(argv[2]);
    char *ifn = argv[6];
    char *prefix = argv[4];

    if ( ( ifp = fopen( ifn, "rb" ) ) == NULL)
        return E_BAD_SOURCE;

    // Correct way to get a file's byte count
    struct stat finfo;
    if( fstat( fileno( ifp ), &finfo ) != 0 ) {
        fclose( ifp );
        return E_BAD_SOURCE;
    }

    int i = 1; // for unique output filenames
    size_t remain = finfo.st_size; // remain in source file
    SplitResult rs = E_NO_ACTION; // a default initial value

    while( remain // while source file not exhausted
    && ( rs = splitOne( ifp, smallChunkSize, i++, prefix ) ) == E_SPLIT_SUCCESS ) // want a batch of this size
        remain -= smallChunkSize; // shrink remaining in source file

    fclose( ifp );

    return rs;
}

SplitResult split_join( int argc, char *argv[] ) {
    if (argc < 7)
        return E_NO_ACTION;

    if( strcmp( split_join, "-s" ) == 0 ) return split( argc, argv );

    if( strcmp( split_join, "-j" ) == 0 ) return join( argc, argv ); // not done

    return E_NO_ACTION;
}

调用堆栈中的每个函数都会执行其thing,为调用下一个函数做准备。不要试图在一个整体函数中完成所有事情。

(请注意:动态分配不会失败。)

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