I have a program that is supposed to receive input, remember the longest string and print it out at EOF. My code works, but when run through a debugger there is a memory leak detected. I am compiling in Windows and do not have a proper debugger like Valgrind so I do not get much information about the error. The only thing I can imagine can cause this leak is the realloc() or free() function. However, I am not skilled enough in C to understand what the problem is.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p;
char *line;
int sc;
p = (char*) malloc ( sizeof(char) );
line = (char*) malloc ( sizeof(char) );
int count = 0;
int max = 0;
p[count] = 0;
while ( ( sc = getchar()) != EOF ) {
if ( p == NULL ) {
p = (char*) realloc ( p, sizeof(char) );
}
if ( isalpha(sc) ) {
p[count] = sc;
count++;
p = (char*) realloc( p, (count+1)*sizeof(char) );
p[count] = 0;
} else if ( sc == '\n' || sc == ' ' ) {
if ( count > max ) {
line = (char*) realloc( line, (count+1)*sizeof(char) );
strcpy( line, p );
max = count;
} else if ( count == 0) {
printf("%d characters in longest word: %s\n", max, line);
free(line);
free(p);
break;
}
count = 0;
}
}
return 0;
}
You state in the comments that you "have tried moving both free() to the end of the program", but I don't believe you. The problem appears to be that this is a badly designed program which does not always reach the free() statements because when sc is a space or newline, count is unlikely to be 0, and after count is reset to 0, the next character is read into sc (unlikely to be a space or newline).
Simply moving the calls to free() to the end of the program fixes the memory leak, which was reported by Valgrind:
λ> valgrind --tool=memcheck ./a.out
==2967== Memcheck, a memory error detector
==2967== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2967== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2967== Command: ./a.out
==2967==
this is a test
==2967==
==2967== HEAP SUMMARY:
==2967== in use at exit: 10 bytes in 2 blocks
==2967== total heap usage: 14 allocs, 12 frees, 42 bytes allocated
==2967==
==2967== LEAK SUMMARY:
==2967== definitely lost: 10 bytes in 2 blocks
==2967== indirectly lost: 0 bytes in 0 blocks
==2967== possibly lost: 0 bytes in 0 blocks
==2967== still reachable: 0 bytes in 0 blocks
==2967== suppressed: 0 bytes in 0 blocks
==2967== Rerun with --leak-check=full to see details of leaked memory
==2967==
==2967== For counts of detected and suppressed errors, rerun with: -v
==2967== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
But there are many other issues with the code. First, never store the result of a call to realloc() in the only copy of a pointer you have to the memory being reallocated; a null pointer may be returned, and if so you then have a memory leak and lost data. Instead, use a temporary variable to hold the result, and assign this value to the original pointer only after checking for a null pointer. If a null pointer has been returned, the simplest solution is probably to terminate the program with an error message, as is done below; the error could be handled in other ways, so long as it is handled.
The posted code is more complex than it needs to be, with multiple calls to malloc() and realloc(). Instead, initialize p and line to NULL, and reallocate only as needed. There is no need to begin by allocating space for 1 char; this can be done when the first character needs to be stored. Also, there is no need to cast the result of malloc() in C (a different story in C++); and, sizeof char is always 1, so this is redundant and only clutters the code.
The fundamental problem in the posted code seems to be that when a character is read, count is incremented. Then if this character is a space or a newline, count may not be 0, so the exit with deallocation condition may not be met. Instead of complicated conditions, rethink the flow of the program.
After reading a character (unless EOF is encountered), if that character is alphabetic, count should be incremented, and p should be reallocated. If this step is successful, the character should be stored in p[], which should then be null-terminated.
Otherwise, if the character is a \n or a space, max should be compared with count. If count is larger, then line should be reallocated. If this step is successful, the string pointed to by p should be copied to line[]. Then max is given the value of count, and count is reset to 0.
After the loop has terminated, the results are printed only if there were words in the input. Then deallocation can occur before the program terminates.
The isalpha() function and similar functions from ctype.h expect an int value in the range of an unsigned char (or EOF). Often you need to cast the value of arguments to these functions to unsigned char to avoid undefined behavior. But, in this case the cast is unnecessary since getchar() returns an int value in the range of an unsigned char (or EOF).
You might also consider using the isspace() function instead of sc == '\n' || sc == ' '. This would allow other whitespace characters, such as '\t', to separate words in the input. As written in the OP, an input of "one\tword" (where '\t' is a tab character) would result in an output of:
7 characters in longest word: oneword
Here is a modified version of the posted code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p = NULL;
char *line = NULL;
int sc;
int count = 0;
int max = 0;
while ((sc = getchar()) != EOF) {
if (isalpha(sc)) {
++count; // read a letter
char *temp = realloc(p, count + 1); // +1 for '\0'
if (temp == NULL) { // check allocation
perror("Failure to reallocate p");
exit(EXIT_FAILURE);
}
p = temp; // OK to reassign p
p[count-1] = sc; // store character
p[count] = 0; // add null-terminator
} else if (isspace(sc)) {
if (count > max) {
char *temp = realloc(line, count + 1); // +1 for '\0'
if (temp == NULL) { // check allocation
perror("Failure to reallocate line");
exit(EXIT_FAILURE);
}
line = temp; // OK to reassign line
strcpy(line, p);
max = count;
}
count = 0;
}
}
if (max > 0) {
printf("%d characters in longest word: %s\n", max, line);
} else {
puts("No words in input");
}
free(line);
free(p);
return 0;
}
And here is a clean bill of health from Valgrind:
λ> valgrind --tool=memcheck ./a.out
==4753== Memcheck, a memory error detector
==4753== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4753== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4753== Command: ./a.out
==4753==
this is a testrun
7 characters in longest word: testrun
==4753==
==4753== HEAP SUMMARY:
==4753== in use at exit: 0 bytes in 0 blocks
==4753== total heap usage: 16 allocs, 16 frees, 69 bytes allocated
==4753==
==4753== All heap blocks were freed -- no leaks are possible
==4753==
==4753== For counts of detected and suppressed errors, rerun with: -v
==4753== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I think during debugging after the free() function call; you checked the value of the pointer p and line, and you still see the value(string) it is pointing to. If so that is not memory leak because free() does not change the value of pointer or assign 0 or '\0' character in it. free() just free the block of memory so that next time when you call any memory allocation function it will get that memory as available memory, and allocate it. Therefore after calling free(), we always assign NULL to the pointer like p = NULL;.
Correct the code as below and try:-
free(line);
free(p);
line = NULL;
p = NULL;
break;
Based on your coding approach I'll use calloc (you need) instead of malloc to get rid of that:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p = NULL;
char *line = NULL;
int sc;
p = calloc ( sizeof(char), 1);
line = calloc ( sizeof(char),1 );
size_t count = 0;
size_t max = 0;
p[count] = 0;
while ( ( sc = getchar()) != EOF ) {
if ( p == NULL ) {
p = realloc ( p, sizeof(char) );
}
if ( isalpha(sc) ) {
p[count] = (char)sc;
count++;
p = realloc( p, (count+1) * sizeof(char) );
p[count] = 0;
} else if ( sc == '\n' || sc == ' ' ) {
if ( count > max ) {
line = realloc( line, (count+1)*sizeof(char) );
strcpy( line, p );
max = count;
} else if ( count == 0) {
printf("%zu characters in longest word: %s\n", max, line);
free(line);
free(p);
break;
}
count = 0;
}
}
return 0;
}
Output with Valgrind:
==4362== Memcheck, a memory error detector
==4362== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4362== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4362== Command: ./program
==4362==
Hello World
5 characters in longest word: Hello
==4362==
==4362== HEAP SUMMARY:
==4362== in use at exit: 0 bytes in 0 blocks
==4362== total heap usage: 15 allocs, 15 frees, 2,096 bytes allocated
==4362==
==4362== All heap blocks were freed -- no leaks are possible
==4362==
==4362== For counts of detected and suppressed errors, rerun with: -v
==4362== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Now try to understand, why is not working with malloc and why is working with calloc.
EDIT
Are you sure that is all about a leak? and is not about an uninitialised value?
I'm saying because if you type a letter works fine, the problem comes with Numbers, hence the calloc sugestion.
This is the Output of Valgrind using your code with no modification:
==5042== Memcheck, a memory error detector
==5042== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5042== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==5042== Command: ./program
==5042==
1
==5042== Conditional jump or move depends on uninitialised value(s)
==5042== at 0x4E88CC0: vfprintf (vfprintf.c:1632)
==5042== by 0x4E8F898: printf (printf.c:33)
==5042== by 0x40082B: main (in /home/michael/program)
==5042== Uninitialised value was created by a heap allocation
==5042== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5042== by 0x400715: main (in /home/michael/program)
==5042==
0 characters in longest word:
==5042==
==5042== HEAP SUMMARY:
==5042== in use at exit: 0 bytes in 0 blocks
==5042== total heap usage: 4 allocs, 4 frees, 2,050 bytes allocated
==5042==
==5042== All heap blocks were freed -- no leaks are possible
==5042==
==5042== For counts of detected and suppressed errors, rerun with: -v
==5042== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Related
So i have this uni assignment for which i have to count votes coming from the input and sort them by the max amount(alphabetical if the number is equal). The uni server is running tests on it, putting different names/numbers in there, and i got some points already, but I'm having an issue with a certain input. This is the error I'm getting:
==30190== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==30190== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==30190== Command: ./run
==30190==
==30190== Invalid write of size 1
==30190== at 0x1092AA: main (program.c:23)
==30190== Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==30190==
==30190==
==30190== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==30190== Access not within mapped region at address 0x1FFF001000
==30190== at 0x1092AA: main (program.c:23)
==30190== If you believe this happened as a result of a stack
==30190== overflow in your program's main thread (unlikely but
==30190== possible), you can try to increase the size of the
==30190== main thread stack using the --main-stacksize= flag.
==30190== The main thread stack size used in this run was 8388608.
==30190==
==30190== HEAP SUMMARY:
==30190== in use at exit: 0 bytes in 0 blocks
==30190== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==30190==
==30190== All heap blocks were freed -- no leaks are possible
==30190==
==30190== For counts of detected and suppressed errors, rerun with: -v
==30190== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
//Declaration
char s[20][50],st[50],sabc[20][50];
int i,j,k,l,num[20],e[20][20],suc[20],end[20],ooo;
for(i=0;i<20;i++){
memset(s[i],'\0',50);
suc[i]=0;
for(j=0;j<20;j++){
e[i][j]=-1;
}
}
//Reading the input and putting it into the s array
gets(st);
i=0;
while(st[0]!='\0'){
for(j=0;j<=strlen(st);j++){
s[i][j]=st[j];
}
gets(st);
i++;
}
//The the individual strings are converted into just numbers and put into the num array
for(i=0;i<20;i++){
num[i]=atoi(s[i]);
}
//The opposite, converting the strings into just characters, so only the names are left into the sabc array
for(i=0;i<20;i++){
k=0;
for(j=0;j<50;j++){
if(s[i][j]<48 || s[i][j]>57){
sabc[i][k]=s[i][j];
k++;
}
}
}
//The e array, is here for letting me know at which positions are the strings with the same names.
for(i=0;i<20;i++){
for(j=0;j<20;j++){
l=0;
for(k=4;k<10;k++){
if(s[i][k]==s[j][k]){
l++;
}
}
if(l>5){
e[i][j]=j;
}
}
}
//Here I'm using the previously created e array to count the number of votes together, the suc array is the number of votes counted together
for(i=0;i<20;i++){
for(j=0;j<20;j++){
if(e[i][j]>=0){
suc[i]=suc[i]+num[j];
}
}
}
//Now the previous loop created duplicates, so im using this loop to remove them
for(i=0;i<20;i++){
if(sabc[i][0]=='\0')
continue;
for(j=0;j<20;j++){
if(i==j)
continue;
l=0;
for(k=4;k<10;k++){
if(sabc[i][k]==sabc[j][k]){
l++;
}
}
if(l>5){
memset(sabc[j],'\0',50);
if(suc[i]<suc[j])
suc[i]=suc[j];
}
}
end[i]=suc[i];
}
//And this is the last part, sorting them by number of votes, and alphabeticaly if necessary
memset(st,'\0',50);
for(i=0;i<20;i++){
for(j=0;j<20;j++){
if(end[j]=='\0')
break;
if(end[j]<end[j+1]){
for(k=0;k<50;k++){
st[k]=sabc[j][k];
sabc[j][k]=sabc[j+1][k];
sabc[j+1][k]=st[k];
}
ooo=end[j];
end[j]=end[j+1];
end[j+1]=ooo;
}
if(end[j]==end[j+1]){
if(strcmp(sabc[j],sabc[j+1])>0){
for(k=0;k<50;k++){
st[k]=sabc[j][k];
sabc[j][k]=sabc[j+1][k];
sabc[j+1][k]=st[k];
}
}
}
}
}
//Writing the output
printf("Vysledky:\n");
for(i=0;i<20;i++){
if(sabc[i][0]=='\0')
continue;
printf("%d",end[i]);
puts(sabc[i]);
}
return 0;
}
I know its probably not really optimized, but its what i came up with.
This part of the code just reads the string and puts it into a 2d array.
Also I'm using a program called Putty connected to the uni's server, and it works fine in there, but for some reason it doesn't work on the uni site.
The input I'm having trouble with is:
4 Myne Lajad
5 Draxton Vorgthar
4 Needira Thontwi
4 Oyaka Wrathpry
5 Thrad Zex'lek
Expected output:
5 Draxton Vorgthar
5 Thrad Zex'lek
4 Myne Lajad
4 Needira Thontwi
4 Oyaka Wrathpry
The input can also contain the same names multiple times, but i have that covered. I can also provide the whole code if necessary.
Hello I wrote this function in C that takes a string of words and returns a two dimensional char array with each case initialized to a word in the right order, I compiled and it did the assigned task
char **decompose_string(char *string)
{
int i,j=0;
char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*)); //string_words_number return the number of words in string string
for(i=0;i<string_words_number(string);i++)
{
temp=NULL;
int l=0;
while(string[j]!=' ' && *string)
{
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]=string[j];
j++;l++;
}
j++;
temp[l]='\0';
tab_mots=realloc(words_array,(string_words_number(string)+1)*sizeof(char)*(j-1));
words_array[i]=temp;
}
words_array[i]=NULL;
return words_array;}
And my main:
int main()
{
char* string1= "word1 and word2 and word3";
printf("Our initial string: %s\n",string1);
char** words_array1;
printf("After decomposition:\n");
words_array1=decompose_string(string1);
display_words_array(words_array1); //displays each element of the array in a line
words_array1=destroy_array(words_array1);
return 0;}
But as I executed the valgrind command to see weither there are any memory leaks this was the result:
==4648== Memcheck, a memory error detector
==4648== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4648== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4648== Command: ./test_csvl
==4648==
Our initial array: word1 and word2 and word3
After decomposition:
==4648== Invalid write of size 1
==4648== at 0x4009D9: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==
==4648== Invalid read of size 1
==4648== at 0x4C30F74: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x4EA969B: puts (ioputs.c:35)
==4648== by 0x400888: display_words_array (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40079F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==
word1
and
word2
and
word3
==4648==
==4648== HEAP SUMMARY:
==4648== in use at exit: 8 bytes in 1 blocks
==4648== total heap usage: 30 allocs, 29 frees, 1,545 bytes allocated
==4648==
==4648== LEAK SUMMARY:
==4648== definitely lost: 8 bytes in 1 blocks
==4648== indirectly lost: 0 bytes in 0 blocks
==4648== possibly lost: 0 bytes in 0 blocks
==4648== still reachable: 0 bytes in 0 blocks
==4648== suppressed: 0 bytes in 0 blocks
==4648== Rerun with --leak-check=full to see details of leaked memory
==4648==
==4648== For counts of detected and suppressed errors, rerun with: -v
==4648== ERROR SUMMARY: 9 errors from 2 contexts (suppressed: 0 from 0)
I know that the missing free is the one for temp in the function but if I do free it I'll end up losing its value which I need for my array. So my question would be can I free it without losing its value ? or any other solution to guarantee both the functionality of my function and the erase of any memory leaks. Thank you for your time.
Sorry I forgot here's the function I used to free the allocated space:
char **destroy_words_array( char** words_array)
{
int i;
for(i=0;i<count_words(words_array);i++) free(words_array[i]); //wount_words return the number of elements of the array
free(words_array);
return words_array;
}
The memory leak isn't where you think it is. It happens at the start of your function:
char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*));
for(i=0;i<string_words_number(string);i++)
{
temp=NULL;
You allocate space for a pointer to temp, but then you overwrite that pointer when you enter the for loop. Remove that malloc call and the leak goes away.
You have a bigger problem however, and that is reading and writing past the end of an allocated buffer. That's happening here:
temp=NULL;
int l=0;
while(string[j]!=' ' && *string)
{
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]=string[j];
j++;l++;
}
j++;
temp[l]='\0';
Suppose the string in question has two characters to read. On the first iteration of your loop, l is 0, so you allocate l+1 == 1 bytes to temp. You then write to temp[l] == temp[0], which is fine, then you increment l to 1. On the next iteration, you allocate l+1 == 2 bytes for temp, write to temp[l] == temp[1], and increment l to 2. Still good so far.
The problem is when you do temp[l]='\0'; outside of the loop. l is now 2, and the size of the allocated memory is 2, so you're writing one element past the end of the array.
You need to allocate one more byte here:
j++;
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]='\0';
Note also that you should be checking the return value of malloc and realloc throughout your code in case it fails.
Also, you're not correctly checking for the end of string. You need to do:
while(string[j]!=' ' && string[j]!=0)
Before the for-loop you have
char* temp=malloc(sizeof(char*));
but the first thing inside the for-loop is
temp=NULL;
So the memory that temp pointed to is lost. If you run this program on a 64 bit computer, you will see a memory leak of size 8. Remove the first declaration of temp and change the first line in the for-loop to
char* temp = NULL;
Another problem is the condition of the inner while-loop:
while(chaine[j]!=' ' && *chaine)
as you don't advance the chaine pointer, the value of *chaine will not change. You probably meant to write chaine[j] here:
while(chaine[j]!=' ' && chaine[j])
which is equivalent to
while(chaine[j]!=' ' && chaine[j]!='\0')
I wrote a simple code that reads a very large file into memory. (The file is around 480 mega bytes in size). The file contains some comma separated values of 0s and 1s. The code is fairly straight forward. I first get the file size, then allocate enough buffer space, read the file, separate by comma and just put it in the array. The program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
long no_of_houses = 1048576L; //dimensions of my final table.
int no_of_appliances = 5;
int no_of_sectors = 48;
int* intended_schedule; // this is where the table will be stored.
intended_schedule = (int*) malloc(no_of_houses * no_of_appliances * no_of_sectors * sizeof(int));
FILE* fptr = fopen("./data/houses.csv", "r"); //this file is around 480 mega bytes.
if(fptr == NULL){
perror("housese file");
exit(0);
}
fseek(fptr, 0L, SEEK_END); //find the size of the file before allocating space
long size = ftell(fptr);
rewind(fptr);
char* buffer = (char*) calloc(1, size); //now we know the size, we can allocate space.
fread(buffer, size, 1, fptr);
char* token = strtok(buffer, ",\n"); //it's a comma separated file. So break from comma
long no = 0;
while(token != NULL){
if(no == no_of_houses*no_of_appliances*no_of_sectors)
break; //guard against unexpectedly big data file.
intended_schedule[no] = token[0] - 48;// it's either 0 or 1. So this is good enough
no++;
token = strtok(NULL, ",\n");
}
fclose(fptr);
free(intended_schedule);
free(buffer);
return 0;
}
I used this code as a function of a bigger program and since it gave me errors, I ran this program through valgrind. This is the result I got:
goodman#node2 analyse_code]$ valgrind ./analyse
==39263== Memcheck, a memory error detector
==39263== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==39263== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==39263== Command: ./analyse
==39263==
==39263== Warning: set address range perms: large range [0x51f8040, 0x411f8040) (undefined)
==39263== Warning: set address range perms: large range [0x59e3f040, 0x77e3f040) (defined)
==39263== Warning: set address range perms: large range [0x59e3f040, 0x77e3f040) (defined)
==39263== Invalid read of size 1
==39263== at 0x4EBEDCC: strtok (in /usr/lib64/libc-2.17.so)
==39263== by 0x400997: main (analyse.c:36)
==39263== Address 0x77e3f040 is 0 bytes after a block of size 503,316,480 alloc'd
==39263== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==39263== by 0x400904: main (analyse.c:27)
==39263==
==39263== Invalid read of size 1
==39263== at 0x4EBEDFC: strtok (in /usr/lib64/libc-2.17.so)
==39263== by 0x400997: main (analyse.c:36)
==39263== Address 0x77e3f040 is 0 bytes after a block of size 503,316,480 alloc'd
==39263== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==39263== by 0x400904: main (analyse.c:27)
==39263==
==39263== Warning: set address range perms: large range [0x51f8028, 0x411f8058) (noaccess)
==39263== Warning: set address range perms: large range [0x59e3f028, 0x77e3f058) (noaccess)
==39263==
==39263== HEAP SUMMARY:
==39263== in use at exit: 0 bytes in 0 blocks
==39263== total heap usage: 3 allocs, 3 frees, 1,509,950,008 bytes allocated
==39263==
==39263== All heap blocks were freed -- no leaks are possible
==39263==
==39263== For counts of detected and suppressed errors, rerun with: -v
==39263== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
I'm wondering why I get these errors. As far as I can tell, there are no problems with my code. Is it because my data is too large? I don't think that could be the case since I run this code on a server with 128 GB of RAM.
Any help would be appreciated.
--ppgoodman
strtok() assumes a NUL-terminated string, your buffer is NOT NUL-terminated, so strtok() will try to walk beyond the end of your buffer. But you can do withoutstrtok() and the large buffer.
You don't need to buffer the entire file; for simple cases like this, you can step through it using a one-character buffer. This will consume less memory and will also be consirably faster (at least 2 times)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
unsigned long no_of_houses = 1048576L; //dimensions of my final table.
unsigned int no_of_appliances = 5;
unsigned int no_of_sectors = 48;
unsigned long no = 0;
int ch;
unsigned int *intended_schedule; // this is where the table will be stored.
intended_schedule = malloc(no_of_houses * no_of_appliances * no_of_sectors * sizeof *intended_schedule);
FILE *fptr = fopen("./data/houses.csv", "r"); //this file is around 480 mega bytes.
if(!fptr) {
perror("housese file");
exit(0);
}
while(no < no_of_houses*no_of_appliances*no_of_sectors) {
ch = getc(fptr);
if (ch== EOF) break;
if (ch== '\n') continue;
if (ch== ',') continue;
intended_schedule[no++] = ch - '0'; // it's either 0 or 1. So this is good enough
}
fclose(fptr);
free(intended_schedule);
return 0;
}
I need to read a file and store the data from the file into a structure. The first line of the file contains the size of the array of structs that i have to dynamically allocate.
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
I am to run my code perfectly in Windows but when I run in Unix environment it shows me segmentation fault (core dumped). I did use valgrind to check for the memory leak and that is the results
==4344== Invalid read of size 1
==4344== at 0x407F842: ____strtol_l_internal (strtol_l.c:298)
==4344== by 0x407F606: strtol (strtol.c:108)
==4344== by 0x407C87E: atoi (atoi.c:27)
==4344== by 0x8048837: main (in /home/admininistrator/ucp/p6/gg)
==4344== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==4344==
==4344==
==4344== Process terminating with default action of signal 11 (SIGSEGV)
==4344== Access not within mapped region at address 0x0
==4344== at 0x407F842: ____strtol_l_internal (strtol_l.c:298)
==4344== by 0x407F606: strtol (strtol.c:108)
==4344== by 0x407C87E: atoi (atoi.c:27)
==4344== by 0x8048837: main (in /home/admininistrator/ucp/p6/gg)
==4344== If you believe this happened as a result of a stack
==4344== overflow in your program's main thread (unlikely but
==4344== possible), you can try to increase the size of the
==4344== main thread stack using the --main-stacksize= flag.
==4344== The main thread stack size used in this run was 8388608.
==4344==
==4344== HEAP SUMMARY:
==4344== in use at exit: 1,396 bytes in 3 blocks
==4344== total heap usage: 3 allocs, 0 frees, 1,396 bytes allocated
==4344==
==4344== LEAK SUMMARY:
==4344== definitely lost: 0 bytes in 0 blocks
==4344== indirectly lost: 0 bytes in 0 blocks
==4344== possibly lost: 0 bytes in 0 blocks
==4344== still reachable: 1,396 bytes in 3 blocks
==4344== suppressed: 0 bytes in 0 blocks
==4344== Rerun with --leak-check=full to see details of leaked memory
==4344==
==4344== For counts of detected and suppressed errors, rerun with: -v
==4344== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Here is my code attached
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"struct.h"
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("You have enter less arguments.\n");
}
else if (argc > 2)
{
printf("You have enter too many arguments.");
}
else
{
FILE *file;
Diary *res;
Diary *res2;
char line[102];
int i, size, k, l, choice;
int day, month, year;
/* int d[10],m[10],y[10];*/
char as[102];
char* oken;
char* yoken;
char* coken;
oken = NULL;
yoken = NULL;
coken = NULL;
i = 0;
file = fopen("struct.txt", "r");
if (file == NULL)
{
perror("Error opening file\n.");
}
else
{
fscanf(file, "%d", &size);
res = (Diary*) malloc(size * sizeof(Diary));
res2 = (Diary*) calloc((5), sizeof(Diary));
while (fgets(line, sizeof(line), file) != NULL)
{
oken = strtok(line, "/");
if (oken != NULL)
{
res2[i].day= atoi(oken);
coken = strtok(NULL, "/");
if (oken != NULL)
{
res2[i].month = atoi(coken);
yoken = strtok(NULL, "\n ");
if (coken != NULL)
{
/*printf("%s",yoken);*/
res2[i].year = atoi(yoken);
fgets(as, 102, file);
strncpy(res2[i].entry, as, 102);
}
}
}
i++;
}
k = 1;
l = 0;
while (l < size)
{
res[l].day = res2[k].day;
res[l].month = res2[k].month;
res[l].year = res2[k].year;
strncpy(res[l].entry, res2[k].entry, 102);
k++;
l++;
}
choice = atoi(argv[1]);
printf("%d-%02d-%02d:%s",res[choice].year, res[choice].month,res[choice].day,res[choice].entry);
free(res2);
free(res);
}
fclose(file);
}
return 0;
}
I need to read all the data from the file to the struct and print it out whenever user want the entry. I tried to debug part by part, and I found out it is the part while( fgets( line, sizeof( line ), file) != NULL) that loop, gives the problem. But I have no idea how to fix it.
My struct.h is given as below:
typedef struct journal{
int day;
int month;
int year;
char entry[1024];
} Diary;
I don't quite understand all of what you are trying to achieve, but here are a few issues.
You probably don't need the day month year variables.
This line
day = atoi(oken);
should probably be
res2[i].day = atoi(oken);
There is a problem with the line that reads the size
fscanf(file, "%d", &size)
This reads an integer but it does not read the trailing newline
You need to change this to be something like
fscanf(file, "%d\n", &size)
or use fgets.
Because of the trailing newline, the next time you call gets you obtain a string containing just the newline.
Your strtok calls and NULL checks are out of phase. The first one, for oken is OK. But then you do a strtok returning coken but a NULL check on oken and lastly a strtok returning yoken and a NULL check on coken. In all 3 cases, the call to strtok should be followed by a NULL check on the returned value (as is the case for oken).
I don't understand the purpose of the while (l < size) loop (maybe because of the mishandling of the newline as described above?). You allocate 5 structs, read 4 from structs.txt into res2 (elements 0 to 3) then you copy elements 1 to 4 of res2 into elements 0 to 3 of res. This means that element 0 of res2 doesn't get copied and element 4 which is all zeroes does get copied.
The cause of the crash is a combination of points 3 and 4.
I would advise against using atoi as it does no error checking. It is unsafe to use unless you are certain that the string contains a well-formed integer. If you want your code to be robust, you need to add more error checking e.g., check the return values of malloc and calloc.
I'm writing a program that loads input until a specific word is typed in,in this case its word "konec".Although my program seems to work just about ok,I can't solve this Valgrind error
==16573== Memcheck, a memory error detector
==16573== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==16573== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==16573== Command: ./s_main_o
==16573==
==16573== Conditional jump or move depends on uninitialised value(s)
==16573== at 0x4C2A020: strcmp (mc_replace_strmem.c:711)
==16573== by 0x4008D7: main (main.c:41)
==16573== Uninitialised value was created by a heap allocation
==16573== at 0x4C28CCE: realloc (vg_replace_malloc.c:632)
==16573== by 0x40089C: main (main.c:38)
==16573==
==16573== Conditional jump or move depends on uninitialised value(s)
==16573== at 0x4C2A024: strcmp (mc_replace_strmem.c:711)
==16573== by 0x4008D7: main (main.c:41)
==16573== Uninitialised value was created by a heap allocation
==16573== at 0x4C28CCE: realloc (vg_replace_malloc.c:632)
==16573== by 0x40089C: main (main.c:38)
==16573==
==16573==
==16573== HEAP SUMMARY:
==16573== in use at exit: 0 bytes in 0 blocks
==16573== total heap usage: 8 allocs, 8 frees, 1,125 bytes allocated
==16573==
==16573== All heap blocks were freed -- no leaks are possible
==16573==
==16573== For counts of detected and suppressed errors, rerun with: -v
==16573== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)
And here part of the used code
int main() {
int numberOfWords, i;
char** words;
char* word;
int* rarity;
char* konec = "konec";
int amount = 0;
double percentage;
words = malloc(10 * sizeof (char*));
rarity = calloc(256, sizeof (int));
numberOfWords = 0;
words[0] = 0;
int working = 1;
while (working == 1) {
int length = 0;
word = calloc((length + 1),sizeof (char));
char c;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n') {
break;
}
length++;
word = realloc(word, length + 1);
word[length - 1] = c;
}
if (strcmp(word, konec) == 0) {
working = 0;
free(word);
break;
}
}
}
I have found lots of topics discussing the same problem,but I wasn't able to find solution anyway.Thanks for your answers.
The problem is that you do not add a null terminator on reallocation:
word = realloc(word, length + 1);
word[length - 1] = c;
At this point, word string is not terminated, so strcmp may go off its end in search of null terminator. For example, when you type "ko", strcmp will determine that characters 0 and 1 are the same, and try checking word[2] - a location that your program did not set.
Add this line to fix the problem:
word[length] = '\0';
You should also add code to free word when comparison to konec is unsuccessful.
Note: You are not using realloc correctly: instead of assigning it back to word, you should assign it to temp, and check it for NULL. Otherwise, you would have no way of freeing previously allocated word when realloc fails.