Allocation memory error with use struct for c - c

I wrote a code for managing a library; the compilation is done but during the simulation I obtained an Allocation error (case2) and I don't know why.
The first case works correctly but if I entered more than one name in the first case, the second case doesn't work.
What did I do wrong? I hope I was clear enough.
typedef struct {
char name[80];
char **books;
int books_num;
} Subscription;
int main() {
// Variables declaration:
int option = 0, subs_num = 0, i = 0, books_num = 0;
Subscription *subs_library;
char **books;
char subs_new_name[80], book_new_name[80];
printf("Choose an option\n");
do {
scanf("%d", &option);
switch (option) {
case 1:
printf("Case 1: enter a new name\n");
scanf("%s", subs_new_name);
if (subs_num == 0) {
subs_library = malloc(sizeof(Subscription));
} else {
subs_library = realloc(subs_library, sizeof(Subscription));
}
strcpy(subs_library[subs_num].name, subs_new_name);
subs_library[subs_num].books_num = 0;
subs_num++;
printf("ADDED\n");
break;
case 2:
printf("Case 2: enter the book name\n");
scanf("%s", book_new_name);
if (books_num == 0) {
books = malloc(sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
} else {
books = realloc(books, sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
}
if (books[books_num] == NULL) {
printf("Allocation Error\n");
exit(1);
}
strcpy(books[books_num], book_new_name);
books_num++;
printf("ADDED\n");
break;
}
} while (option != 7);
return 0;
}

Your code to reallocate the arrays is incorrect. You do not allocate enough room for the new array sizes. When you reallocate these arrays, you pass the size of a single element, therefore the array still has a length of 1 instead of subs_num + 1. The size passed to realloc should be the number of elements times the size of a single element in bytes.
Initialize subs_library and books to NULL and change your array reallocations:
if (subs_num == 0) {
subs_library = malloc(sizeof(Subscription));
} else {
subs_library = realloc(subs_library, sizeof(Subscription));
}
Into this:
subs_library = realloc(subs_library, (subs_num + 1) * sizeof(*subs_library));
And do the same for books, change:
if (books_num == 0) {
books = malloc(sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
} else {
books = realloc(books, sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
}
To this:
books = realloc(books, (books_num + 1) * sizeof(*books));
books[books_num] = malloc(80 * sizeof(char));
Or simpler:
books = realloc(books, (books_num + 1) * sizeof(*books));
books[books_num] = strdup(book_new_name);

I guess the problem is with scanf reading a string only until a separator, in your case - a whitespace separating multiple names entered. The characters after separator remain in the input buffer and get immediately processed by other calls to scanf.
You should consider using getline for reading name(s) and checking return values from other calls to scanf.

The problem is your reallocation calls. For example you do
realloc(books,sizeof(char*))
This reallocates the memory pointed to be books to be one pointer to character in size, which is exactly what you already have. This will lead you to index out of bounds of the allocated memory, something which is undefined behavior.
If you want to allocate more than one element you need to multiply the base type size with the number of elements you want to allocate, e.g.
realloc(books, (books_num + 1) * sizeof(char *))

Your reallocation realloc(books, sizeof(char *)) only allocates the size of one pointer char *, not the size of the enlarged array that you need:
books=realloc(books,sizeof(char*));
You need to multiply the size of a pointer (char *) by the number of books you plan on storing in the array. You maintain the number of books in books_num.
As Joachim Pileborg said, with every allocation/reallocation, you want this to be one more than the current size. For the first allocation (malloc()), you want to allocate for one book, which is 1 times sizeof(char *). This happens to be equivalent to your existing code, which is fine. But the reallocation (realloc()) reallocates for the same size every time (only enough for one pointer), so you're not enlarging the allocation. You need to multiply the size required for one pointer (sizeof(char *)) by the number of pointers you want, which is books_num + 1. As in Joachim's answer, this is
books = realloc(books, (books_num + 1)*sizeof(char *));
This will enlarge the allocation of the array books by one more pointer. Then, on the next line you correctly allocate a string of size 80.
Your subs_library has the same reallocation issue.
Less frequent reallocation
You might want to resize an allocation less frequently. In this situation, you are reallocating every time you add an entry. One simple technique to reduce the number of reallocations is to double the allocation size every time it gets full. But you have to maintain the allocation size (capacity) and check for it whenever you add something. For example:
char **buffer; /* buffer of pointers to char */
int capacity = 1; /* number of elements allocated for */
int size = 0; /* number of elements actually used */
Then the initial allocation is
/* Initial allocation */
buffer = malloc(capacity*sizeof(*buffer));
And to add some char *new_item to the buffer
/* When adding an element */
if ( size == capacity ) {
/* Double allocation every time */
capacity *= 2;
/* Reallocate the buffer to new capacity */
realloc(buffer, capacity*sizeof(*buffer));
}
/* Item will fit, add to buffer */
buffer[size++] = new_item;
Notice that I have used sizeof(*buffer) instead of sizeof(char *). This makes the compiler figure out what the type and size is. That way, if I change the type of buffer for some reason, I don't have to change more places in the code. Another thing that I left out for brevity is that you should always check the return values to make sure they are not NULL.

Related

Segmentation fault when trying to access properly allocated array

I'm trying to read a CSV file and am writing a function to parse a line of data into an array of strings, which dynamically changes the size of the array and updates size and str_size accordingly. I have written a properly-working function called find_key() to locate the fseek() location of the line in question. I'm coming across a problem that I think relates to the allocation of the string array: I get a segmentation fault on the line at the bottom of the while loop, where it reads data[data_count][str_pos] = curr. The program breaks when I try to access data[0][0], even though as far as I can tell I've allocated memory properly. Any help would be appreciated!
/**
* #brief Get a row from the provided CSV file by first item. Dynamically
* allocated memory to data array
*
* #param file
* #param key First item of row
* #param data Array of strings containing data
* #param size Size of array
* #param str_size Size of strings in array
* #return 0 if successful, -1 if the row cannot be found, or 1 otherwise
*/
int csv_get_row(FILE *file, char *key, char **data, size_t *size, size_t *str_size) {
if(!file || !key) return 1;
/* Get the position of the beginning of the line starting with the key */
long pos = find_key(file, key);
if(pos == -1) return -1;
fseek(file, pos, SEEK_SET);
/* If these parameters aren't useful values, assign default values */
if(*size < 1) *size = DEFAULT_ARRAY_SIZE;
if(*str_size < 1) *str_size = DEFAULT_BUFFER_SIZE;
/* If the memory for the array hasn't been allocated, do so now */
if(!data) data = (char**) malloc(*size * *str_size);
/* Get characters one-by-one, keeping track of the current amount of elements and the current buffer position */
size_t data_count = 0;
size_t str_pos = 0;
char curr;
while(fscanf(file, "%c", &curr)) {
if(data_count >= *size) data = (char**) realloc(data, (*size *= 2) * *str_size);
if(str_pos >= *str_size) data = (char**) realloc(data, *size * (*str_size *= 2));
if(curr == ',') {
data[data_count][str_pos] = '\0';
data_count++;
str_pos = 0;
continue;
}
if(curr == '\n') {
data[data_count][str_pos] = '\0';
data_count++;
break;
}
data[data_count][str_pos] = curr;
str_pos++;
}
/* Resize the array to fit */
*size = data_count;
data = (char**) realloc(data, *size * *str_size);
return 0;
}
Assume that *size starts at 1. You set data_count to 0. Then, in the first iteration,
you do not have data_count >= *size, so you don't realloc(). You increment data_count
to 1, though, so in the next iteration, you grow the data buffer to 2.
So, at this point, data has length 2 and data_count is 1.
Let's then say we do not go into the first if statement but the second.
There, you increment data_count to two. You then access data[data_count], which is one
past the last element. That is a problem.
That might be the problem you see at the end of the while-loop, but it is far from the
only problem. Whenever you malloc() or realloc() data, you are invalidating the pointer the caller
has, because you might be freeing the memory at the original location. You never give him
a pointer to the new data back; all the newly allocated data will be leaked when you
return from the function, and the caller must never access data after the call, lest
he wants a segfault.

C programming, losing data after realloc

I am trying to get string of numbers and put it inside an int array.
I have no idea how many numbers I am going to get so I need to use dynamic allocation.
I created an array by using malloc and tried to resize it by +1 every time inside the loop.
This is my code
void main()
{
char *s;
int *polyNums;
int count = 0;
char *token;
s = gets();
polyNums = (int *)malloc(sizeof(int));
if (polyNums == NULL)
{
printf("Could not allocate required memory\n");
exit(1);
}
token = strtok(s, " ");
while (token != NULL)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1);
token = strtok(NULL, " ");
}
}
My problem is that every time it's doing realloc, all the saved numbers are gone, if my string is "1 2 3" so in loop 1 the polyNums[0] is 1, but I am loosing it in loop 2 after reallocating. Can some one please tell me where I went wrong?
You do not allocate enough memory for your array.
int *polyNums; // Holding integer!
int count = 0;
polyNums = (int *)malloc(sizeof(int)); // enough space for interger. OK!
...
while(...)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1); // Not enough space for intergers!
...
}
You access an array holding int values but you only allocate 1 byte per element.
While your first allocation can hold the first integer, you allocate less memory for any forther number.
polyNums = realloc(polyNums, (count+1)*sizeof(*polyNums));
Aside from that:
Do not cast the return value of malloc
Do not assign the return value of realloc directly to your pointer. In case of NULL return value you lose your old data.
You should take a look at pointers and resource management, more specifically you should learn what deep copy is and how to reallocate dynamic memory.
In general, you should define a temporary pointer for the new larger chunk of memory, copy all the old values to the new memory location and then you can reassign the temporary pointer to the initial pointer, polyNums. Then you are safe to add more new data.

