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.

Answer from paxdiablo on Stack Overflow
Top answer
1 of 8
198

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.

2 of 8
5

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.

Discussions

Allocate memory for a struct with a character pointer in C - Stack Overflow
Of course, you should also add ... when you deal with strings. So if you say that no string can be longer then i.e. 50+1, an array is easier to maintain. ... When you allocate memory for structptr, the pointer word in the struct has no valid memory to point.... More on stackoverflow.com
🌐 stackoverflow.com
April 25, 2017
c - Structs, pointers and memory allocation - Stack Overflow
typedef struct { int * nr; char *nume, **mesaj; } utilizator; If you only want one int, don't call malloc. It will be allocated as part of your utilizator object (funny word btw). ... I want it to be just an int. I dont have to allocate memory for it? More on stackoverflow.com
🌐 stackoverflow.com
c - Allocating memory to a struct using pointers - Stack Overflow
So if both point to the same location, ... with allocated memory ? 2015-08-19T16:02:04.973Z+00:00 ... Eugene Sh. Over a year ago · At the first hand both k and l are variables. If you are assigning them a value, they will retain it unless you reassign it either directly, or by dereferencing a pointer to them, not the pointer having the same value. 2015-08-19T16:03:42.437Z+00:00 ... @Eugene_Sh. Am I understanding it correctly: struct node *l is ... More on stackoverflow.com
🌐 stackoverflow.com
Best practice on allocating memory for a struct that has dynamic array members
Right now, the for loop is always printing the same value. You also need to free(ms->my_arr); Every malloc will have a corresponding free. More on reddit.com
🌐 r/C_Programming
21
3
February 29, 2024
🌐
Programiz
programiz.com › c-programming › c-structures-pointers
C structs and Pointers (With Examples)
To allocate the memory for n number of struct person, we used, ptr = (struct person*) malloc(n * sizeof(struct person)); Then, we used the ptr pointer to access elements of person.
🌐
Cprogramming
cboard.cprogramming.com › c-programming › 66209-struct-pointer-memory-allocation.html
Struct/pointer/memory allocation
As someone has already mentioned, you need to pass a pointer to a pointer to the structure in your malloc_mystruct() functions argument to accomplish what you want to do. Here's how it can be done: ... Last edited by xeddiex; 06-03-2005 at 12:03 PM. ... Thanks for the replies and the help!
🌐
Learn C
learn-c.org › en › Dynamic_allocation
Dynamic allocation - Learn C - Free Interactive C Tutorial
This tells the compiler that we ... a pointer of type person to the newly allocated data. The memory allocation function malloc() reserves the specified memory space....
🌐
TutorialsPoint
tutorialspoint.com › explain-the-dynamic-memory-allocation-of-pointer-to-structure-in-c-language
Explain the dynamic memory allocation of pointer to structure in C language
#include <stdio.h> #include <stdlib.h> ... of persons: "); scanf("%d", &n); // allocating memory for n numbers of struct person ptr = (struct person*) malloc(n * sizeof(struct person)); for(i = 0; i < n; ++i){ printf("Enter name and age respectively: "); // To access members of ...
Find elsewhere
🌐
Swarthmore College
cs.swarthmore.edu › ~newhall › cs31 › resources › C-structs_pointers.php
CS31: Intro to C Structs and Pointers
Dynamic Memory Allocation A common uses of pointer variables is to use them to point to memory that your program allocates at runtime. This is very useful for writing programs where the size of an array or other data structure is not know until runtime, or that may grow or shrink over the lifetime of a run of a program.
🌐
Delft Stack
delftstack.com › home › howto › c malloc struct
How to Allocate Struct Memory With malloc in C | Delft Stack
February 12, 2024 - To allocate the memory of the custom struct object that has been defined, we should call the sizeof operator and retrieve the amount of memory the object needs to be stored. ... void*: It returns a void pointer (void*) that can be implicitly ...
🌐
Reddit
reddit.com › r/c_programming › best practice on allocating memory for a struct that has dynamic array members
r/C_Programming on Reddit: Best practice on allocating memory for a struct that has dynamic array members
February 29, 2024 -

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!

