Malloc and Free Edition

So, I have this piece of code, I run it a couple of times:

void svnViewStatus() { FILE *file; int i, j, k, q=0, ok; char mystring[100000], *vect[100000], *var, last[12], first[12]; file = fopen("db_svnViewStatus.txt", "r"); if(file == NULL) { printf("error"); } else { i=1; while(fgets(mystring, 100000, file)) { if( i > 1) { j=1; var = strtok(mystring, ";"); while(var != NULL) { if(j==3) { if(i == 2) { strcpy(first, var); } strcpy(last, var); } if(j == 2) { if(q != 0) { ok=1; for(k=0; k<q; k=k+2) { if(strcmp(vect[k], var) == 0) { *vect[k+1]++; ok=0; } } if(ok == 1) { vect[q] = malloc(strlen(var)+1); strcpy(vect[q], var); vect[q+1] = malloc(sizeof(int)); *vect[q+1] = 1; q = q+2; } } else { vect[q] = malloc(strlen(var)+1); strcpy(vect[q], var); vect[q+1] = malloc(sizeof(int)); *vect[q+1] = 1; q = q+2; } } j++; var = strtok(NULL, ";"); } } i++; } } fclose(file); printf("nr: %d \n", i-2); printf("first: %s \n", first); printf("last: %s \n", last); for(i=0; i<q; i = i+2) { printf("User %s: %d \n", *vect[i], *vect[i+1]); } for(i=0; i<q; i=i+1) { free(vect[i]); } } 

and in db_svnViewStatus.db I have:

 NumeRepo:CitateWoodyAllen;DataCreat:12 Nov 2011;Detinator:Ioana;Descriere:Citate ale faimosului regizor Woody Allen 1;Ioana;12 Nov 2011;Woody Allen;What if everything is an illusion and nothing exists? In that case, I definitely overpaid for my carpet. 2;Mihai;12 Nov 2011;Woody Allen;The lion and the calf shall lie down together but the calf won't get much sleep 3;Mihai;13 Nov 2011;Woody Allen;Eighty percent of success is showing up 4;Cristi;23 Nov 2011;Woody Allen;It is impossible to travel faster than the speed of light, and certainly not desirable, as one hat keeps blowing off 5;Ioana;25 Nov 2011;Woody Allen;I had a terrible education. I attended a school for emotionally disturbed teachers. 6;Cristi;25 Nov 2011;Woody Allen;I will not eat oysters. I want my food dead. Not sick. Not wounded. Dead. 

But I get this:

"HEAP CORRUPTION DETECTED: after a normal block (# 54) at 0x000032E90. CRT detected that the application was written to memory after the completion of the heap buffer."

Any help?

Also, should I use it for free after allocating memory? What for?

+4
source share
6 answers

This code compiles cleanly and runs purely under valgrind .

 #include <stdlib.h> #include <string.h> #include <stdio.h> static void svnViewStatus(void) { FILE *file; int i, j, k, q=0, ok; char mystring[100000], *vect[100000], *var, last[12], first[12]; file = fopen("db_svnViewStatus.txt", "r"); if (file == NULL) { printf("error"); return; } for (i = 1; fgets(mystring, sizeof(mystring), file) != 0; i++) { if (i == 1) /* Skip heading */ continue; char *space = mystring; for (j = 1; (var = strtok(space, ";")) != NULL; space = NULL, j++) { if (j == 3) { if (i == 2) { strcpy(first, var); } strcpy(last, var); } if (j == 2) { if (q != 0) { ok = 1; for (k = 0; k<q; k += 2) { if (strcmp(vect[k], var) == 0) { (*vect[k+1])++; ok=0; } } if (ok == 1) { vect[q] = malloc(strlen(var)+1); strcpy(vect[q], var); vect[q+1] = malloc(sizeof(int)); *vect[q+1] = 1; q += 2; } } else { vect[q] = malloc(strlen(var)+1); strcpy(vect[q], var); vect[q+1] = malloc(sizeof(int)); *vect[q+1] = 1; q += 2; } } } } fclose(file); printf("nr: %d \n", i-2); printf("first: %s \n", first); printf("last: %s \n", last); for (i=0; i<q; i = i+2) { printf("User %s: %d \n", vect[i], *vect[i+1]); } for (i=0; i<q; i=i+1) { free(vect[i]); } } int main(void) { svnViewStatus(); return 0; } 

It has several levels with less indentation than the original. The code on the right side of the screen most often indicates problems. As noted in the comments, the main problem was the expression, which was intended to increment an integer using a pointer, but actually increase the pointer, not the integer. There are a couple of for loops that replace the while loops, so loop control is at the top of the loop. It is often easier to control the loop this way.

