Malloc and Realloc array of structs - c

I am defining a type of structures
typedef struct structs{
int freeSpace;
} structs;
I am creating a pointer to a structure
structs* arrayOfStructs;
I am allocating memory for array of size 5 of that structure
arrayOfStructs = malloc(5 * sizeof (arrayOfStructs));
arrayOfStructs[3].freeSpace = 99;
printf("\n%d", arrayOfStructs[3].freeSpace);
At some point I am reallocating that memory to array of size 10
arrayOfStructs = realloc(arrayOfStructs, 10 * sizeof (arrayOfStructs));
arrayOfStructs[8].freeSpace = 9;
printf("\n%d", arrayOfStructs[8].freeSpace);
And here I am setting freespace 17 at position 13 of the array which I expect to have only 10 positions.
arrayOfStructs[13].freeSpace = 17;
printf("\n%d", arrayOfStructs[13].freeSpace);
free(arrayOfStructs);
Why is this working ? What am I doing wrong ?

The behaviour of the program is undefined.
You are accessing memory that doesn't belong to you.
(What could well be happening is that realloc is obtaining more memory from the operating system than is actually required).

Related

Reallocation of memory to empty reference

I was watching a lesson on malloc and while they were doing a specific example, it made no sense for why such code to print out the entire pointer.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *list = malloc(3 * sizeof(int));
if (list == NULL)
return 1;
list[0] = 1;
list[1] = 2;
list[2] = 3;
int *tmp = malloc(4 * sizeof(int));
if (tmp == NULL)
return 1;
for (int i = 0; i < 3; i++)
tmp[i] = list[i];
tmp[3] = 4;
free(list);
//From this line and below is the thing in question.
list = tmp;
for (int i = 0; i < 4; i++)
printf("%i\n", list[i]);
}
OUTPUT:
~/test/ $ ./malloc_test
1
2
3
4
From my understanding of free(), it de-allocates the memory allocated by allocation functions and free() will 'free' up the memory of the pointer.
If I were to go by this definition:
*list was allocated 12 bytes (3 * sizeof(int), sizeof(int) = 4
Hard code list with numbers
*tmp was allocated 16 bytes
Copy the numbers in list to tmp
Free up list making it have no allocated bytes
List is now equal to tmp
How can list now be equal to tmp when list doesn't have any allocated memory?
Is list pointing to the address of tmp? If yes, why do we need to not allocate memory for list since earlier in the code, we did this int *tmp = malloc(4 * sizeof(int));
*list was allocated 12 bytes (3 * sizeof(int), sizeof(int) = 4
To be precise, you allocated 12 bytes of memory and set list to point to that memory.
Hard code list with numbers
*tmp was allocated 16 bytes
Again, to be precise, you allocated 16 bytes of memory and set the pointer variable tmp to point to it.
Copy the numbers in list to tmp
Free up list making it have no allocated bytes
To be precise, you freed the object that list pointed to so now list points to garbage and must not be dereferenced.
list is now equal to tmp
To be precise, list now points to the same thing tmp points to, those 16 bytes you allocated that previous was pointed to only by tmp.
How can list now be equal to tmp when list doesn't have any allocated memory?
Previously, list didn't point to allocated memory. But you changed it to point to the 16 bytes you allocated second. The value of a pointer is what it points to, list and tmp now point to the same thing so they have the same value. So they're now equal.
Is list pointing to the address of tmp? If yes, why do we need to not allocate memory for list since earlier in the code, we did this int *tmp = malloc(4 * sizeof(int));
The code frees the first allocated block of memory. If it didn't allocate a second block of memory, there would be nothing valid for either pointer to point to!
When you copy a pointer you're just copying the pointer's value1:
list = tmp;
This means that list now contains a copy of the tmp pointer, or in other words, they both point to the same memory address. In this case that address is an allocation.
Once they're made identical you can reference either of them interchangeably.
1 Of course this presumes the pointers are of the same type, like int* to int*, and not int to int**. You could also assign to void* and convert back again later, that works as well.
a pointer is a data type that is only assigned memory addresses of the corresponding data type, in your case in list = tmp; you assign the first position of that memory block that you created with int * tmp = malloc (4 * sizeof (int)); , when you make the assignment to list it will point to that memory address. (in your case at the beginning of that memory block).

Can someone please explain this. It deals with malloc and global array in C

If I'm trying to create a global array to hold an arbitrary number of integers in this case 2 ints. How is it possible that I can assign more numbers to it if I only allocate enough space for just two integers.
int *globalarray;
int main(int argc, char *argv[]) {
int size = 2;
globalarray = malloc(size * sizeof(globalarray[0]));
// How is it possible to initialize this array pass
// the two location that I allocated.
for (size_t i = 0; i < 10; i++) {
globalarray[i] = i;
}
for (size_t i = 0; i < 10; i++) {
printf("%d ", globalarray[i]);
}
printf("%s\n", "");
int arrayLength = sizeof(*globalarray)/sizeof(globalarray[0]);
printf("Array Length: %d\n", arrayLength);
}
When I run this it gives me
0 1 2 3 4 5 6 7 8 9
Array Length: 1
So I wanted to know if someone could clarify this for me.
(1) Am I creating the global array correctly?
(2) Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
And background info on why I want to know this is because I want to create a global array (shared array) so that threads can later access the array and change the values.
How is it possible to initialize this array pass the two location that I allocated.
Short answer: This is undefined behaviour and anything can happen, also the appearance that it worked.
Long answer: You can only initialize the memory you've allocated, it
doesn't matter that the variable is a global variable. C doesn't prevent you from
stepping out of bounds, but if you do, then you get undefined behaviour and anything can happen
(it can "work" but it also can crash immediately or it can crash later).
So if you know that you need 10 ints, then allocate memory for 10 int.
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
}
And if you later need more, let's say 15, then you can use realloc to increase
the memory allocation:
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
// do not contiue
}
....
// needs more space
int *tmp = realloc(globalarray, 15 * sizeof *globalarray);
if(tmp == NULL)
{
// error handling
// globalarray still points to the previously allocated
// memory
// do not continue
}
globalarray = tmp;
Am I creating the global array correctly?
Yes and no. It is syntactically correct, but semantically it is not, because you are
allocating space for only 2 ints, but it's clear from the next lines that
you need 10 ints.
Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
That's because
sizeof(*globalarray)/sizeof(globalarray[0]);
only works with arrays, not pointers. Note also that you are using it wrong in
two ways:
The correct formula is sizeof(globalarray) / sizeof(globalarray[0])
This only works for arrays, not pointers (see below)
We sometimes use the term array as a visual representation when we do stuff
like
int *arr = malloc(size * sizeof *arr)
but arr (and globalarray) are not arrays,
they are pointers. sizeof returns the amount in bytes that the
expression/variable needs. In your case *globalarray has type int and
globalarray[0] has also type int. So you are doing sizeof(int)/sizeof(int)
which is obviously 1.
Like I said, this only works for arrays, for example, this is correct
// not that arr here is not an array
int arr[] = { 1, 2, 3, 4 };
size_t len = sizeof arr / sizeof arr[0]; // returns 4
but this is incorrect:
int *ptr = malloc(4 * sizeof *ptr);
size_t len = sizeof ptr / sizeof ptr[0]; // this is wrong
because sizeof ptr does not returns the total amount of allocated
bytes, it returns the amount of bytes that a pointer needs to be stored in memory. When you are dealing with
pointers, you have to have a separate variable that holds the size.
C does not prevent you from writing outside allocated memory. When coding in C it is of the utmost importance that you manage your memory properly.
For your second question, this is how you would want to allocate your buffer:
globalarray = malloc(sizeof(int) * size);
And if you are on an older version of C than c11:
globalarray = (int*) malloc(sizeof(int) * size);

