In this function,

void
allocateMem(struct myStruct *struct1)
{
    struct1 = malloc(sizeof(struct myStruct));
    struct1->number = 500;
    printf("struct1->number: %d\n", struct1->number);
}

struct1 is passed by value. Any changes you make to it in the function are not visible from the calling function.

A better alternative:

struct myStruct* allocateMem()
{
    struct myStruct *struct1 = malloc(sizeof(struct myStruct));
    struct1->number = 500;
    printf("struct1->number: %d\n", struct1->number);
    return struct1;
}

Change the calling function to:

int
main(int argc, char *argv[])
{
    struct myStruct *struct1 = allocateMem();
    printf("number: %d\n", struct1->number);

    // Make sure to free the memory.
    free(struct1);

    return 0;
}
Answer from R Sahu on Stack Overflow
Top answer
1 of 3
12

In this function,

void
allocateMem(struct myStruct *struct1)
{
    struct1 = malloc(sizeof(struct myStruct));
    struct1->number = 500;
    printf("struct1->number: %d\n", struct1->number);
}

struct1 is passed by value. Any changes you make to it in the function are not visible from the calling function.

A better alternative:

struct myStruct* allocateMem()
{
    struct myStruct *struct1 = malloc(sizeof(struct myStruct));
    struct1->number = 500;
    printf("struct1->number: %d\n", struct1->number);
    return struct1;
}

Change the calling function to:

int
main(int argc, char *argv[])
{
    struct myStruct *struct1 = allocateMem();
    printf("number: %d\n", struct1->number);

    // Make sure to free the memory.
    free(struct1);

    return 0;
}
2 of 3
5

A pointer is just an integer in reality, when you pass in struct1 to your function since struct1 is null you are just passing in a 0 to your function in reality. that value gets passed on the stack and you do a heap allocation and update the stack value with the new address. but when you return from the function, that value just gets popped of the stack and you have leaked that memory. the value of struct1 in main (which is also on the stack still keeps its value 0(NULL). so you have to pass in a pointer to your pointer if you want to update that value, or what might be easier is just to return the malloc'd pointer from your function.

This is one way you could modify your function to work:

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

struct myStruct
{
    int number;
};

struct myStruct*
allocateMem()
{
    struct myStruct* struct1 = malloc(sizeof(struct myStruct));
    struct1->number = 500;
    printf("struct1->number: %d\n", struct1->number);
    return struct1;
}

int
main(int argc, char *argv[])
{
    struct myStruct *struct1 = allocateMem();
    printf("number: %d\n", struct1->number);
    return 0;
}
๐ŸŒ
Reddit
reddit.com โ€บ r/learnprogramming โ€บ why do structs need to be created on the heap in c or generally ?
r/learnprogramming on Reddit: Why do structs need to be created on the heap in C or generally ?
January 10, 2022 -

Why is it so important to create space with malloc for structs so the struct will be on the heap. Why cant the struct be created without malloc and stay on the stack ? We are being thought this concept in school, but i dont understand why.

// A simple C program for traversal of a linked list
#include <stdio.h>
#include <stdlib.h>

struct Node {
	int data;
	struct Node* next;
};

// This function prints contents of linked list starting from
// the given node
void printList(struct Node* n)
{
	while (n != NULL) {
		printf(" %d ", n->data);
		n = n->next;
	}
}

int main()
{
	struct Node* head = NULL;
	struct Node* second = NULL;
	struct Node* third = NULL;

	// allocate 3 nodes in the heap
	head = (struct Node*)malloc(sizeof(struct Node));
	second = (struct Node*)malloc(sizeof(struct Node));
	third = (struct Node*)malloc(sizeof(struct Node));

	head->data = 1; // assign data in first node
	head->next = second; // Link first node with second

	second->data = 2; // assign data to second node
	second->next = third;

	third->data = 3; // assign data to third node
	third->next = NULL;

	printList(head);

	return 0;
}
๐ŸŒ
Quora
quora.com โ€บ How-do-you-allocate-memory-for-a-struct-on-the-heap-in-C-Whats-the-difference-between-allocating-space-with-new-and-malloc
How to allocate memory for a struct on the heap in C++? What's the difference between allocating space with new and malloc - Quora
Answer (1 of 3): If you can use operator new instead of malloc, do it. malloc and free are for C code compatibility, and while not deprecated, they do not have the internal code to understand objects. malloc is a byte-oriented C function that returns raw bytes of contiguous uninitialized memory,...
๐ŸŒ
Brown University
cs.brown.edu โ€บ courses โ€บ csci1310 โ€บ 2020 โ€บ notes โ€บ l05.html
CS 131/CSCI 1310: Fundamentals of Computer Systems
There are several ways to obtain memory for an instance of your struct in C: using a global, static-lifetime struct, stack-allocating a local struct with automatic lifetime, or heap-allocating dynamic-lifetime memory to hold the struct.
๐ŸŒ
Reddit
reddit.com โ€บ r/c_programming โ€บ is it better to allocate a structs on the stack or on the heap?
r/C_Programming on Reddit: Is it better to allocate a structs on the stack or on the heap?
July 29, 2022 -

I just defined a new struct type typedef struct graph_struct {} struct; and I need to make one of them in my main function. There are two options for a constructor:

  1. Declare a graph in main(), and pass its address to the constructor. Return nothing.

  2. Pass nothing to the constructor, malloc a graph inside of it, and return a pointer to the graph.

I prefer 2), but I think that memory on the heap is slower to work with than memory on the stack. And my program does need to be really fast.

