1

Let's say I have a struct that is a list such as

typedef struct mylist {
   int head;
   int tail;
   int size;
   buckets_t *bucketslots; 
} mylist_t;

and then

void create_list(mylist_t* list, int size) {
   list->head = 0;
   list->tail = 0;
   list->size = size;
   list->bucketslots = malloc(sizeof(bucket_t) * size);
}

Now, in my main method, if I perform:

mylist_t list1;
create_list(&list1, 1000);

Does the second to last line automatically malloc space for list1? Or, do I need to explicitly malloc space through

malloc(sizeof(mylist_t))

?

What I'd like to really know is if this is a valid procedure to make a struct of type mylist and start using it in main.

EDIT

It appears that C puts list1 on the stack when I declare the second to last line, but it does not go on the heap. If I want it on the heap, should I do the following? :

mylist_t* create_list(int size) {
   mylist_t list1 = malloc(sizeof(mylist_t));
   list->head = 0;
   list->tail = 0;
   list->size = size;
   list->bucketslots = malloc(sizeof(bucket_t) * size);
   return list1;
}

And then for calling the function:

create_list(1000);

With this, will I have access to list1 throughout the program?

3
  • the line mylist_t list1;, when in block scope, creates an object of type mylist_t with automatic storage duration. What is unclear about that? Commented Dec 5, 2015 at 21:01
  • Space for list1 was allocated when you declared it! Its not a pointer variable which needs to be assigned memory. Commented Dec 5, 2015 at 21:03
  • Sorry, I am pretty new to C. When you say storage duration, do you mean space in memory is automatically allocated? Is that space equivalent to sizeof(mylist_t)? Commented Dec 5, 2015 at 21:03

5 Answers 5

4

when you write

mylist_t list1;
create_list(&list1, 1000);

list1 is allocated on the stack, the struct contains a pointer. the members in the struct1 are not initialized.

the create_list function will allocate space for the pointer to point to and initialize the struct in general

heap always need to be explicitly allocated with malloc/calloc. stack on the other hand is automatic.

Sign up to request clarification or add additional context in comments.

3 Comments

Also tell the OP about the need to free heap allocated structures. He might think they are reclaimed automatically as in java.
So, if I want list1 on the heap, I should explicitly malloc. If I were to do this, should I remove the line "mylist_t list1;" and then add the malloc statement in create_list?
If you allocate list1 from the heap, you will change the definition to mylist_t *list1 = malloc(sizeof(*list1));. list1 will be a pointer to a mylist_t structure. You will still need to initialize this structure as malloc returns a block of uninitialized memory. You will do it this way: create_list(list1, 1000);. Note how list1 is a pointer, no longer the structure itself.
3

C will never implicitly malloc() anything.

In general, whenever you have a question of this sort, (until you become proficient enough with the language so as to stop even having questions of this sort,) remember that the philosophy of C is to never do anything behind your back, never do anything that you did not explicitly ask for.

Especially things that are not even part of the language, like memory allocation. In C, memory allocation is exclusively an issue of the runtime library. The language has no built-in knowledge of the concept of memory allocation.

3 Comments

"never do anything behind your back" except when it comes to the stack
@Rhymoid like what does it do with the stack?
Like storing local variables and call information in an undefined place (behind your back, IMO), which can lead to UB (e.g. stack overflows).
1

Your proposed alternative for create_list to allocate and initialize a structure is almost correct:

  • list1 should be defined as a pointer to mylist_t,
  • the allocation for the bucket pointers should use the size of a pointer to bucket_t instead of the size for the structure bucket_t,
  • you also need to initialize the array of bucket pointers.

Here is a modified version:

mylist_t  *create_list(int size) {
    mylist_t *list1 = malloc(sizeof(mylist_t));
    list->head = 0;
    list->tail = 0;
    list->size = size;
    list->bucketslots = malloc(sizeof(bucket_t*) * size);
    for (int i = 0; i < size; i++)
        list->bucketslots[i] = NULL;
    return list1;
}

Comments

1

Does the second to last line automatically malloc space for list1?

No. Generally a list is created by allocating space for a node, and then allocating space as required for each additional node added to the list. (regardless of whether the space is allocated dynamically or not)

create_list(&list1, 1000);

initializes head, tail and size values for list1 (a node of type mylist_t) and then dynamically allocates an array of type buckets_t with size elements for that node. If that is the entirety of your list1, then your list1 is allocated.

Comments

0

Two things you need to understand.

  • The scope of local variables
  • Global variables

When you declare a variable within any function or even within a chain-bracket statement block, that variable has no existence outside that block of code. You can use it as a parameter to other function calls, but if you try to reference it outside the statement block it is declared in, it is an error. These are local variables.

Variable declared inside a function are within the scope of that function only.

Global variables. You can declare a variable outside of any statement blocks or functions. It is global insofar as any function inside the same file can reference that variable.

Typically a compiler would allocate space for a local variable on the stack, although in practice a local variable might be kept in a register and never even stored in memory. These are details we leave to the compiler to sort out.

Sometimes people confuse "static" variables with "global variables". Static variables will not be "visible" by name outside the file you declare them in. Global variables can be visible, although you also need to declare them in a header file as "extern" to allow this.

One thing to note in C is that inside a chain bracket statement block you can reuse variable names declared outside the block. The one that is declared in the level closest to one you're at is the one that takes precedence.

In C this is perfectly valid and all the following variables are different :

void myfunc( int n )
{
    if( n == 1 )
    {
        int n = 35 ;

        /* This will print 35 */
        printf( "n = %d\n", n ) ;
    }
    else
    {
        int n = 45 ;

        /* This n variable has a value of 45 */
        printf( "n = %d\n", n ) ;
    }

    /* but no matter what we did inside the if statements
     * the n variable at this stage refers to the original one !
     *
     * So this printf will show the original value.
     */

    printf( "n = %d\n", n ) ;
}

I mention this because an increasing number of programmers start on Java, where this would be illegal ( alas ) and find it confusing. It is extremely useful, especially in macros.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.