What is the difference between malloc(sizeof(int)) and malloc(sizeof(int*))

I'd like to allocate memory for the 2d int ptr below, but I'm not 100% positive I've done it correctly, so any pointers (ha ha) on that would be great. Is the way I free the array and its indexes in the for loop correct? Also, what is the difference between the first malloc and the second malloc: (int *) and (int)?
int **array = NULL;
int mem_size = 0;
int i = 0, j = 0;
// leaving out how mem_size is calculated, but it can vary
array = malloc(sizeof(int *) * mem_size);
if (array == NULL) {
// some error message
return;
}
for (i = 0; i < mem_size; i++) {
array[i] = malloc(sizeof(int) * 2);
if (!(array[i])) {
// some error message
for (j = 0; j < i; j++)
free(array[j]);
free (array);
return;
}
}
This is only a section of the code I wrote. At the end, I am freeing the array:
for (i = 0; i < mem_size; i++)
free(array[i]);
free(array);
It is just a compile time constant - size of pointer in first case, size of int in second. It may vary between systems (e.g. if compiling for 32bit systems, pointer would be 4 bytes, while on 64bit systems it is 8 bytes).
In case any of the mallocs fail in the for loop, should I be freeing the array there
You should be freeing everything you've allocated so far - each array[0..(i-1)] and array itself.
malloc(sizeof(int *) * mem_size)
Allocates memory for array of mem_size pointers.
malloc(sizeof(int) * 2);
Allocates memory for 2 ints.
Also you should consider allocating ordinary 1D array and just calculating index when you want to access it.
sizeof(int) is equal to 4 bytes
sizeof(int *) is also equal to 4 bytes
... since a pointer only holds 4 bytes.
When you call malloc(int) and malloc(int *) - in both cases, the memory manager allocates 4 bytes on the heap and returns a pointer to the allocated memory.
Since you are going to store that address into the array (which is a double pointer and can thus only hold the address of another pointer), the following is illegal:
array = malloc(sizeof(int *) * mem_size); --- illegal to use
You may implement what you want in the following way:
int *ptr = NULL;
int **p_ptr = NULL;
ptr=(int *)malloc(sizeof(int *));
p_ptr = &ptr;
**p_ptr = 100 or any other value; now, whatever changes you made will be reflected in the allocated size of 4 bytes
Each one of them is determined according to a different characteristic within your platform.
The size of int is determined by the compiler, which is typically designated for a specific processor.
So it is effectively derived from the CPU architecture.
It is usually 4 bytes, but may be 2 bytes on some platforms.
The size of int* (or any other pointer) is determined by the size of the virtual memory address space.
So it is effectively derived from the MMU architecture.
It is 4 bytes on 32-bit systems and 8 bytes on 64-bit systems.