how to keep using malloc?

I have a file which stored a sequence of integers. The number of total integers is unknown, so I keep using malloc() to apply new memory if i read an integer from the file.
I don't know if i could keep asking for memory and add them at the end of the array. The Xcode keeps warning me that 'EXC_BAD_EXCESS' in the line of malloc().
How could i do this if i keep reading integers from a file?
int main()
{
//1.read from file
int *a = NULL;
int size=0;
//char ch;
FILE *in;
//open file
if ( (in=fopen("/Users/NUO/Desktop/in.text","r")) == NULL){
printf("cannot open input file\n");
exit(0); //if file open fail, stop the program
}
while( ! feof(in) ){
a = (int *)malloc(sizeof(int));
fscanf(in,"%d", &a[size] );;
printf("a[i]=%d\n",a[size]);
size++;
}
fclose(in);
return 0;
}
Calling malloc() repeatedly like that doesn't do what you think it does. Each time malloc(sizeof(int)) is called, it allocates a separate, new block of memory that's only large enough for one integer. Writing to a[size] ends up writing off the end of that array for every value past the first one.
What you want here is the realloc() function, e.g.
a = realloc(a, sizeof(int) * (size + 1));
if (a == NULL) { ... handle error ... }
Reworking your code such that size is actually the size of the array, rather than its last index, would help simplify this code, but that's neither here nor there.
Instead of using malloc, use realloc.
Don't use feof(in) in a while loop. See why.
int number;
while( fscanf(in, "%d", &number) == 1 ){
a = realloc(a, sizeof(int)*(size+1));
if ( a == NULL )
{
// Problem.
exit(0);
}
a[size] = number;
printf("a[i]=%d\n", a[size]);
size++;
}
Your malloc() is overwriting your previous storage with just enough space for a single integer!
a = (int *)malloc(sizeof(int));
^^^ assignment overwrites what you have stored!
Instead, realloc() the array:
a = realloc(a, sizeof(int)*(size+1));
You haven't allocated an array of integers, you've allocated one integer here. So you'll need to allocate a default array size, then resize if you're about to over run. This will resize it by 2 each time it is full. Might not be in your best interest to resize it this way, but you could also reallocate each for each additional field.
size_t size = 0;
size_t current_size = 2;
a = (int *)malloc(sizeof(int) * current_size);
if(!a)
handle_error();
while( ! feof(in) ){
if(size >= current_size) {
current_size *= 2;
a = (int *)realloc(a, sizeof(int) * current_size);
if(!a)
handle_error();
}
fscanf(in,"%d", &a[size] );;
printf("a[i]=%d\n",a[size]);
size++;
}
The usual approach is to allocate some amount of space at first (large enough to cover most of your cases), then double it as necessary, using the realloc function.
An example:
#define INITIAL_ALLOCATED 32 // or enough to cover most cases
...
size_t allocated = INITIAL_ALLOCATED;
size_t size = 0;
...
int *a = malloc( sizeof *a * allocated );
if ( !a )
// panic
int val;
while ( fscanf( in, "%d", &val ) == 1 )
{
if ( size == allocated )
{
int *tmp = realloc( a, sizeof *a * allocated * 2 ); // double the size of the buffer
if ( tmp )
{
a = tmp;
allocated *= 2;
}
else
{
// realloc failed - you can treat this as a fatal error, or you
// can give the user a choice to continue with the data that's
// been read so far.
}
a[size++] = val;
}
}
We start by allocating 32 elements to a. Then we read a value from the file. If we're not at the end of the array (size is not equal to allocated), we add that value to the end of the array. If we are at the end of the array, we then double the size of it using realloc. If the realloc call succeeds, we update the allocated variable to keep track of the new size and add the value to the array. We keep going until we reach the end of the input file.
Doubling the size of the array each time we reach the limit reduces the total number of realloc calls, which can save performance if you're loading a lot of values.
Note that I assigned the result of realloc to a different variable tmp. realloc will return NULL if it cannot extend the array for any reason. If we assign that NULL value to a, we lose our reference to the memory that was allocated before, causing a memory leak.
Note also that we check the result of fscanf instead of calling feof, since feof won't return true until after we've already tried to read past the end of the file.

