I want the following code to accomplish to store the content of the file it reads in a variable
content
without leaking memory:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 len2 1);
memcpy(result, s1, len1);
memcpy(result len1, s2, len2 1);
return result;
}
int main() {
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path,"r");
char line[200];
char * content = "";
if (archivo == NULL)
exit(1);
else {
fseek(archivo, 0L, SEEK_END);
int sz = ftell(archivo);
fseek(archivo, 0L, SEEK_SET);
if (sz < pow(10, 7) ) {
printf("\nThe content of %s is:\n", path);
while (feof(archivo) == 0) {
fgets(line, 200, archivo); //reads one line at a time - comment out the while loop to find out
content = concat(content, line);
//free(content);//No leaks but no content either
}
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
fclose(archivo);
exit(0);
}
}
fclose(archivo);
puts(content);
free(content);
return 0;
}
much the same as this code that uses fread()
does it:
#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#include <sys/types.h>
int main() {
int count;
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path,"rb");
if (archivo == NULL) {
puts("Does not exist.");
exit(1);
}
else {
fseek(archivo, 0L, SEEK_END);
int sz = ftell(archivo);
char contenido[sz];
fseek(archivo, 0L, SEEK_SET);
if (sz < pow(10, 7) ) {
count = fread(&contenido, 10 * sizeof(char), sz, archivo);//reads 10 characters at a time.
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
}
fclose(archivo);
// Printing data to check validity
printf("Data read from file: %s \n", contenido);
printf("Elements read: %i, read %li byte at a time.\n", count, 10 * sizeof(char));
}
return 0;
}
The first code snippet leaks memory, as evidenced by valgrind:
...
total heap usage: 44 allocs, 4 frees, 23,614 bytes allocated
...
==404853== LEAK SUMMARY:
==404853== definitely lost: 17,198 bytes in 40 blocks
...
When I attempt to prevent such leak by executing free()
within the while loop I get no value stored in content
. How might I store the string read by fgets
without leaking memory?
CodePudding user response:
When you call concat
the second time, the value from the first call is overwritten by the malloc
call. That is the memory leak.
I presume that you want content
to be one long string that contains the data from all lines.
You want to use realloc
(vs. malloc
) in concat
and just append s2
to the enlarged s1
.
With this modified scheme, instead of char *content = "";
, you want: char *content = NULL;
Also, don't use feof
And, ftell
returns long
and not int
. And, it's better to not use pow
to compare against the limit.
Here is the refactored code (I've compiled it but not tested it):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
char *
concat(char *s1, const char *s2)
{
size_t len1;
size_t len2;
if (s1 != NULL)
len1 = strlen(s1);
else
len1 = 0;
len2 = strlen(s2);
s1 = realloc(s1,len1 len2 1);
if (s1 == NULL) {
perror("realloc");
exit(1);
}
memcpy(s1 len1, s2, len2 1);
return s1;
}
int
main(void)
{
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path, "r");
char line[200];
#if 0
char *content = "";
#else
char *content = NULL;
#endif
if (archivo == NULL)
exit(1);
fseek(archivo, 0L, SEEK_END);
long sz = ftell(archivo);
fseek(archivo, 0L, SEEK_SET);
if (sz < (10 * 1024 * 1024)) {
printf("\nThe content of %s is:\n", path);
while (fgets(line, sizeof(line), archivo) != NULL)
content = concat(content, line);
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
fclose(archivo);
exit(0);
}
fclose(archivo);
if (content != NULL)
puts(content);
free(content);
return 0;
}
CodePudding user response:
You knew what you needed to do but didnt do it right
content = concat(content, line);
//free(content);//No leaks but no content either
you need to keep the old content pointer so you can delete it after you create a new one
char *oldc = content;
content = concat(content, line);
free(oldc);