🌐
Dartmouth College
cs.dartmouth.edu › ~campbell › cs50 › dynamicmem.html
Pointers and Dynamic Memory Allocation
Note:Unlike Java, C has no garbage collection of heap objects, and so programs must be very careful about deallocating memory that is no longer required. The memory management functions use “pointer to void” (void *) which allows the programmer to assign the returned pointer to memory to ...
🌐
W3Schools
w3schools.com › c › c_memory_struct.php
C Structures and Dynamic Memory
You can use the malloc() function to allocate memory for a struct pointer:
🌐
Quora
quora.com › When-I-declare-a-struct-in-C-does-it-automatically-allocate-memory-for-me-using-malloc
When I declare a struct in C, does it automatically allocate memory for me using malloc()? - Quora
Answer (1 of 13): First, a general principle: no matter what you do, [code ]malloc()[/code] is never invoked automagically. When you declare a [code ]struct[/code], you declare a type. A type, by itself, consumes no memory at runtime. When you declare a variable of the struct type, memory is al...
Top answer
1 of 3
1

If you insist on passing the pointer, it should be by reference, so it's a pointer to a pointer, as the function itslef will modify the address in the pointer.

You're much better off if your function returns a pointer.

//function for allocating the memory
myName *structMemInit(void)
{
    myName *myNameIs = (myName *)calloc(1, sizeof(myName));
    if (myNameIs == NULL) {
        printf("allocating memory didn't work!\n");
        exit(1);
    } else {                     // don't repeat the negation of the condition
        myNameIs->name = "Zach"; // No need for \0, it's automatic
        return myNameIs;
    }
}

//Usage
myName *myNameIs = structMemInit();

BTW it's int main(void) not int main().

2 of 3
1

Before I answer, I should state that I am not too well-versed in C, I am a C++ programmer so there may be a few grammatical errors in what follows. Hopefully though, my point will be made sufficiently for any errors to be of much importance.

The reason you're getting segfault is because of your misunderstanding of what's happening when you pass a pointer as an argument to a function.

Imagine, for instance, your program was the following:

int main(void){
    int i;

    setInteger(i);

    printf("%d\n", i);

    return 0;
}

void setInteger(int n){
    n = 12;
}

In this case, you can clearly see that the output will be undefined because the variable i was not initialised, and was passed by-value to setInteger. Any changes to n are not transferred back to i when the function returns.

If the program were replaced with

int main(void){
    int i;

    setInteger(&i);

    printf("%d\n", i);

    return 0;
}

void setInteger(int *n){
    *n = 12;
}

Then the value output by i will be 12.

The same thing is happening in your program, you're passing your pointer by value.

If you want to pass by reference, you need to do the following:

int main(void){

    myName *myNameIs;

    structMemInit(&myNameIs); // pass the address of your pointer

    printf("%s\n", myNameIs->name);

    return 0;
}

//function for allocating the memory
void structMemInit(myName **myNameIs){ // argument is pointer-to-pointer 
    *myNameIs = (myName *) calloc(1, sizeof(myName)); // dereference pointer to get underlying pointer
    if(*myNameIs == NULL){
        printf("allocating memory didn't work!\n");
        exit(1);
    }
    else{
        *myNameIs->name = "Zach";
    }

}

That's, unfortunately, not the end of your problems. Although you've allocated memory to your myName object, you have not allocated memory to your character array.

To return the string "Zach", you need to do the following:

*myNameIs->name = (char*)malloc(5*sizeof(char)); // need extra char for \0
strcpy(*myNameIs->name, "Zach");
Top answer
1 of 1
4

To dynamically allocate memory for a struct, the following can be used:

TCarro *carVariable=malloc(sizeof(TCarro)*someNumbers);

, where someNumbers are the number of elements you want to allocate.

From the error you posted in the comment, I assume you tried doing something like:

printf("%d",carVariable);

As you have specified the integer specifier in printf (%d), the compiler expects the function to receive an integer, but you give it a struct TCarro instead.

So now you may be wondering, what specifier can I use to print my carVariable?

C, actually, does not offer such specifier, because structs are types created by the programmer, so it has no idea of how to print it.

What you could do, if you wanted to print your variable would be to print each individual elements of the array.

Something like this:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

typedef struct{
  char nome[20];
  char placaDoCarro[5];
}TCarro;

int main(void){
  size_t someNumbers=10; //if you want to allocate 10 cars
  TCarro *carVariable=malloc(sizeof(TCarro)*someNumbers);
  //notice that struct before TCarro is not needed, as you defined it as an existing type (named TCarro)

  strcpy(carVariable[0].nome,"Mercedes");
  strcpy(carVariable[0].placaDoCarro,"xxxx");

  strcpy(carVariable[1].nome,"Ford");
  strcpy(carVariable[1].placaDoCarro,"xxxx");
 
  //printf cars
  printf("%s %s\n",carVariable[0].nome, carVariable[0].placaDoCarro);
  printf("%s %s\n",carVariable[1].nome, carVariable[1].placaDoCarro);

  free(carVariable);
  return 0;
}

Notice that I used strcpy, because I needed to copy a string to each field of the struct.