I'm still not happy with the code. You allocate int and treat char * as int * , which on a 64-bit machine means that you have an 8-byte pointer pointing to 4 bytes of data (and two calls to malloc() ). If you used a structure like:

 struct data { char *string; int count; }; struct data vect[5000]; 

In this case, you only select (duplicate) the line in the next element of the structure. It would be more compact and there would be less risk of error. (You write vect[i].count++; and it will do what you need, without fuss, without garbage.) And you will not need to bother with q += 2; (or q = q + 2; ).

This code is better using structure. It also checks the memory allocation and ensures that the names copied to first and last do not overflow (and end with zero). It still does not check the bounds of the vect array to ensure that it does not overwrite the end. If an error occurred while reading the file, a memory leak occurs; cleaning will require some caution (and functions for this).

 #include <stdlib.h> #include <string.h> #include <stdio.h> struct data { char *string; int count; }; static void svnViewStatus(void) { FILE *file; int i, q = 0; char mystring[100000], last[12], first[12]; struct data vect[50000]; file = fopen("db_svnViewStatus.txt", "r"); if (file == NULL) { printf("file open error\n"); return; } for (i = 1; fgets(mystring, sizeof(mystring), file) != 0; i++) { if (i == 1) /* Skip heading */ continue; char *space = mystring; char *var; for (int j = 1; (var = strtok(space, ";")) != NULL; space = NULL, j++) { if (j == 3) { if (i == 2) { strncpy(first, var, sizeof(first)-1); first[sizeof(first)-1] = '\0'; } strncpy(last, var, sizeof(last)-1); last[sizeof(last)-1] = '\0'; } if (j == 2) { int found = 0; for (int k = 0; k < q; k++) { if (strcmp(vect[k].string, var) == 0) { vect[k].count++; found = 1; } } if (found == 0) { vect[q].string = strdup(var); if (vect[q].string == 0) { printf("Memory allocation error\n"); return; } vect[q].count = 1; q++; } } } } fclose(file); printf("nr: %d\n", i-1); printf("first: %s\n", first); printf("last: %s\n", last); for (i = 0; i < q; i++) { printf("User %s: %d\n", vect[i].string, vect[i].count); } for (i = 0; i < q; i++) { free(vect[i].string); } } int main(void) { svnViewStatus(); return 0; } 
+1
source

You must allocate memory to complete the null value, for example:

 vect[q] = malloc(strlen(var)+1); 

If you are unable to allocate an extra byte, strcpy will write past the end of the allocated block, causing heap corruption.

+6
source

There are 2 problems. First, you do not allocate enough memory for the string. For a null terminator, you need an extra byte.

The other is that you set vect [q + 1] to a pointer, then you rewrite this pointer with a value of 1. When you try to free it, you try to free memory in memory location 1. You need to change:

 vect[q+1] = 1; 

to

 *(vect [ q + 1 ]) = 1; 
+4
source

Here you do not allocate enough memory:

 vect[q] = malloc(strlen(var)); 

strlen(3) only reports the length of the contents of the string and does not take into account the trailing ASCII NUL that C uses to break lines. Every time you see: malloc(strlen(foo)); This is almost certainly a mistake . Always write malloc(strlen(foo) + 1); . Make this + 1 obvious, because at any time when you don't see this + 1 , you probably found an error.

 strcpy(vect[q], var); 

Since vect[q] does not have enough memory allocated for it, this line overwrites the unbound byte with the ASCII NUL .

As for free(3) in your memory, most programmers find it very useful to write calls to malloc(3) and free(3) at the same time as checking the source code so that you can add functions or delete them cleanly and easily. Is there a simple and appropriate β€œstall” function that matches the function you just wrote? ..._init() functions often have functions ..._final() , functions ..._open() often have functions ..._close() , etc. These pairs are ideal for memory management.

+1
source

First, in this expression, the expressions:

 *vect[k+1]++; 

You have a problem with operator priority. You probably wanted to do this:

 (*vect[k+1])++; 

Then in this function is called:

 printf("User %s: %d \n", *vect[i], *vect[i+1]); 

type vect[i] is a char pointer. To print a line, you do not want to search for it and probably want this:

 printf("User %s: %d \n", vect[i], *vect[i+1]); 
0
source

Answering your last question:

Also, should I use it for free after allocating memory? What for?

Yes, you should use free (); If you do not use free (), you run the risk of having a memory leak.

You must call free () right at the end of the function, before the return statement, if you have one.

However, the calling function in the main case can also call free () when your svnViewStatus () function is finished and returns control to main. This is due to the fact that you can use another pointer variable using free (); you just need to make sure that the new pointer stores the same address. I mean the address of the first byte of the allocated malloc memory block.

And as dasblinkenlight said, you need to allocate memory to complete the null value.

I hope this help.

0
source

Source: https://habr.com/ru/post/1388870/


All Articles