Is there any reason to prefer one over the other?

Top answer
1 of 1
8

If you're just using a simple struct, you don't need more memory allocated for it as time goes on. You just create the struct, use it, and clean it up if required. If you are dynamically allocating your struct (ie: with malloc), then you test the value of the pointer-to-struct you create and see if it is NULL. If it is NULL, then the memory allocation failed, and you can either retry, or abandon further operations (ie: exit on error condition).

#include <stdio.h>

typedef struct myStruct {
  int i;
  char c;
} myStruct;

int main(void) {
  // Static allocation, no cleanup required
  myStruct staticStruct;
  staticStruct.i = 0;
  staticStruct.c = 'c';

  // Dynamic allocation, requires cleanup
  myStruct* dynamicStruct;
  dynamicStruct = malloc(sizeof(myStruct));
  if (dynamicStruct == NULL) {
    printf("Memory allocation error!\n");
    return (-1);
  } else {
    printf("Successfully allocated memory!\n");
  }

  dynamicStruct->i = 1;
  dynamicStruct->c = 'd';
  free(dynamicStruct);  // Release allocated memory
  dynamicStruct = NULL; // Somewhat common practise, though not 100% necessary
  return 0;
}

Now, if you need to create an array of dynamically allocated structs, and you've used them all up, and need more, you'd likely be best off with a slightly more complicated approach, like a dynamically allocated linked list of structs. A good example can be found in the "References" section below. Also, I've included a link to a somewhat related question I answered on memory allocation in C. It has some good examples that might also help clear up this topic for you.

References


  1. C Linked List Data Structure Explained with an Example C Program, Accessed 2014-03-25, <http://www.thegeekstuff.com/2012/08/c-linked-list-example/>
  2. Difference between declared string and allocated string, Accessed 2014-03-25, <https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string>
๐ŸŒ
Delft Stack
delftstack.com โ€บ home โ€บ howto โ€บ c malloc struct
How to Allocate Struct Memory With malloc in C | Delft Stack
February 12, 2024 - The program demonstrates controlled ... and deallocation functions. calloc is a function in the C programming language used for dynamically allocating memory from the heap during runtime....
Find elsewhere
๐ŸŒ
University of Central Florida
cs.ucf.edu โ€บ courses โ€บ cop3502h โ€บ spring2012 โ€บ Lectures โ€บ heap.c
heap.c
h = (struct heapStruct*)(malloc(sizeof(struct heapStruct))); h->capacity = SIZE; h->heaparray = (int*)malloc(sizeof(int)*(SIZE+1)); h->size = 0; return h; } // Frees the struct pointed to by h. void freeHeap(struct heapStruct *h) { free(h->heaparray); free(h); } // Initializes the heap using the first length number of items in the array // values. struct heapStruct * initHeapfromArray(int* values, int length) { int i; struct heapStruct* h; h = (struct heapStruct*)(malloc(sizeof(struct heapStruct))); // We allocate one extra slot, since slot 0 stays unused. h->heaparray = (int*)malloc(sizeof(int)*(length+1)); // Just copy the values into our array.
Top answer
1 of 2
7
struct USER {
   int human_id_number;
   char first_name_letter;
   int minutes_since_sneezing;
} *administrator;

This isn't just a struct declaration, it's also a variable declaration... it's the same as:

struct USER {
   int human_id_number;
   char first_name_letter;
   int minutes_since_sneezing;
};

struct USER *administrator;

So, when you subsequently use sizeof(administrator), you'll get "the size of a pointer"... which is most likely not what you want.