Are "malloc(sizeof(struct a *))" and "malloc(sizeof(struct a))" the same?

This question is a continuation of Malloc call crashing, but works elsewhere
I tried the following program and I found it working (i.e. not crashing - and this was mentioned in the above mentioned link too). I May be lucky to have it working but I'm looking for a reasonable explanation from the SO experts on why this is working?!
Here are some basic understanding on allocation of memory using malloc() w.r.t structures and pointers
malloc(sizeof(struct a) * n) allocates n number of type struct a elements. And, this memory location can be stored and accessed using a pointer-to-type-"struct a". Basically a struct a *.
malloc(sizeof(struct a *) * n) allocates n number of type struct a * elements. Each element can then point to elements of type struct a. Basically malloc(sizeof(struct a *) * n) allocates an array(n-elements)-of-pointers-to-type-"struct a". And, the allocated memory location can be stored and accessed using a pointer-to-(pointer-to-"struct a"). Basically a struct a **.
So when we create an array(n-elements)-of-pointers-to-type-"struct a", is it
valid to assign that to struct a * instead of struct a ** ?
valid to access/de-reference the allocated array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
The code snippet is as follows:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
typedef struct {
int value1;
int value2;
}data;
int n = 1000;
int i;
int val=0;
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
printf("allocation successful\n");
for (i=0 ; i<n ; i++) {
array[i].value1 = val++;
array[i].value2 = val++;
}
for (i=0 ; i<n ; i++) {
printf("%3d %3d %3d\n", i, array[i].value1, array[i].value2);
}
free(array);
printf("freeing successful\n");
return 0;
}
EDIT:
OK say if I do the following by mistake
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
Is there a way to capture (during compile-time using any GCC flags) these kind of unintended programming typo's which could work at times and might blow out anytime! I compiled this using -Wall and found no warnings!
There seems to be a fundamental misunderstanding.
malloc(sizeof(struct a) * n) allocates n number of type struct a elements.
No, that's just what one usually does use it as after such a call. malloc(size) allocates a memory region of size bytes. What you do with that region is entirely up to you. The only thing that matters is that you don't overstep the limits of the allocated memory. Assuming 4 byte float and int and 8 byte double, after a successful malloc(100*sizeof(float));, you can use the first 120 of the 400 bytes as an array of 15 doubles, the next 120 as an array of 30 floats, then place an array of 20 chars right behind that and fill up the remaining 140 bytes with 35 ints if you wish. That's perfectly harmless defined behaviour.
malloc returns a void*, which can be implicitly cast to a pointer of any type, so
some_type **array = malloc(100 * sizeof(data *)); // intentionally unrelated types
is perfectly fine, it might just not be the amount of memory you wanted. In this case it very likely is, because pointers tend to have the same size regardless of what they're pointing to.
More likely to give you the wrong amount of memory is
data *array = malloc(n * sizeof(data*));
as you had it. If you use the allocated piece of memory as an array of n elements of type data, there are three possibilities
sizeof(data) < sizeof(data*). Then your only problem is that you're wasting some space.
sizeof(data) == sizeof(data*). Everything's fine, no space wasted, as if you had no typo at all.
sizeof(data) > sizeof(data*). Then you'll access memory you shouldn't have accessed when touching later array elements, which is undefined behaviour. Depending on various things, that could consistently work as if your code was correct, immediately crash with a segfault or anything in between (technically it could behave in a manner that cannot meaningfully be placed between those two, but that would be unusual).
If you intentionally do that, knowing point 1. or 2. applies, it's bad practice, but not an error. If you do it unintentionally, it is an error regardless of which point applies, harmless but hard to find while 1. or 2. applies, harmful but normally easier to detect in case of 3.
In your examples. data was 4 resp. 8 bytes (probably), which on a 64-bit system puts them into 1. resp. 2. with high probability, on a 32-bit system into 2 resp. 3.
The recommended way to avoid such errors is to
type *pointer = malloc(num_elems * sizeof(*pointer));
No.
sizeof(struct a*) is the size of a pointer.
sizeof(struct a) is the size of the entire struct.
This array = (data *)malloc(sizeof(data *) * n) allocates a sizeof(data*) (pointer) to struct data, if you want to do that, you need a your array to be a data** array.
In your case you want your pointer to point to sizeof(data), a structure in memory, not to another pointer. That would require a data** (pointer to pointer).
is it valid to assign that to struct a * instead of struct a ** ?
Well, technically speaking, it is valid to assign like that, but it is wrong (UB) to dereference such pointer. You don't want to do this.
valid to access/de-reference the allocated array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?
No, undefined behavior.

