0

Let's take the following basic program which creates a single item for a linked list of Movies:

#include <stdio.h>
#include <stdlib.h>
#define TLEN 45

struct film {
    char title[TLEN];
    int rating;
};
typedef struct film Item;

typedef struct node {
    Item        item;
    struct node *next;
} Node, *List;

int main(void) 
{
    Item avatar = {"Avatar", 7};
    List movies = malloc(sizeof(Item));
    movies->item = avatar;
    printf("Movie: %s\n", movies->item.title);
}

In the above, I create a new movie by doing:

List movies = malloc(sizeof(Item));

Would it be possible to add this struct film item directly on the stack without using a malloc? This is mainly for educational/academic purposes, but I'm wondering if I can do something along the lines of:

int main(void) 
{
    Item avatar = {"Avatar", 7};
    List movies; // possible to add to stack instead? = malloc(sizeof(Item)); 
    movies->item = avatar;
    printf("Movie: %s\n", movies->item.title);
}

Update: it seems I can do it by declaring a normal (non-pointer) struct:

Node movies2;
movies2.item = avatar;
printf("Movie: %s\n", movies->item.title);

Is that the only way to do this? I know this is stupid, but in an academic sense, can I have the pointer on the stack, refer to a(nother) non-pointer struct on the stack?

David542
  • 104,438
  • 178
  • 489
  • 842
  • 2
    (1) Your malloc call is actually incorrect, as you're only allocating enough storage for `Item`, where you actually are wanting `sizeof(Node)`; (2) Your next example with `List movies;` has undefined behavior because `movies` is an uninitialized pointer and you use it before giving it a value; (3) Your second example is fine (apart from the printf call which is unrelated to the example), and it's unclear what your problem is... Perhaps you want to directly initialize the item inside the struct without copying the other one in. In that case, try `Node movies2 = { {"Avatar", 7}, NULL };` – paddy Mar 09 '21 at 02:59
  • 1
    And yes, you can have a pointer on the stack that points to something else on the stack... – paddy Mar 09 '21 at 03:01
  • If you really want to use stack based objects and access them as a list: https://onlinegdb.com/BL02H5LfK - that's a bunch of individual nodes on the stack but it is a lot cleaner looking to have an array of nodes: https://onlinegdb.com/PmECuOyfK – Jerry Jeremiah Mar 09 '21 at 04:04
  • regarding: `typedef struct node { Item item; struct node *next; } Node, *List;` it is a very poor programming practice to declare a pointer type in a `typedef` – user3629249 Mar 10 '21 at 07:42

3 Answers3

2

I suspect you are looking for something like:

#include <stdio.h>
#include <stdlib.h>
#define TLEN 45

typedef struct film {
        char title[TLEN];
        int rating;
} Item;

typedef struct node {
        Item item;
        struct node *next;
} Node;

int main(void)
{
        Item avatar = { "Avatar", 7 };
        Node k = { { "Blues Bros", 8 }, NULL };
        Node m[] = {
                { avatar, m + 1 },
                { { "Star Wars", 10 }, m + 2 },
                { { "Empire", 10 }, m + 3 },
                { { "Phantom Menace", -437 }, &k }
        };
        for( Node *n = m; n; n = n->next ){
                printf("Movie: %s\n", n->item.title);
        }
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300
1

"Can a struct be on the stack?" Certainly – if it is a local variable to a currently-active function. But you will observe that this is rarely done, because "stack space" is very often limited, while "heap space" is not.

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
  • 1
    Another reason is that stack space is reclaimed when the function returns, heap space is persistent for the duration of the program. – mhawke Mar 09 '21 at 03:40
0

If you plan to do some dynamic allocation in the stack, you can consider using alloca():

The alloca() function allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed when the function that called alloca() returns to its caller.

For educational/academic purposes, keep in mind the limitations pointed out in the manual and this discussion.

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

#define TLEN 45

struct film {
    char title[TLEN];
    int rating;
};
typedef struct film Item;

typedef struct node {
    Item        item;
    struct node *next;
} Node, *List;

int main(void) 
{
  List movies;
  Node *node;

  node = alloca(sizeof(Node));
  snprintf(node->item.title, TLEN, "Avatar");
  node->item.rating = 7;

  movies = node;

  node->next = alloca(sizeof(Node));
  node = node->next;
  snprintf(node->item.title, TLEN, "River of no return");
  node->item.rating = 10;

  node->next = alloca(sizeof(Node));
  node = node->next;
  snprintf(node->item.title, TLEN, "Breakfast at Tiffany's");
  node->item.rating = 10;

  node->next = NULL;

  node = movies;
  while(node) {
    printf("Movie: '%s', rating: %d\n", node->item.title, node->item.rating);
    node = node->next;
  }  

  return 0;
}

Build/execution:

$ gcc stkalloc.c
$ ./a.out 
Movie: 'Avatar', rating: 7
Movie: 'River of no return', rating: 10
Movie: 'Breakfast at Tiffany's', rating: 10
Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • thanks, could you please show an example of how it would be done in the above case? – David542 Mar 09 '21 at 07:32
  • I updated my answer with an example program – Rachid K. Mar 09 '21 at 11:19
  • got it. Are there any valid uses of `alloca` -- or is this almost never used in production code? – David542 Mar 09 '21 at 19:58
  • 1
    It is used in production code. As lots of things, you must use them with care as the allocated resources are ephemeral since when you return from the functions where the allocation occured, the allocated data (being in the stack) are no longer available. The [discussion](https://stackoverflow.com/q/1018853/14393739) mentioned in the answer provides some pros&cons. – Rachid K. Mar 09 '21 at 20:02