Add a new record using pointer and realloc

Hey Guys so basically I'm writing a program where you prompt the user how many first names he wants to store. You then create the pointer based on his response. After, you prompt him how many first names he wants to add to the pointer. So basically I'm trying to expand the same array by using realloc but I'm not sure if I'm using it correctly or not(Apparently not since it's not working)
Basically I want the first names that the user already inputted to stay as is, and for the program to start off asking the user for the next first name he wants to input. For example if the first time the user enters the number 2. Then he writes two names and then asks to add 2 more names, the program should keep the first 2 names and be ready to store at firstNames[2]. Thanks!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int amount;
//Asking user for number of records to input
printf("Please indicate the number of records you want to enter:");
scanf("%d", &amount);
printf("\n");
//Declaring dynamic array for first names
char **firstNames = (char**)malloc(amount * sizeof(char));
for (int i = 0; i < amount; i++)
{
firstNames[i] = (char*)malloc(1 * sizeof(char));
}
//Prompting user for first name, last name, and scores
for (int count = 0; count < amount; count++)
{
printf("Enter first name for user %d:", count + 1);
scanf("%s", firstNames[count]);
}
int add;
printf("How many users do you want to add now:");
scanf("%d", &add);
int sum = amount + add;
firstNames = (char**)realloc(firstNames, sum * sizeof(char));
for (int count = amount; count < sum; count++)
{
printf("Enter first name for user %d:", count + 1);
scanf("%s", firstNames[count]);
}
return 0;
}
There are a number of areas where you are having trouble. As mentioned in my original comment, you must first allocate the memory correctly, before worrying about reallocating. Rather than calling realloc and assigning the return to firstNames, it is far better to create a temporary pointer to assign the return from realloc to. In the event realloc fails, it returns NULL. That means all existing data is lost because you just assigned firstNames = NULL. Using the temporary pointer allows your to test if the realloc succeeded before assigning the reallocated space to firstNames.
Going thought your code, there are several additional areas that can be improved. Always initialize your variables (to zero is fine). Why? Attempting to read from an uninitialized variable is Undefined Behavior (bad). Your input routines are critical. Especially using scanf and reading int/char data. You must insure you empty the input buffer before calling scanf again or it will use the newline (that results from pressing [enter]) as your next value causing your program to skip over the scanf statements that follow. You can use scanf to consume the newline to properly flush the input buffer (stdin) with careful choice of the format string.
When you get input validate it! Knucklehead users will enter anything.
When initializing pointer to pointers it is often better to use calloc for the initial allocation instead of malloc. calloc initializes all values to (zero) again preventing a read from an uninitialized variable.
Regarding program flow, you will want to minimize the number of loops and eliminate unnecessary blocks of code. If for no other reason, to lessen that chance of mistake. Think through your loops. You used multiple loops to count to the same number when all your operations could take place in one. This isn't a knock, this is just a suggestion to help you simplify your code.
When you ask for how many more users to enter before reallocating, what happens if 0 is entered? How should you handle it? Better to check and respond the way you want to, than leave it up to what the computer considers potentially undefined.
Those are the main points. I put together an example with those thoughts incorporated. It can always be improved, but I think this will help you handle the input issue and give you an example of simplifying the flow. While not necessary, I created a couple of functions to handle the printing and freeing of memory. Remember, if you allocate memory, you are responsible for keeping track of it and freeing it when your are done. Enough! Here is the example. Let me know if you have questions.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_users (char **array, int sz); /* funciton to print users */
void free_memory (char **array, int sz); /* function to free memory */
int main (void)
{
int amount = 0; /* always intialize all variables */
int i = 0;
//Asking user for number of records to input
printf("\nEnter the number of records to enter: ");
scanf("%d%*c", &amount); /* read int, discard newline */
printf("\n");
if (!amount) /* validate records to enter */
{
fprintf (stderr, "\nerror: invalid input.\n\n"); /* if realloc fails, error and exit */
return 1;
}
//Declaring dynamic array for first names
char **firstNames = calloc (amount, sizeof (*firstNames)); /* using your variable for sizeof (x) */
for (i = 0; i < amount; i++) /* prevents mistaken sizeof (wrong) */
{ /* calloc initializes to NULL (zero) */
firstNames[i] = malloc (sizeof (**firstNames)); /* same for malloc */
//Prompting user for first name, last name, and scores
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]); /* read string and newline (discarded) */
}
int add = 0;
printf ("\nAny *additional* users to add: ");
scanf ("%d%*c", &add); /* read int, discard newline */
printf ("\n");
if (!add)
{
print_users (firstNames, amount);
free_memory (firstNames, amount);
return 0;
}
int sum = amount + add;
char **tmp = NULL;
tmp = realloc (firstNames, sum * sizeof (*firstNames)); /* never realloc actual pointer to data */
/* if realloc fails pointer set to NULL */
if (!tmp) /* validate realloc succeeded */
{
fprintf (stderr, "\nerror: reallocation failed.\n\n"); /* if realloc fails, error and exit */
return 1;
}
firstNames = tmp; /* now assign to pointer */
for (i = amount; i < sum; i++) /* why new var count, use i */
{
firstNames[i] = malloc (sizeof (**firstNames)); /* allocate new Names, prompt & store */
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]);
}
print_users (firstNames, sum);
free_memory (firstNames, sum);
return 0;
}
void print_users (char **array, int sz)
{
printf ("\nUsers firstNames:\n\n"); /* output users collecte in firstNames */
int i = 0;
for (i = 0; i < sz; i++)
printf (" user[%d] %s\n", i, array[i]);
}
void free_memory (char **array, int sz)
{
int i = 0;
for (i = 0; i < sz; i++) /* free allocated memory */
if (array[i])
free (array[i]);
if (array)
free (array);
}
Example Usage:
$ ./bin/reallocptr
Enter the number of records to enter: 2
first name for user 1 : Jack
first name for user 2 : Jill
Any *additional* users to add: 2
first name for user 3 : Mike
first name for user 4 : Moe
Users firstNames:
user[0] Jack
user[1] Jill
user[2] Mike
user[3] Moe
Note: See Addendum below, otherwise 4-bytes of memory will remain un-freed at exit.
Addendum
As was pointed out, only a single char was allocated to each of the firstName[i] pointers which was insufficient for the full strings assigned. Generally, in practice firstName[i] string allocation can be handled automatically with functions such as strdup or scanf with an appropriate format string. To fully handle the strings with scanf, the following changes are required:
//Declaring dynamic array for first names
char **firstNames = calloc (amount, sizeof (*firstNames)); /* using your variable for sizeof (x) */
for (i = 0; i < amount; i++) /* prevents mistaken sizeof (wrong) */
{ /* calloc initializes to NULL (zero) */
// firstNames[i] = malloc (sizeof (**firstNames)); /* let scanf auto-allocate */
//Prompting user for first name, last name, and scores
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]); /* read string and newline (discarded) */
}
...
for (i = amount; i < sum; i++) /* why new var count, use i */
{
// firstNames[i] = malloc (sizeof (**firstNames)); /* allocate new Names, prompt & store */
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]);
}
changes to free_memory()
void free_memory (char **array, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
if (array[i])
free (array[i]);
if (array)
free (array);
}
output/verification:
Enter the number of records to enter: 2
first name for user 1 : Jack
first name for user 2 : Jill
Any *additional* users to add: 2
first name for user 3 : Larry
first name for user 4 : Moe
Users firstNames:
user[0] Jack
user[1] Jill
user[2] Larry
user[3] Moe
==13690==
==13690== HEAP SUMMARY:
==13690== in use at exit: 0 bytes in 0 blocks
==13690== total heap usage: 10 allocs, 10 frees, 468 bytes allocated
==13690==
==13690== All heap blocks were freed -- no leaks are possible
char **firstNames = (char**)malloc(amount * sizeof(char));
This is a double pointer and memory needs to be allocated for pointers which points to your information.
So it should be
char **firstNames = malloc(amount * sizeof(char *));/* No need to cast malloc() */
Later you are doing realloc() for this memory and it is necessary for you to take care of realloc() failures.So use a temporary pointer to store the return value of realloc() and assign the address back to your firstNames.
firstNames[i] = (char*)malloc(1 * sizeof(char));
You are allocating a single byte here in each iteration in order to read strings you need more memory than this.
Some corrections in your memory allocations.
#define SIZE 10
char **firstNames = malloc(amount * sizeof(char *));
for (i = 0; i < amount; i++)
{
firstNames[i] = malloc(SIZE * sizeof(char));
}
First malloc is allocating memory for no of entries you want to store.
Since the entry are pointers to another memory, use malloc(amount * sizeof(char *))
The second malloc is nothing but, allocating memory for the actual strings you wan to store.
Where SIZE is the no of bytes for each entry.
So now you want to add more users, so you use realloc.
int sum = amount + add;
firstNames = realloc(firstNames, sum * sizeof(char *));
/* Add the following to your code */
for (i = amount; i < sum; i++)
firstNames[i] = malloc(SIZE * sizeof(char));
printf("Total Names: \n");
for ( i = 0; i < sum; i++)
printf("%s\n", firstNames[i]);
Here the second malloc is used for allocating memory for the newly added users.
It starts from (i = amount), since till amount memory is already allocated.

