My favorite:
#include <stdlib.h>
struct st *x = malloc(sizeof *x);
Note that:
xmust be a pointer- no cast is required
- include appropriate header
My favorite:
#include <stdlib.h>
struct st *x = malloc(sizeof *x);
Note that:
xmust be a pointer- no cast is required
- include appropriate header
You're not quite doing that right. struct st x is a structure, not a pointer. It's fine if you want to allocate one on the stack. For allocating on the heap, struct st * x = malloc(sizeof(struct st));.
memory management - malloc for struct and pointer in C - Stack Overflow
pointers - How do I define a struct and properly allocate memory for it in C? - Stack Overflow
C struct and memory allocation - Stack Overflow
How to correctly allocate memory for an array of structs in C? - Stack Overflow
Videos
Hi all! I am very new to C but am familiar with Python & Go quite a bit. Memory allocation is a new concept to me, but I want to start with best practices.
Lets say I want to create a struct that has some members, where one of them happens to be a pointer which I will size dynamically as an array.
Here is what I am doing in my init_my_struct(int n) function. I want to understand if I am doing something that is bad practice here
#include <stdlib.h>
#include <stdio.h>
struct my_struct {
int n;
int *my_arr; // this will be dynamically grown based on user arg
};
struct my_struct * init_my_struct(int n)
{
// allocate memory for one struct
struct my_struct *ms = malloc(sizeof(struct my_struct));
// use -> syntax since ms is a pointer
ms->n = n;
ms->my_arr = malloc(sizeof(int)*n);
return ms;
}
int main(int argc, char *argv[])
{
if (argc < 2) return 1;
int n = atoi(argv[1]);
// initialize the struct members
struct my_struct *ms = init_my_struct(n);
// check out contents of my struct
printf("my struct's n: %d\n", ms->n);
printf("my struct's my_arr: \n");
for (int i = 0; i < n; i++) {
printf("%d\n", ms->my_arr[i]);
}
free(ms); // clean up the memory
return 0;
}Any pointers or tips would be great! Thank you!
No, you're not allocating memory for y->x twice.
Instead, you're allocating memory for the structure (which includes a pointer) plus something for that pointer to point to.
Think of it this way:
1 2
+-----+ +------+
y------>| x------>| *x |
| n | +------+
+-----+
You actually need the two allocations (1 and 2) to store everything you need.
Additionally, your type should be struct Vector *y since it's a pointer, and you should never cast the return value from malloc in C.
It can hide certain problems you don't want hidden, and C is perfectly capable of implicitly converting the void* return value to any other pointer.
And, of course, you probably want to encapsulate the creation of these vectors to make management of them easier, such as with having the following in a header file vector.h:
#include <stddef.h>
struct Vector {
double *data; // Use readable names rather than x/n.
size_t size;
};
struct Vector *newVector(size_t sz);
void delVector(struct Vector *vector);
//void setVectorItem(struct Vector *vector, size_t idx, double val);
//double getVectorItem(struct Vector *vector, size_t idx);
Then, in vector.c, you have the actual functions for managing the vectors:
#include <stdlib.h>
#include "vector.h"
// Atomically allocate a two-layer object. Either both layers
// are allocated or neither is, simplifying memory checking.
struct Vector *newVector(size_t sz) {
// First, the vector layer.
struct Vector *vector = malloc(sizeof (struct Vector));
if (vector == NULL)
return NULL;
// Then data layer, freeing vector layer if fail.
vector->data = malloc(sz * sizeof (double));
if (vector->data == NULL) {
free(vector);
return NULL;
}
// Here, both layers worked. Set size and return.
vector->size = sz;
return vector;
}
void delVector(struct Vector *vector) {
// Can safely assume vector is NULL or fully built.
if (vector != NULL) {
free(vector->data);
free(vector);
}
}
By encapsulating the vector management like that, you ensure that vectors are either fully built or not built at all - there's no chance of them being half-built.
It also allows you to totally change the underlying data structures in future without affecting clients. For example:
- if you wanted to make them sparse arrays to trade off space for speed.
- if you wanted the data saved to persistent storage whenever changed.
- if you wished to ensure all vector elements were initialised to zero.
- if you wanted to separate the vector size from the vector capacity for efficiency(1).
You could also add more functionality such as safely setting or getting vector values (see commented code in the header), as the need arises.
For example, you could (as one option) silently ignore setting values outside the valid range and return zero if getting those values. Or you could raise an error of some description, or attempt to automatically expand the vector under the covers(1).
In terms of using the vectors, a simple example is something like the following (very basic) main.c
#include "vector.h"
int main(void) {
struct Vector *myvec = newVector(42);
myvec->data[0] = 2.718281828459;
delVector(myvec);
}
(1) That potential for an expandable vector bears further explanation.
Many vector implementations separate capacity from size. The former is how many elements you can use before a re-allocation is needed, the latter is the actual vector size (always <= the capacity).
When expanding, you want to generally expand in such a way that you're not doing it a lot, since it can be an expensive operation. For example, you could add 5% more than was strictly necessary so that, in a loop continuously adding one element, it doesn't have to re-allocate for every single item.
The first time around, you allocate memory for Vector, which means the variables x,n.
However x doesn't yet point to anything useful.
So that is why second allocation is needed as well.
Short answer: they are allocated with the order as they declared in the struct.
Example:
#include <stdio.h>
#include <string.h>
struct student
{
int id1;
int id2;
char a;
char b;
float percentage;
};
int main()
{
int i;
struct student record1 = {1, 2, 'A', 'B', 90.5};
printf("size of structure in bytes : %d\n",
sizeof(record1));
printf("\nAddress of id1 = %u", &record1.id1 );
printf("\nAddress of id2 = %u", &record1.id2 );
printf("\nAddress of a = %u", &record1.a );
printf("\nAddress of b = %u", &record1.b );
printf("\nAddress of percentage = %u",&record1.percentage);
return 0;
}
Output:
size of structure in bytes : 16
Address of id1 = 675376768
Address of id2 = 675376772
Address of a = 675376776
Address of b = 675376777
Address of percentage = 675376780
The pictorial representation of above structure memory allocation is given below. This diagram will help you to understand the memory allocation concept in C very easily.

Further reading: check out here (also the source for the above example) for C โ Structure Padding and Structure dynamic memory allocation in C.
You are guaranteed that field3 comes after field2, which comes after field1, and that field1 is at the start of the memory (i.e. there's no padding before field1). However, they may be padding in between the other members (and even after field3). In short, the order in which they are declared is the order in which they are laid out in memory, though exact alignment and padding is implementation defined (but there won't be any padding before the first member).