You probably wanted to do something more like this:

struct USER {
   int human_id_number;
   char first_name_letter;
   int minutes_since_sneezing;
};

int main(void) {
    struct USER *administrator;

    administrator = malloc(sizeof(*administrator));
    /* - or - */
    administrator = malloc(sizeof(struct USER));

    /* check that some memory was actually allocated */
    if (administrator == NULL) {
        fprintf(stderr, "Error: malloc() returned NULL...\n");
        return 1;
    }

    /* ... */

    /* don't forget to free! */
    free(administrator)

    return 0;
}

sizeof(*administrator) and sizeof(struct USER) will both give you "the size of the USER structure", and thus, the result of malloc() will be a pointer to enough memory to hold the structure's data.

2 of 2
0
struct USER{
    int human_id_number;
    char first_name_letter;
    int minutes_since_sneezing;
} *administrator;

This defines administrator as a pointer variable. But, from the other code

administrator *newStruct = (administor*)malloc(sizeof(administrator));

It seems you want to use that as a type. To do so, you can make use of the typedef.

typedef struct USER{
    int human_id_number;
    char first_name_letter;
    int minutes_since_sneezing;
} administrator;

and then use

administrator *newStruct = (administrator *)malloc(sizeof(administrator));
๐ŸŒ
DEV Community
dev.to โ€บ davidhwangij โ€บ 5-25-til-c-basics-heap-memory-referencing-pointer-to-struct-1edo
5/25 TIL: C++ basics (heap memory, referencing, pointer to struct) - DEV Community
May 26, 2021 - You must delete (release/de-allocate) the memory in whenever you are dynamically allocating memory Ex) free(p) in C and delete [] p in C++ where p is an array ยท // allocates 20 bytes (5 * 4) of heap memory holding an int and assign that pointer to p p = (int *)malloc(5 * sizeof(int)); free(p); // C++ p = new int[5]; delete [] p;
๐ŸŒ
Reddit
reddit.com โ€บ r/c_programming โ€บ why are structs frequently heap allocated unnecessarily?
Why are structs frequently heap allocated unnecessarily? : r/C_Programming
March 23, 2021 - You can now malloc or alloca struct foo arrays even if struct foo is opaque. You only need an init function, which you already have if it's opaque.
Top answer
1 of 5
8

In this case, however, is it possible to create a new instance of this struct on the heap, or would I need to define a constructor? Is there a way to create things on the heap without the new operator?

As answered before, you can create a new instance on the heap either via new or with malloc.

Or, better yet: is it unnecessary for me to cling so tightly to the notion that I shouldn't define member functions for structs?

This is the more interesting question. The major (only?) difference between struct and class in c++ is the default access specifier. That is, struct defaults to public access and class defaults to private. In my opinion, this is the difference that should determine which of the two you use. Basically, if users should access the members directly, then it should be a struct.

If, for example, you have no member functions, then obviously the intention is for the object's members to be accessed directly and so it would be a struct. In the case of an object that is just a small private helper for the implementation of its outer class, as in your example, then even if it has member functions it is often clearest to allow the outer class access to its members and so it should be a struct. Often with these classes the implementation of the outer class is tightly coupled to the implementation of the inner class and so there is no reason to hide the one from the other.

So, for trivial (e.g. std::pair) objects or those whose use is limited (as in a private inner class) default access to members can be a good thing, and in these cases I would make them structs.

2 of 5
6

Even if you don't define a constructor, the compiler will create a default one and so you can use operator 'new':

Node *n = new Node;

AFAIAC, a struct is a class, except that its "publicness" default is reversed.

๐ŸŒ
Quora
quora.com โ€บ How-would-I-dynamically-allocate-a-struct-in-the-main-of-my-program
How would I dynamically allocate a struct in the main of my program? - Quora
Answer (1 of 2): Traditionally, in C youโ€™d use malloc(). This is a common pattern, where you define a named type for the struct (together with the type as a pointer to the struct), and then in your main() you use malloc() to allocate memory ...
Top answer
1 of 4
10

Yes, you've created a struct on the heap. You haven't populated it correctly, and you are going to face problems deleting it - I'm not sure whether the homework covered that or not. As it stands, you're more likely to get memory corruption or, if you're lucky, a memory leak than to release one of these strings.

Code that works with standard C89 and C99

Your code, somewhat fixed up...

typedef 
struct String {
    int length;
    int capacity;
    char *ptr;
} String;