Pointer within structure reallocs fine, but pointer to a pointer within structure fails to realloc with invalid pointer error

While working on a program which requires frequent memory allocation I came across behaviour I cannot explain. I've implemented a work around but I am curious to why my previous implementation didn't work. Here's the situation:
Memory reallocation of a pointer works
This may not be best practice (and if so please let me knwow) but I recall that realloc can allocate new memory if the pointer passed in is NULL. Below is an example where I read file data into a temporary buffer, then allocate appropriate size for *data and memcopy content
I have a file structure like so
typedef struct _my_file {
int size;
char *data;
}
And the mem reallocation and copy code like so:
// cycle through decompressed file until end is reached
while ((read_size = gzread(fh, buf, sizeof(buf))) != 0 && read_size != -1) {
// allocate/reallocate memory to fit newly read buffer
if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {
printf("Memory reallocation error for requested size %d.\n", file->size+read_size);
// if memory was previous allocated but realloc failed this time, free memory!
if (file->size > 0)
free(file->data);
return FH_REALLOC_ERROR;
}
// update pointer to potentially new address (man realloc)
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Memory reallocation of pointer to pointer fails
However, here is where I'm confused. Using the same thought that reallocation of a NULL pointer will allocate new memory, I parse a string of arguments and for each argument I allocate a pointer to a pointer, then allocate a pointer that is pointed by that pointer to a pointer. Maybe code is easier to explain:
This is the structure:
typedef struct _arguments {
unsigned short int options; // options bitmap
char **regexes; // array of regexes
unsigned int nregexes; // number of regexes
char *logmatch; // log file match pattern
unsigned int limit; // log match limit
char *argv0; // executable name
} arguments;
And the memory allocation code:
int i = 0;
int len;
char **tmp;
while (strcmp(argv[i+regindex], "-logs") != 0) {
len = strlen(argv[i+regindex]);
if((tmp = realloc(args->regexes, sizeof(char **)*(i+1))) == (char **)NULL) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
tmp = NULL;
if((args->regexes[i] = (char *)malloc(sizeof(char *)*(len+1))) == (char *)NULL) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
strcpy(args->regexes[i], argv[i+regindex]);
i++;
}
When I compile and run this I get a run time error "realloc: invalid pointer "
I must be missing something obvious but after not accomplishing much trying to debug and searching for solutions online for 5 hours now, I just ran two loops, one counts the numbers of arguments and mallocs enough space for it, and the second loop allocates space for the arguments and strcpys it.
Any explanation to this behaviour is much appreciated! I really am curious to know why.
First fragment:
// cycle through decompressed file until end is reached
while (1) {
char **tmp_data;
read_size = gzread(fh, buf, sizeof buf);
if (read_size <= 0) break;
// allocate/reallocate memory to fit newly read buffer
tmp_data = realloc(file->data, (file->size+read_size) * sizeof *tmp_data );
if ( !tmp_data ) {
printf("Memory reallocation error for requested size %d.\n"
, file->size+read_size);
if (file->data) {
free(file->data)
file->data = NULL;
file->size = 0;
}
return FH_REALLOC_ERROR;
}
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Second fragment:
unsigned i; // BTW this variable is already present as args->nregexes;
for(i =0; strcmp(argv[i+regindex], "-logs"); i++) {
char **tmp;
tmp = realloc(args->regexes, (i+1) * sizeof *tmp );
if (!tmp) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
args->regexes[i] = strdup( argv[i+regindex] );
if ( !args->regexes[i] ) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
...
return 0;
}
A few notes:
the syntax ptr = malloc ( CNT * sizeof *ptr); is more robust than the sizeof(type) variant.
strdup() does exactly the same as your malloc+strcpy()
the for(;;) loop is less error prone than a while() loop with a loose i++; at the end of the loop body. (it also makes clear that the loopcondition is never checked)
to me if ( !ptr ) {} is easyer to read than if (ptr != NULL) {}
the casts are not needed and sometimes unwanted.

Resources