仅当通过 C 程序运行较大的文本文件时,free() 无效
我一直在开发一个项目,该项目将整个文件作为单个字符串并以各种方式操作它们,但是当运行大于大约 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] = '\0';
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] = '\0';
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] != '\0'; i++)
{
if(checkPunctuation(aStringToShrink[i]) == 1)
{
puncCount++;
}
else
{
tempShrinked[tempIndex] = aStringToShrink[i];
tempIndex++;
}
}
tempShrinked[tempIndex] = '\0';
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 分配的空间)< /em>
我假设它可能与 readFile 中的 calloc(); 和 splitMe 中的 strcpy(); 的组合有关?任何帮助表示赞赏。谢谢。
Ive been working on a project which takes whole files as single strings and manipulates them in various ways, but keep getting stuck on a valgrind error when running text files bigger than around ~500 characters. Some code for reference:
My Program:
#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] = '\0';
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] = '\0';
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] != '\0'; i++)
{
if(checkPunctuation(aStringToShrink[i]) == 1)
{
puncCount++;
}
else
{
tempShrinked[tempIndex] = aStringToShrink[i];
tempIndex++;
}
}
tempShrinked[tempIndex] = '\0';
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;
}
}
I get no errors when calling readFile();
by itself, it allocates and frees fine. It is only when it is a larger file and the function splitMe();
is called, Valgrind reports 2 errors:
==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)
(The 733 bytes is the space allocated by that first calloc in readFile)
Im assuming maybe it has something to do with a combination of the calloc();
in readFile and the strcpy();
in splitMe? Any help is appreciated. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,您做出了一个巨大的假设:您可以将整个文件放入内存中。但不要检查它是否有效。
您必须
在 splitME 开始时检查 calloc 的返回,即使该返回有效,您也可以将整个文件复制到另一个堆分配,而无需测试它是否有效。
所以你试图在内存中同时保存文件的 2 个副本
对于 500 字节的文件,这可能没问题,但这是非常糟糕的代码
你失败的实际原因是因为你没有检查是否有 > ;如果单词大于 MAX_LENGTH,则为 MAX_WORDS
另请注意,您的程序无法在 Windows 上运行。您可以找到文件的长度,包括行尾的所有 CRLF,但是以文本模式打开文件,fread 会删除 LF,因此您的测试是否读取正确的字符数将失败
Well for a start you make the huge assumption that you can fit the entire file into memory. But dont check that it worked
You have to check the return from calloc
then at the start of splitME even if that one worked you copy the entire file to another heap allocation with no test if it worked.
so you are attempting to hold 2 copies of the file in memory at once
With a 500 byte file this is probably OK, but this is very poor code
The actual reason you are failing is because you don't check to see if you have > MAX_WORDS of if a word is larger than MAX_LENGTH
Also note that you program won't work on windows. You find the length of the file including all the CRLFs at the end of the line, but open the file in text mode, fread will drop the LFs so your test to see if you read the correct number of chars will fail