char* modelstrdup(char* src){
    int length = strlen(src);
    char *space = malloc(sizeof(String) + length + 1);
    //String *string = space;  // Original code - compilers are not keen on it
    String *string = (String *)space;
    assert(space != 0);
    string->ptr = space + sizeof(String);  // or sizeof(*string)
    string->length = length;
    string->capacity = length + 1;
    strcpy(string->ptr, src);
    return string->ptr;
}

This code will work in C89 as well as C99 (except for the C99/C++ comments). You can probably optimize it to work with the 'struct hack' (saves a pointer in the structure - but only if you have a C99 compiler). The assert is sub-optimal error handling. The code doesn't defend itself against a null pointer for input. In this context, neither the length nor the capacity provides any benefit - there must be other functions in the suite that will be able to make use of that information.

As already intimated, you are going to face problems deleting the string structure when the value handed back is not a pointer to the string. You have some delicate pointer adjustments to make.


Code that works with standard C99 only

In C99, section 6.7.2.1 paragraph 16 describes 'flexible array members':

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. With two exceptions, the flexible array member is ignored. First, the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length.106) Second, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.

106 The length is unspecified to allow for the fact that implementations may give array members different alignments according to their lengths.

Using a 'flexible array member', your code could become:

typedef 
struct String {
    int length;
    int capacity;
    char ptr[];
} String;

char* modelstrdup(char* src){
    int length = strlen(src);
    String *string = malloc(sizeof(String) + length + 1);
    assert(string != 0);
    string->length = length;
    string->capacity = length + 1;
    strcpy(string->ptr, src);
    return string->ptr;
}

This code was accepted as clean by GCC 4.0.1 apart from a declaration for the function (options -Wall -Wextra). The previous code needs a cast on 'String *string = (String *)space;' to tell the compiler I meant what I said; I've now fixed that and left a comment to show the original.


Using the 'struct hack'

Before C99, people often used the 'struct hack' to handle this. It is very similar to the code shown in the question, except the dimension of the array is 1, not 0. Standard C does not allow array dimensions of size zero.

typedef struct String {
    size_t length;
    size_t capacity;
    char ptr[1];
} String;

char* modelstrdup(char* src)
{
    size_t length = strlen(src);
    String *string = malloc(sizeof(String) + length + 1);
    assert(string != 0);
    string->length = length;
    string->capacity = length + 1;
    strcpy(string->ptr, src);
    return string->ptr;
}

Code that uses a GCC non-standard extension to C89 and C99

The zero-size array notation is accepted by GCC unless you poke it hard - specify the ISO C standard and request pedantic accuracy. This code, therefore, compiles OK unless you get to use gcc -Wall -Wextra -std=c99 -pedantic:

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

typedef
struct String {
    int length;
    int capacity;
    char ptr[0];
} String;

char* modelstrdup(char* src){
    int length = strlen(src);
    String *string = malloc(sizeof(String) + length + 1);
    assert(string != 0);
    string->length = length;
    string->capacity = length + 1;
    strcpy(string->ptr, src);
    return string->ptr;
}

However, you should not be being trained in non-standard extensions to the C language before you have a thorough grasp of the basics of standard C. That is simply unfair to you; you can't tell whether what you're being told to do is sensible, but your tutors should not be misguiding you by forcing you to use non-standard stuff. Even if they alerted you to the fact that it is non-standard, it is not fair to you. C is hard enough to learn without learning tricksy stuff that is somewhat compiler specific.

2 of 4
2

You have allocated some memory on the heap, but you're not using it as if it were your structure. The string variable in your function is of type char *, not of type struct String. I think you're duplicating the functionality of strdup() reasonably enough, but I don't understand the reason for the structure.

Note: You should probably check your call to malloc() for failure, and return appropriately. The man page for strdup() should explains exactly what your function should be doing.

๐ŸŒ
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...
๐ŸŒ
University of Toronto
cs.toronto.edu โ€บ ~heap โ€บ 270F02 โ€บ node31.html
But first, structs and malloc
n1 = (struct node *) malloc(sizeof(struct node)); n2 = (struct node *) malloc(sizeof(struct node)); n3 = (struct node *) malloc(sizeof(struct node)); head = n1; n1->data = 1; n1->next = n2; n2->data = 2; n2->next = n3; n3->data = 3; n3->next = NULL; /* <-- indicates end of list */ malloc allocates sizeof(struct node) bytes, and returns a void pointer to it, which we cast to struct node *. Under some conditions malloc could fail to allocate the required space, in which case it returns the special address NULL. We don't check for (nor act on) this possibility, but in A2 emalloc does.