append to dynamically allocated array in c

I try realloc but it didn't work
this is the code. thanks for your help
trial = malloc (4 * sizeof(int));
trial[0] = 1; trial[1] = 4;trial[2] = 7;trial[3] = 11;
trial = (int*)realloc(trial, sizeof(int) * 5);
trial[sizeof(trial)-1] = 23;
int a;
for(a = 0; a < sizeof(trial); a++){
printf("TRIAL %d \n", trial[a]);
}
And the output look like this
TRIAL 1
TRIAL 4
TRIAL 7
TRIAL 23
It should be
TRIAL 1
TRIAL 4
TRIAL 7
TRIAL 11
TRIAL 23
The problem is that sizeof does not tell you how many elements are in the array; it tells you how much space the pointer (which points to the first element) takes up. So sizeof(trial) == sizeof(int*), and not the number of elements. You need to store the length separately.
sizeof will return sizeof(int *), which is the size of the pointer. You will have to keep track of the size of the pointer seperately.
Also, you should not return realloc() to the pointer you are reallocating. If realloc returns NULL, it will not modify the pointer and you will lose it. It is best to use a temporary pointer as follows:
int *p;
int *tmp;
/*...*/
tmp = realloc(p, NEW_SIZE);
if (tmp != NULL) p = tmp;
else { /*...*/ }
sizeof() on dynamically allocated memory only returns the size of the type, not the size of the block allocated. So sizeof(trial) in this case will return 4, the size of an int*.
sizeof(trial) == a constant (probably 4 or 8). It won't be the count of elements you allocated.
You need something like
int n = 100;
trial = realloc(trial, n*sizeof(*trial));
trial[n-1] = K; // K is some number.
sizeof returns the size of the type, in this case the size of an int * which I assume is 4 bytes. So you are making the array size 5, but you are setting element (4 - 1) to 23. You'll need to keep track of the size of the array through a variable.

Resources