I am facing a memory leak condition in the following functions.
char * readdatafromfile(unsigned pageNumber) {
char *buff = (char*) malloc(sizeof(char) * pagesize);
lseek(fd, pagesize * (pageNumber), SEEK_SET);
read(fd, buff, pagesize);
return buff;
}
//Read from file
char * readfromfile(char *fname, int pageno) {
char *buff = NULL;
fd = searchinvector(fname);
if (fd > 0)
buff = readdatafromfile(pageno);
else
printf("\nINDEX is not opened\n");
return buff;
}
I am trying to call the function the following way
char* root_buf = readfromfile(fname,pageno);
Can someone point to me where the memory leak occurs and how to overcome it.
EDIT
I do call free(root_buf); later. Forgot to mention that part. I believe this has to do with the fact that I am creating a pointer and returning it. Maybe the reference is caught in another pointer in the caller function.
The memory allocated using malloc are never freed again.
If you do this from your call site:
char* root_buf = readfromfile(fname,pageno);
// do stuff
free(root_buf);
It should solve the leak.
You are using malloc here.
char *buff = (char*) malloc(sizeof(char) * pagesize);
You need to free the memory after you have used it.
After you are done with root_buf and no longer need it:
free (root_buf);
Related
I have the following C struct:
typedef struct {
char *name;
int nfollowers;
char *followers[];
} User;
There's a point in my code where I have to allocate memory for the last variable of the struct (followers) and I'm having issues on it.
I have tried this:
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char));
or this
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char *));
but the output I get after compiling is the following:
error: invalid use of flexible array member
How can I properly do this?
EDIT
Example of how my C file is structured:
User *users;
int i=0, n, nusers=0;
char aux, *str;
fd_in = open(argv[1], O_RDONLY);
if (fd_in >= 0) {
users = (User *) malloc(sizeof(User));
while (aux!='&') {
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char)); //Issue
while (aux != '#') {
...
}
}
}
As mentioned by tadman, instead of char *followers[]; use char **followers; to declare the field.
Also watch out that malloc does not initialize memory (though on linux the memory might be initialized to 0 if it has not been reused) so your use of realloc may result in corrupting the heap. Instead, just use malloc again (or use calloc to allocate the struct).
I have the following code:
char *get_packet(int cc, char *args[]){
char *packet;
packet = (char*) malloc(30 * sizeof(char));
//other code..
...
return packet;
}
int main(){
int cc = SCANS_TO_ACCUMULATE;
int args[] = {5000};
char *str_args[15];
int i = 0;
for(i; i<((sizeof(args)/sizeof(args[0]))); i++){
char buffer[10];
sprintf(buffer, "%d", args[i]);
str_args[i] = strdup(buffer);
free(buffer);
}
str_args[i] = NULL;
char *pkt;
pkt = get_packet(cc, str_args);
printf("%s\n", pkt);
free(pkt);
pkt = NULL;
getchar();
return 0;
}
However, running this causes my program to crash immediately, and after doing some inspection with Dr. Memory it appears I have a memory leak, but I can't seem to find why it's occurring. Am I not freeing the malloc'd memory correctly? Thanks in advance
Your code tries to deallocate memory of buffer which is not dynamically allocated,i.e. which is a local variable-array. This causes the crash.
Here:
char buffer[10];
...
free(buffer);
You cannot free local array, remove the call to the free. The memory will be freed up automatically when the variable gets out of scope.
Freeing the local array "buffer" is undefined, and probably horrible, behavior! You can't free something unless it was allocated with malloc() or calloc(). It's likely corrupting the heap and causing the crash.
I'm trying to read a set of lines from a file to an array. I'm doing this to learn malloc and realloc.
#define MAX_LINE 301
char** read_file_lines(char* filename) {
char** ptr = NULL;
int max = 5;
int i = 0;
FILE *fp = fopen(filename, "r");
if(fp != NULL) {
char line[MAX_LINE];
while(fgets(line, MAX_LINE, fp) != NULL) {
/* allocate some extra memory for some more lines */
if(i == max) {
int new_max = max * 2;
int nr_bytes = new_max * sizeof(char) * MAX_LINE;
char **ptr2 = realloc(ptr, nr_bytes);
if(ptr2 != NULL) {
ptr = ptr2;
ptr2 = NULL;
max = new_max;
}
}
// ptr[i] = line;
// strcpy(ptr[i], line);
memcpy(ptr[i], line, strlen(line));
i++;
}
fclose(fp);
}
else {
printf("Error opening file %s\n", filename);
}
return ptr;
}
The code compiles. However, when it is executed, an error occurs (the program crashes).
I did some debugging and determined that the problem is in up in the memcpy () instruction. I had previously tried using strcpy, which also gives a similar problem.
I went to check memcpy ()'s protocolo and it is as followS:
void * memcpy ( void * destination, const void * source, size_t num );
Now, if ptr is char**, isn't ptr[i] equivalent to a char* ?
Thanks for your comments.
It looks like ptr isn't initialized to point to any memory at all. Also, you're not allocating any memory for the individual lines.
To initialize ptr, change the declaration to:
int max = 5;
char** ptr = malloc(max * sizeof(char*));
Try adding this before the call to memcpy:
ptr[i] = malloc(strlen(line) + 1);
and change the calculation for the realloc call:
int nr_bytes = new_max * sizeof(char*);
EDIT: To explain in more detail: ptr is a pointer to an array of pointers. You have to allocate memory for ptr (that is, enough memory just to store individual pointers). In addition to this, you also have to allocate each individual array of characters that the individual elements of ptr will point to.
The first change I suggested ensures that ptr always points to enough memory to hold 5 pointers (or more, once it's been realloc'd.)
The second change ensures that each member of ptr always points to valid memory before you try to access it as a pointer.
And the third change is required because ptr points to elements that are pointers to char, not char.
Nah. Arrays are not pointers. Pointers to pointers are not arrays of arrays. If you want a two-dimensional dynamic array, then you have to allocate memory for 1. the array of pointers that point to the individual lines, and 2. for the lines themselves too.
Problem is that at first execution memory is not allocated: i is 0, max is 5, the if condition is false and the realloc is never executed.
when I compile this piece of code, the pointer freed not allocated error pops up. Could someone please explain why that is? Thank you!
static int make_buffer(FILE *input, char *buffer[]){
*buffer = (char *)malloc(INIT_BUFFER_SIZE*sizeof(char));
int buffer_size = INIT_BUFFER_SIZE;
int txt_size = 0;
char cha;
while((cha = fgetc(input)) != EOF){
if (txt_size == buffer_size){
*buffer = (char *)realloc(buffer, buffer_size*2*sizeof(char));
buffer_size *= 2;
}
(*buffer)[txt_size] = cha;
txt_size ++;
}
free(*buffer);
return txt_size;
}
It means that the code is attempting to free something that was not allocated using malloc/realloc. In your case, I think the problem is in
*buffer = (char *)realloc(buffer, buffer_size*2*sizeof(char));
which should be
*buffer = realloc(*buffer, buffer_size*2);
Probably also want to check the result of realloc just for form. Note I simplified yours a bit in that sizeof(char) == 1 by definition and the cast shouldn't be needed these days (it used to be). The commend by David S. about the usefulness of freeing the result is also valid.
Can I return an array that is created dynamically (using malloc) inside a function back to its caller?
I know that returning a statically allocated array is wrong because the stack unwinds as the function returns and variable is no longer valid but what about a dynamically allocated variable?
Returning anything allocated with malloc is fine, as long as whoever uses your function takes care of free()ing it when they're done. malloc allocates on the heap which is essentially global within your program.
As others have noted, you can in fact return a char pointer.
However, another common method is for the caller to pass in the pointer for the method to fill along with a length parameter. This makes it so the function responsible for allocating the memory will also be the same function responsible for freeing the memory, which can make memory leaks easier to see. This is what functions such as snprintf and strncpy do.
/* Performs a reverse strcpy. Returns number of bytes written if dst is
* large enough, or the negative number of bytes that would have been
* written if dst is too small too hold the copy. */
int rev_strcpy(char *dst, const char *src, unsigned int dst_len) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
int i,j;
if (src_len+1 > dst_len) {
return -(src_len+1); /* +1 for terminating NULL */
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return src_len;
}
void random_function() {
unsigned int buf_len;
char *buf;
int len;
const char *str = "abcdefg";
buf_len = 4;
buf = malloc(buf_len * sizeof(char));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ...whatever randomness this function needs to do */
len = rev_strcpy(buf, str, buf_len);
if (len < 0) {
/* realloc buf to be large enough and try again */
free(buf);
buf_len = -len;
buf = malloc(buf_len * sizeof(buf));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
len = rev_strcpy(buf, str, sizeof(buf));
}
/* ... the rest of the randomness this function needs to do */
/* random_function has allocated the memory, random_function frees the memory */
free(buf);
}
This can lead to some overhead though if you don't know how big a buffer you'll need and need to call the function twice, but often the caller has a good idea to how large the buffer needs to be. Also it requires a little more logic to ensure the function doesn't overrun the given buffer. But it keeps the responsibility of freeing the memory with whatever is allocating the memory, while also allowing the option to pass local stack memory.
Example just returning the char*:
/* Performs a reverse strcpy. Returns char buffer holding reverse copy of
* src, or NULL if memory could not be allocated. Caller is responsible
* to free memory. */
char* rev_strcpy(const char *src) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
char *dst;
int i,j;
dst = malloc((src_len+1) * sizeof(char));
if (!dst) {
return NULL;
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return dst;
}
void random_function() {
char *buf;
const char *str = "abcdefg";
/* ...whatever randomness this function needs to do */
buf = rev_strcpy(str);
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ... the rest of the randomness this function needs to do */
/* random_function frees the memory that was allocated by rev_strcpy */
free(buf);
}
Yes you can. Just malloc() the array inside your function and return the pointer.
BUT, the caller needs to understand it needs to be freed at some point, or you'll have a memory leak.
You can certainly return an array allocated with malloc, but you have to make sure the caller of the function eventually releases the array with free; if you don't free a malloc'd array, the memory remains "in use" until program exit.