Why can't I realloc an array that was fully initialized? - c

Have a look at the piece of code below. When I create an array by mallocating space for it I can always resize the array without loss of data. But when I create an array by fully initializing it with int test2[] = {3}; I am unable to realloc. Why is that? This is just a silly example but it presents the problem I am facing well.
I tried referencing test2 in different ways (*, &, **, etc) but at some point I found myself just hoping to magically find the solution without knowing what I was doing anymore.
I have been googling a lot but I cannot seem to find a proper explanation for this or solution that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int *test1 = malloc(1 * sizeof(int));
test1[0] = 1;
test1 = realloc(test1, 2 * sizeof(int));
test1[1] = 2;
for(int i = 0; i < 2; i++)
{
printf("%d\n", test1[i]);
}
int test2[] = {3};
test2 = realloc(test2, 2 * sizeof(int));
test2[1] = 4;
for(int i = 0; i < 2; i++)
{
printf("%d\n", test2[i]);
}
}
Output:
test.c: In function 'main':
test.c:17:8: error: assignment to expression with array type
test2 = realloc(test2, 2 * sizeof(int));
When I remove the code after the first for loop, the program compiles and executes nicely as it should.

The declaration int test2[] = {3}; does not create memory that can be later either freed or re-allocated! Rather, it defines an array of fixed length, most likely 'created' on the stack.
A call to malloc, on the other hand, allocates the requested amount of memory from the heap (essentially, a large pool of memory available to your running program); this memory 'chunk' can later be re-sized with realloc and must be released (when you're done with it) by calling free.

Related

Issue writing in a pointer allocated through a function

I need to write in a variable allocated through a function. I found a lot of threads discussing this, such as Allocating a pointer by passing it through two functions and How to use realloc in a function in C, which helped me fixing some issues, but one remains and I can't find the cause.
Consider the following code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void foo(uint64_t** m)
{
*m = realloc(*m, sizeof(uint64_t) * 4);
*m[0] = (uint64_t)1;
//*m[1] = (uint64_t)2; // create a segfault and crash right here, not at the print later
}
int main()
{
uint64_t* memory = NULL;
foo(&memory);
for(int i = 0; i < 4; i++)
printf("%d = %ld\n", i, memory[i]);
return 0;
}
I send the address of memory to foo, which takes a double pointer as an argument so it can modify the variable. The realloc function need a size in bytes, so I make sure to ask for 4 * sizeof(uint64_t) to have enough space to write 4 64-bits int. (The realloc is needed, I don't need malloc).
I can then write in m[0] without issue. But if I write in m[1], the program crashes.
What did I do wrong here ?

A dynamic 1D array in C don't want to ingest each character of a file in each of his boxes

In C, I want to fill a dynamic array with each character of a file in each of his boxes.
But instead, when I print my array I have:
0 = []
1 = []
2 = []
3 = []
4 = []
5 = []
6 = []
7 = []
8 = []
9 = []
I have no compilation errors, but valgrind said that I have a:
Conditional jump or move depends on uninitialised value(s)
in my main at the printf.
That's strange, because even with an initialisation in my main:
array_valid_char = NULL;
valgrind keeps getting me that error.
And even if I change to:
printf("%d = [%d] \n", i, array_valid_char[i]);
the display is the same.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int* f(char* name_file_in)
{
FILE *file_in;
int* array_valid_char = malloc(10 * sizeof(int*));
int read_char;
file_in = fopen(name_file_in,"rb");
if(file_in)
{
while ((read_char = fgetc(file_in)) != EOF)
{
*(array_valid_char++) = read_char;
}
}
if(file_in){fclose(file_in);}
return array_valid_char;
}
int main(int argc,char* argv[])
{
int *array_valid_char = malloc(10 * sizeof(int*));
array_valid_char = f(argv[1]);
for (int i = 0; i < 10; i++)
{
printf("%d = [%c] \n", i, array_valid_char[i]);
}
return(0);
}
What is wrong with my code?
You have to keep track of the beginning of the allocated memory which you didn't. (That original allocated chunks address should be returned ).
int* array_valid_char = malloc(10 * sizeof(int*));
int *st = array_valid_char ;
...
return st;
Also you have memory leak - you can omit the malloc in main().
Also you need to free the dynamically allocated memory when you are done working with it.
free(array_valid_char);
And also the memory allocation part would be
int* array_valid_char = malloc(10 * sizeof(int));
or
int* array_valid_char = malloc(10 * sizeof(*array_valid_char));
You want array of int.
Among other points check the return value of malloc and handle it properly.
The correct way to code would be to index into the allocated memory and check whether we are reaching limit of what we allocated - if it is so then reallocate.
Many of us confine ourselves with the thought that sizeof( *ptr)*10
is only good enough for the clear syntax etc but knowing that sizeof returns size_t when multiplied this with other value it is less likely to overflow as in opposed to writing the other way round(which was having int arithmetic) that's a benefit. (chux)
For example: sizeof(something)*int*int will do result in operation with size_t value which will less likely to overflow that int*int*sizeof(int). In second case int*int may overflow.(more likely)
There are some problems in your code:
With *(array_valid_char++), you move your pointer each time you pass on the loop. If you want to use this method, you need to keep a track on the beginning of your array with an other variable. You can also use an iterator array_valid_char[i] that starts at 0 and increments it at each loop turn.
In your main, you malloc your array int *array_valid_char = malloc(10 * sizeof(int*)); but you override it just after with array_valid_char = f(argv[1]);. If you malloc your array in a function and send it back with a return, the memory is still allocated.
In printf, %d is for display a number and %c is for display a character. In your case, you need to use %c. In the other case, you will see the ASCII value of your character.
By the way, you also use an int array to receive char array. It is not a problem now but for some optimisation, you can use char array to take less memory.
Also, don't forget to free the memory you have used when you don't use it anymore, it could be useful in bigger programs.

C - Self-referencing structure and realloc

I've got a problem with calling realloc on self-referencing structure. When I run this program, I get error *** Error in ...: realloc(): invalid next size: 0x0000000000602160 ***. I suppose the problem is related to the last line, because program runs without any problem if I comment it.
This is the smallest (not) working piece of code:
#include <string.h>
#include <stdlib.h>
typedef struct structure {
int connections;
struct structure *links;
} structure;
int main(int argc, char *argv[]) {
int struct_count;
int i, from, to, offset;
structure *structs;
struct_count = 2;
structs = malloc(sizeof(structure) * struct_count);
memset(structs, 0, sizeof(structure) * struct_count);
for(i = 0; i < struct_count; i++) {
structs[i].links = malloc(1);
structs[i].connections = 0;
}
for(i = 0; i < 100; i++) {
from = 0;
to = 1;
offset = structs[from].connections++;
structs[from].links = realloc(structs[from].links, sizeof(int) * (offset + 1));
structs[from].links[offset] = structs[to]; // This is the problematic line - why?
}
}
And my question: what's wrong in that code?
The problem is the first time you allocate it, it's not enough. To allocate n elements of a given type you can use
structs[i].links = malloc(n * sizeof(*structs[i].links));
and the same goes wit realloc() you also need to make sure that realloc() doesn't return NULL, suppose that after allocating space for n structures with the line above you want to resize to store n + 1 instances, then
struct structure *links;
links = realloc(structs[i].links, (n + 1) * sizeof(*links));
if (links == NULL)
{
/* Depending on the way your program is designed */
probably_free_links(&structs[i].links);
/* ^ make it `NULL' inside */
allocation_failure_do_something_about_it_but_do_not_continue();
}
structs[i].links = links;
you can make structs[i].links = NULL; initially and realloc() will behave as malloc() the first time.
Write your programs as if all errors are possible, and do something about them don't just let your program invoke undefined behavior and make it a mistery to you and your program users.
If You will increase the Blueprint of structure and decrease the size of loop it will run perfectly..
**For Example:-**without manipulating run your program just decrease the loop condition from 100 to 2. It will run perfectly.
If you want to increase loop size you have to increase the size of structure.

Why can't I use malloc to set array size larger than what is needed?

I am coming from Python so using malloc is new to me. Intuitively the below should work but having syntax issues. In my first line I want to set array size to be a max of 8 ints. In the second line, I want to add those 4 ints. This line is for example only, in production I will have user input up to an 8-digit number. When I go to compile (clang) I get size of array has non-integer type 'void *' If I comment out this first line and initialize with the second line (and adding int type) the code works. So I am obviously setting the size incorrectly. Any ideas?
int main(void)
{
int mult_digits[malloc(8 * sizeof(int))];
mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
This code is all wrong. You call malloc to allocate memory, and malloc returns a pointer. Rather than deconstructing your syntax, which is very broken, I'll give a couple of variants of your program.
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
Here the array is not allocated dynamically. It's a local variable with automatic, stored on the stack.
For dynamic allocation you would do this:
int main(void)
{
int *mult_digits = malloc(4*sizeof *mult_digits);
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
free(mult_digits);
return 0;
}
The argument to malloc is the number of bytes to be returned. The value returned is the address of the new block of memory. Note also here that we made a call to free to deallocate the memory. If you omit that, the memory will be leaked.
With this variant, there is no way to recover the length of the array from mult_digits. I know that might freak you out, coming from Python, but I repeat. There is no way to recover the length of the array from mult_digits. It's your job to keep track of that information.
Now, you wanted to over-allocate the memory. You can certainly do that:
int main(void)
{
int *mult_digits = malloc(8*sizeof *mult_digits);
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
free(mult_digits);
return 0;
}
Here we only used the first 4 elements, and ignored the final 4. That's just fine. In case you do over-allocate you would typically need to keep track of both the allocated length, and the in-use length. You can then add new items by increasing the in-use length, up until you reach the allocated length. The you need to reallocate a larger block. I guess that's what you are driving at.
The problem is your syntax. What you meant was: int *mult_digits = malloc(8 * sizeof(int));
After that, mult_digits[] = {1,2,3,4}; is wrong. You could, however,
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
But unless you have some reason to swim into the pointer deep end, you might just want to:
int mult_digits[] = {1, 2, 3, 4};
Edit: to help with applying this answer, here is a full modified function that compiles and runs:
#include <stdio.h>
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
in square brackets you must specify the number of elements needed, not the length in byte of the array. you can use malloc to do
int* multdigits = malloc(sizeof(int)*8);
mult_digits[0] = 1;
etc
(sorry if my syntax is wrong, i don't write c code from years!)
they're two ways to do the same thing. see "malloc" as the "new" operator.
Try
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof int;
printf("Size of the array is %d\n", size_mult);
return 0;
}

Malloc initializing a null pointer

Hi I ran in to this situation. I am using malloc to give me an array of 10 pointers. When I see the test pointers in gdb, one of them(the third )points to 0x0. Sometimes the code segfaults when using apple[2]->string = "hello". Why does malloc do this? Thanks in advance for the help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
typedef struct test
{
char *string;
int data;
} test;
test *apple[10]; // Declare an array of 10 test pointers. This line results in one of the pointers having a null value.
apple[0] = malloc(sizeof(test));
apple[0]->string = "hello";
printf("The string is %s\n",apple[0]->string);
printf("Size of apple[0]->data is %d\n",sizeof(apple[0]->data));
printf("Size of tester is %d\n",sizeof(test));
free(apple[0]);
return 0;
}
I wanted to see how the array of pointers would work. I was not intending on using all the 10 pointers. So do I need to malloc only what I need? Is it a coincidence, that the third pointer was 0x0?
Memory has only been allocated for first element in apple so only apple[0] points to a valid struct test.
To allocate memory for all elements of apple:
for (int i = 0; i < sizeof(apple) / sizeof(test*); i++)
{
apple[i] = malloc(sizeof(test));
}
Similar loop required to free().
test.string is a char*, so pointing to a string literal as you have done is fine (though type should be const char*). If you wish to copy a string to test.string then you must malloc() space to copy into and free() it later.
There are different approaches, depending on what your final goal is.
If the number of elements in your array is meant to be constant every time the program is run, you don't have to use pointers at all:
test apple[10]; // array with 10 instances of test
test[0].string = ...;
test[1].data = ...;
If you'd like to use your approach (with pointers, which isn't really necessary right now), you have to malloc() every element on its own (like you did with apple[0], or malloc() the whole array:
int num = 10;
test *apple = malloc(sizeof(test) * num);
// access any element here
apple[5].string = "hello!";
free(apple);
You are allocating only one instance of the test and you're assigning it to the first array element:
apple[0] = malloc(sizeof(test));
To allocate all ten, you'd do:
for (int i = 0; i < 10; i++) {
apple[i] = malloc(sizeof(test));
}

Resources