OK, this is going to be long answer, because what you've asked spans many subjects, so bare with me.
Arrays vs Pointers
First, let's learn the difference between arrays and pointers. When you declare an array as:
int nums[20];
you reserve 20 consecutive places in memory, which you can refer to by the variable nums
. Specifically, you reserve these places in stack memory. Stack memory is where all your local variables get stored, and the order with which you called a series of function, so your program knows how to return to the caller function.
When you want those places in memory to be on the heap memory, you use:
int *nums;
nums = malloc(20 * sizeof(int));
Both of these reserve the same amount of memory, but one is on the stack while the other is in the heap memory.
In both cases, can access you can access the elements in the array using any of two notations:
nums[7] = 42;
or
*(nums+7) = 42;
The first uses the array brackets notation, while the second, treats nums
as a pointer (which it is in both cases), moves some places forward from that position in memory (the +7 part), and derefrences the memory at that position (the *
at the beginning). Here is a complete program you can run to test this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// allocate the memory in stack
int nums[20];
// allocate the memory in heap
int *nums2;
nums2 = malloc(20 * sizeof(int));
// array-like notation
nums[7] = 42;
nums2[7] = 42;
// pointer-like notation
*(nums+8) = 50;
*(nums2+8) = 50;
// the two notations can be used interchangeably
printf("%d\n", *(nums+7));
printf("%d\n", *(nums2+7));
printf("%d\n", nums[8]);
printf("%d\n", nums2[8]);
// never forget to free the memory you have allocated in the heap!
free(nums2);
return 0;
}
with output:
42
42
50
50
In both cases, you can use any other type of variable, I just used int
for simplicity.
You can read more about stack and heap here.
Structs in stack and structs in heap
Now let's see what happens with your structs, for which you allocate memory in stack, but they have variables stored in heap and stack.
Let's start with how you access a struct if it's in heap and how if it's in stack. For example we will use the following struct:
struct test
{
int foo;
int *bar;
int baz[20];
int *qux;
};
When you want to access a variable of a struct in stack, you use the .
operator as in:
t1.foo = 5;
When you want to access a variable of a struct in heap, you use the ->
operator, which is the same as *(t2).foo
, as in:
t2->foo = 5;
// the same as
*(t2).foo = 5;
We almost always use the arrow notation, because its cleaner and more readable. Here is a working example program of how you access variables in heap and stack inside structs stored in heap and stack:
#include <stdio.h>
#include <stdlib.h>
struct test
{
int foo;
int *bar;
int baz[20];
int *qux;
};
int main(int argc, char const *argv[])
{
// a test struct stored in stack
struct test t1;
// a test struct stored in heap
struct test *t2 = malloc(sizeof(struct test));
/**
* access the struct stored in stack
*/
// single variable in stack
t1.foo = 42;
// single variable in heap
t1.bar = malloc(sizeof(int));
*(t1.bar) = 50;
// array in stack
t1.baz[7] = 100;
// array in heap
t1.qux = malloc(20 * sizeof(int));
t1.qux[7] = 200;
/**
* access the struct stored in heap
*/
// single variable in stack
t2->foo = 42;
// single variable in heap
t2->bar = malloc(sizeof(int));
*(t2->bar) = 50;
// array in stack
t2->baz[7] = 100;
// array in heap
t2->qux = malloc(20 * sizeof(int));
t2->qux[7] = 200;
printf("%d\n", t1.foo);
printf("%d\n", t2->foo);
printf("%d\n", *(t1.bar));
printf("%d\n", *(t2->bar));
printf("%d\n", t1.baz[7]);
printf("%d\n", t2->baz[7]);
printf("%d\n", t1.qux[7]);
printf("%d\n", t2->qux[7]);
// never forget to free the memory you have allocated in the heap!
free(t1.bar);
free(t1.qux);
free(t2->bar);
free(t2->qux);
free(t2);
return 0;
}
with output:
42
42
50
50
100
100
200
200
Arrays of structs in stack and in heap
Here is also how to have an array of structs in stack and in heap and access them:
#include <stdio.h>
#include <stdlib.h>
struct test
{
int foo;
int *bar;
int baz[20];
int *qux;
};
int main(int argc, char const *argv[])
{
/**
* You can also have an array of structs in stack and in heap
*/
/**
* Array of structs in stack
*/
struct test t1[20];
// single variable in stack
t1[5].foo = 42;
// single variable in heap
t1[5].bar = malloc(sizeof(int));
*(t1[5].bar) = 50;
// array in stack
t1[5].baz[7] = 100;
// array in heap
t1[5].qux = malloc(20 * sizeof(int));
t1[5].qux[7] = 200;
/**
* Array of structs in heap
*/
struct test *t2 = malloc(20 * sizeof(struct test));
// single variable in stack
t2[5].foo = 42;
// single variable in heap
t2[5].bar = malloc(sizeof(int));
*(t2[5].bar) = 50;
// array in stack
t2[5].baz[7] = 100;
// array in heap
t2[5].qux = malloc(20 * sizeof(int));
t2[5].qux[7] = 200;
printf("%d\n", t1[5].foo);
printf("%d\n", t2[5].foo);
printf("%d\n", *(t1[5].bar));
printf("%d\n", *(t2[5].bar));
printf("%d\n", t1[5].baz[7]);
printf("%d\n", t2[5].baz[7]);
printf("%d\n", t1[5].qux[7]);
printf("%d\n", t2[5].qux[7]);
// never forget to free the memory you have allocated in the heap!
free(t1[5].bar);
free(t1[5].qux);
free(t2[5].bar);
free(t2[5].qux);
free(t2);
return 0;
}
with output:
42
42
50
50
100
100
200
200
I hope this answers your question, which from what I understand is in general about how you access variables inside structs in stack and in heap.
For any further questions, drop a comment bellow.
Happy coding! :)