仅当通过 C 程序 运行 较大的文本文件时,free() 无效
Invalid free() only when running larger text files through C program
我一直在从事一个项目,该项目将整个文件作为单个字符串并以各种方式对其进行操作,但是当 运行 文本文件大于约 500 个字符时,我一直陷入 valgrind 错误。部分代码供参考:
我的程序:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_LENGTH 20
#define MAX_WORDS 50
// REQUIRED PROTOTYPES
char * readFile (char * filename);
char * stretchMe (char * aStringToStretch);
int splitMe (char * aStringToSplit, char static2D [MAX_WORDS][MAX_LENGTH]);
int shrinkMe (char * aStringToShrink);
bool isItAPalindrome (char * aString);
void printSuffixes (char * aString, int whichWord, char * desiredSuffix);
// Custom Functions
int checkPunctuation(char x);
// Main
int main(int argc, char **argvs)
{
if(argc < 2)
{
puts("Wrong usage when executing");
exit(EXIT_FAILURE);
}
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
printf("Txt File: [%s]\n", argvs[1]);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
char *ioFileString;
ioFileString = readFile(argvs[1]);
printf("%s", ioFileString);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
/*
char *stretchedIoFileString;
stretchedIoFileString = stretchMe(ioFileString);
printf("%s", stretchedIoFileString);
free(stretchedIoFileString);
*/
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
char static2D [MAX_WORDS][MAX_LENGTH];
int wordsCounted = splitMe(ioFileString, static2D);
printf("Word Count :[%d]", wordsCounted);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
free(ioFileString);
return EXIT_SUCCESS;
}
char * readFile (char * filename)
{
FILE *fp = NULL; // Initialize file pointer
fp = fopen(filename, "r"); // Open file
if(fp == NULL) // Check if file was found
{
printf("Error: Could not find file %s, please try again", filename);
exit(-1); // Error
}
// First count number of characters in file
fseek(fp, 0, SEEK_END); // Seek to end of file
int cCount = ftell(fp); // Counts amount of characters in file, add one for endline.
fseek(fp, 0, SEEK_SET); // Seek back to the beginning of the file
char *buffer = calloc((cCount+1), sizeof(char));
if(buffer == NULL)
{
puts("Malloc Failed, exiting");
exit(EXIT_FAILURE);
}
int numRead = fread(buffer, sizeof(char), cCount, fp);
buffer[cCount] = '[=11=]';
if(numRead != cCount)
{
puts("Did not read correctly, exiting.");
exit(EXIT_FAILURE);
}
fclose(fp);
return buffer;
}
char * stretchMe (char * aStringToStretch)
{
const int stringLength = strlen(aStringToStretch);
int *userInput = calloc(stringLength, sizeof(int));
int newStringLength = 0;
printf("Please enter %d integers sequentially:\n", stringLength);
int inUser;
for (int i = 0; i < stringLength; i++)
{
//scanf("%d", &inUser);
inUser = 2;
userInput[i] = inUser;
if(userInput[i] < 1)
{
printf("\nInvalid value: values must be positive\n");
i--;
}
else
{
newStringLength = newStringLength + userInput[i];
}
}
char *stretchedString = malloc(sizeof(char)*(newStringLength + 1));
int index = 0;
for (int i = 0; i < stringLength; i++)
{
for(int j = 0; j < userInput[i]; j++)
{
stretchedString[index] = aStringToStretch[i];
index++;
}
}
stretchedString[index] = '[=11=]';
free(userInput);
return stretchedString;
}
int splitMe (char * aStringToSplit, char static2D [MAX_WORDS][MAX_LENGTH])
{
const int stringLength = strlen(aStringToSplit);
const char delim[] = " \n";
char *buffer = calloc(stringLength+1, sizeof(char)); // Alloc memory for buffer for strtok();
strcpy(buffer, aStringToSplit); // Copy string to buffer
char *token;
token = strtok(buffer, delim);
int wordCount = 0;
while(token != NULL)
{
puts("Loops");
printf("%d", wordCount);
strcpy(static2D[wordCount], buffer);
wordCount++;
token = strtok(NULL, delim);
}
free(buffer);
return wordCount;
}
/*int shrinkMe (char * aStringToShrink)
{
int puncCount = 0;
int tempIndex = 0;
int stringLength = strlen(aStringToShrink);
char *tempShrinked = malloc(sizeof(char)*stringLength);
for(int i = 0; aStringToShrink[i] != '[=11=]'; i++)
{
if(checkPunctuation(aStringToShrink[i]) == 1)
{
puncCount++;
}
else
{
tempShrinked[tempIndex] = aStringToShrink[i];
tempIndex++;
}
}
tempShrinked[tempIndex] = '[=11=]';
strcpy(aStringToShrink, tempShrinked);
printf("%s", tempShrinked);
printf("%s", aStringToShrink);
return puncCount;
}
bool isItAPalindrome (char * aString)
{
return true;
}
void printSuffixes (char * aString, int whichWord, char * desiredSuffix)
{
}*/
int checkPunctuation(char x)
{
switch (x)
{
case '.':
case ':':
case ';':
case '?':
case '!':
return 1; // If any of the above cases are found, the case flows down the line to the last
break;
default:
return 0;
break;
}
}
我自己调用 readFile();
时没有出错,它分配和释放都很好。只有当文件比较大,调用函数splitMe();
时,Valgrind报2个错误:
==19545== Invalid free() / delete / delete[] / realloc()
==19545== at 0x48369AB: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x109335: main (main.c:35)
==19545== Address 0x65685404a26730 is not stack'd, malloc'd or (recently) free'd
==19545==
==19545==
==19545== HEAP SUMMARY:
==19545== in use at exit: 733 bytes in 1 blocks
==19545== total heap usage: 7 allocs, 7 frees, 15,627 bytes allocated
==19545==
==19545== Searching for pointers to 1 not-freed blocks
==19545== Checked 67,600 bytes
==19545==
==19545== 733 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19545== at 0x4837B65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x1093E0: readFile (functions.c:24)
==19545== by 0x10928B: main (main.c:17)
==19545==
==19545== LEAK SUMMARY:
==19545== definitely lost: 733 bytes in 1 blocks
==19545== indirectly lost: 0 bytes in 0 blocks
==19545== possibly lost: 0 bytes in 0 blocks
==19545== still reachable: 0 bytes in 0 blocks
==19545== suppressed: 0 bytes in 0 blocks
==19545==
==19545== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==19545==
==19545== 1 errors in context 1 of 2:
==19545== Invalid free() / delete / delete[] / realloc()
==19545== at 0x48369AB: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x109335: main (main.c:35)
==19545== Address 0x65685404a26730 is not stack'd, malloc'd or (recently) free'd
==19545==
==19545== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
(733字节是readFile中第一个calloc分配的space)
我假设它可能与 readFile 中的 calloc();
和 splitMe 中的 strcpy();
的组合有关?任何帮助表示赞赏。谢谢。
首先,您假设可以将整个文件装入内存。但是不要检查它是否有效
// First count number of characters in file
fseek(fp, 0, SEEK_END); // Seek to end of file
int cCount = ftell(fp); // Counts amount of characters in file, add one for endline.
fseek(fp, 0, SEEK_SET); // Seek back to the beginning of the file
char* buffer = calloc((cCount + 1), sizeof(char));
int numRead = fread(buffer, sizeof(char), cCount, fp);
你必须检查来自 calloc
的 return
然后在 splitME 开始时,即使它有效,您也将整个文件复制到另一个堆分配,而无需测试它是否有效。
const int stringLength = strlen(aStringToSplit);
const char delim[] = " \n";
char* buffer = calloc(stringLength + 1, sizeof(char)); // Alloc memory for buffer for strtok(); <<<<=== check this retunrn
strcpy(buffer, aStringToSplit); // Copy string to buffer
所以您正试图在内存中同时保存文件的 2 个副本
对于 500 字节的文件,这可能没问题,但这是非常糟糕的代码
你失败的真正原因是你没有检查是否有 > MAX_WORDS 或一个词是否大于 MAX_LENGTH
另请注意,您的程序无法在 windows 上运行。您发现文件的长度包括行尾的所有 CRLF,但是以文本模式打开文件,fread 将删除 LF,因此您测试是否读取了正确数量的字符将失败
我一直在从事一个项目,该项目将整个文件作为单个字符串并以各种方式对其进行操作,但是当 运行 文本文件大于约 500 个字符时,我一直陷入 valgrind 错误。部分代码供参考:
我的程序:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_LENGTH 20
#define MAX_WORDS 50
// REQUIRED PROTOTYPES
char * readFile (char * filename);
char * stretchMe (char * aStringToStretch);
int splitMe (char * aStringToSplit, char static2D [MAX_WORDS][MAX_LENGTH]);
int shrinkMe (char * aStringToShrink);
bool isItAPalindrome (char * aString);
void printSuffixes (char * aString, int whichWord, char * desiredSuffix);
// Custom Functions
int checkPunctuation(char x);
// Main
int main(int argc, char **argvs)
{
if(argc < 2)
{
puts("Wrong usage when executing");
exit(EXIT_FAILURE);
}
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
printf("Txt File: [%s]\n", argvs[1]);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
char *ioFileString;
ioFileString = readFile(argvs[1]);
printf("%s", ioFileString);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
/*
char *stretchedIoFileString;
stretchedIoFileString = stretchMe(ioFileString);
printf("%s", stretchedIoFileString);
free(stretchedIoFileString);
*/
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
char static2D [MAX_WORDS][MAX_LENGTH];
int wordsCounted = splitMe(ioFileString, static2D);
printf("Word Count :[%d]", wordsCounted);
puts("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
free(ioFileString);
return EXIT_SUCCESS;
}
char * readFile (char * filename)
{
FILE *fp = NULL; // Initialize file pointer
fp = fopen(filename, "r"); // Open file
if(fp == NULL) // Check if file was found
{
printf("Error: Could not find file %s, please try again", filename);
exit(-1); // Error
}
// First count number of characters in file
fseek(fp, 0, SEEK_END); // Seek to end of file
int cCount = ftell(fp); // Counts amount of characters in file, add one for endline.
fseek(fp, 0, SEEK_SET); // Seek back to the beginning of the file
char *buffer = calloc((cCount+1), sizeof(char));
if(buffer == NULL)
{
puts("Malloc Failed, exiting");
exit(EXIT_FAILURE);
}
int numRead = fread(buffer, sizeof(char), cCount, fp);
buffer[cCount] = '[=11=]';
if(numRead != cCount)
{
puts("Did not read correctly, exiting.");
exit(EXIT_FAILURE);
}
fclose(fp);
return buffer;
}
char * stretchMe (char * aStringToStretch)
{
const int stringLength = strlen(aStringToStretch);
int *userInput = calloc(stringLength, sizeof(int));
int newStringLength = 0;
printf("Please enter %d integers sequentially:\n", stringLength);
int inUser;
for (int i = 0; i < stringLength; i++)
{
//scanf("%d", &inUser);
inUser = 2;
userInput[i] = inUser;
if(userInput[i] < 1)
{
printf("\nInvalid value: values must be positive\n");
i--;
}
else
{
newStringLength = newStringLength + userInput[i];
}
}
char *stretchedString = malloc(sizeof(char)*(newStringLength + 1));
int index = 0;
for (int i = 0; i < stringLength; i++)
{
for(int j = 0; j < userInput[i]; j++)
{
stretchedString[index] = aStringToStretch[i];
index++;
}
}
stretchedString[index] = '[=11=]';
free(userInput);
return stretchedString;
}
int splitMe (char * aStringToSplit, char static2D [MAX_WORDS][MAX_LENGTH])
{
const int stringLength = strlen(aStringToSplit);
const char delim[] = " \n";
char *buffer = calloc(stringLength+1, sizeof(char)); // Alloc memory for buffer for strtok();
strcpy(buffer, aStringToSplit); // Copy string to buffer
char *token;
token = strtok(buffer, delim);
int wordCount = 0;
while(token != NULL)
{
puts("Loops");
printf("%d", wordCount);
strcpy(static2D[wordCount], buffer);
wordCount++;
token = strtok(NULL, delim);
}
free(buffer);
return wordCount;
}
/*int shrinkMe (char * aStringToShrink)
{
int puncCount = 0;
int tempIndex = 0;
int stringLength = strlen(aStringToShrink);
char *tempShrinked = malloc(sizeof(char)*stringLength);
for(int i = 0; aStringToShrink[i] != '[=11=]'; i++)
{
if(checkPunctuation(aStringToShrink[i]) == 1)
{
puncCount++;
}
else
{
tempShrinked[tempIndex] = aStringToShrink[i];
tempIndex++;
}
}
tempShrinked[tempIndex] = '[=11=]';
strcpy(aStringToShrink, tempShrinked);
printf("%s", tempShrinked);
printf("%s", aStringToShrink);
return puncCount;
}
bool isItAPalindrome (char * aString)
{
return true;
}
void printSuffixes (char * aString, int whichWord, char * desiredSuffix)
{
}*/
int checkPunctuation(char x)
{
switch (x)
{
case '.':
case ':':
case ';':
case '?':
case '!':
return 1; // If any of the above cases are found, the case flows down the line to the last
break;
default:
return 0;
break;
}
}
我自己调用 readFile();
时没有出错,它分配和释放都很好。只有当文件比较大,调用函数splitMe();
时,Valgrind报2个错误:
==19545== Invalid free() / delete / delete[] / realloc()
==19545== at 0x48369AB: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x109335: main (main.c:35)
==19545== Address 0x65685404a26730 is not stack'd, malloc'd or (recently) free'd
==19545==
==19545==
==19545== HEAP SUMMARY:
==19545== in use at exit: 733 bytes in 1 blocks
==19545== total heap usage: 7 allocs, 7 frees, 15,627 bytes allocated
==19545==
==19545== Searching for pointers to 1 not-freed blocks
==19545== Checked 67,600 bytes
==19545==
==19545== 733 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19545== at 0x4837B65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x1093E0: readFile (functions.c:24)
==19545== by 0x10928B: main (main.c:17)
==19545==
==19545== LEAK SUMMARY:
==19545== definitely lost: 733 bytes in 1 blocks
==19545== indirectly lost: 0 bytes in 0 blocks
==19545== possibly lost: 0 bytes in 0 blocks
==19545== still reachable: 0 bytes in 0 blocks
==19545== suppressed: 0 bytes in 0 blocks
==19545==
==19545== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==19545==
==19545== 1 errors in context 1 of 2:
==19545== Invalid free() / delete / delete[] / realloc()
==19545== at 0x48369AB: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19545== by 0x109335: main (main.c:35)
==19545== Address 0x65685404a26730 is not stack'd, malloc'd or (recently) free'd
==19545==
==19545== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
(733字节是readFile中第一个calloc分配的space)
我假设它可能与 readFile 中的 calloc();
和 splitMe 中的 strcpy();
的组合有关?任何帮助表示赞赏。谢谢。
首先,您假设可以将整个文件装入内存。但是不要检查它是否有效
// First count number of characters in file
fseek(fp, 0, SEEK_END); // Seek to end of file
int cCount = ftell(fp); // Counts amount of characters in file, add one for endline.
fseek(fp, 0, SEEK_SET); // Seek back to the beginning of the file
char* buffer = calloc((cCount + 1), sizeof(char));
int numRead = fread(buffer, sizeof(char), cCount, fp);
你必须检查来自 calloc
的 return然后在 splitME 开始时,即使它有效,您也将整个文件复制到另一个堆分配,而无需测试它是否有效。
const int stringLength = strlen(aStringToSplit);
const char delim[] = " \n";
char* buffer = calloc(stringLength + 1, sizeof(char)); // Alloc memory for buffer for strtok(); <<<<=== check this retunrn
strcpy(buffer, aStringToSplit); // Copy string to buffer
所以您正试图在内存中同时保存文件的 2 个副本
对于 500 字节的文件,这可能没问题,但这是非常糟糕的代码
你失败的真正原因是你没有检查是否有 > MAX_WORDS 或一个词是否大于 MAX_LENGTH
另请注意,您的程序无法在 windows 上运行。您发现文件的长度包括行尾的所有 CRLF,但是以文本模式打开文件,fread 将删除 LF,因此您测试是否读取了正确数量的字符将失败