#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 导致了某些具有相同名称的变量出现问题,但事实并非如此。
这段代码的“分割”部分有 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,为调用下一个函数做准备。不要试图在一个整体函数中完成所有事情。
(请注意:动态分配不会失败。)