What does a function whose 'return type' is a tag do?

Viewed 82

I've been learning C for a month now and I've learned/remember that functions are defined like this:

return_type function_name( parameter list ) {
     ...body
}

But in a lecture about 'list ADTs' the example code which illustrates making and printing a full list there were some pieces of code(function declarations) in a form that I've never seen.

...
typedef struct list{ int data; struct list *next; } list;

list* create_list(int d) {
     ...
}

To my understanding the return type is ' list '(?) which is a structure tag, and the function name is ' * create_list ' (which is a dereferenced pointer??). I couldn't understand why it was written like that. I want to know how it works and how to use it. How does it differ from other (normal looking)functions like struct create_list(int d) {...}? The instructor didn't mention or explain about these so I'm quite confused.

here is the full code just in case

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

typedef struct list{ int data; struct list *next;} list;

int is_empty(const list *l) { return (l == NULL); }

list* create_list(int d) {
    list* head = malloc(sizeof(list));
    head -> data = d;
    head -> next = NULL;
    return head;
}
list* add_to_front(int d, list* h) {
    list* head = create_list(d);
    head -> next = h;
    return head;
}
list* array_to_list(int d[], int size) {
    list* head = create_list(d[0]);
    int i;
    for(i = 1;  i < size; i++) {
        head = add_to_front(d[i], head);
    }
    return head;
}

void print_list(list *h, char *title) {
    printf("%s\n", title);
    while (h != NULL) {
    printf ("%d :", h -> data);
    h = h -> next;
    }
}

int main() {
    list list_of_int;
    list* head = NULL;
    int data[6] = {2,3,5,7,8,9};
    head = array_to_list(data, 6);
    print_list(head, "single element list");
    printf("\n\n");
    return 0;
}

any help would be appreciated!

Please correct me if I'm wrong in some point. Thank you

2 Answers

You're close, but reading it wrong. Function names do not have things like * in them, only types do.

This defines a function that returns list* (a.k.a. struct list* which is what typedef establishes earlier) given argument d of type int:

list* create_list(int d) {
  // ...
}

In other words, create_list returns a pointer to list. In a type definition * means pointer, but it has a different meaning as an operator, such as:

int x = 0;
int* y = &x;

*y = 5; // Dereference y pointer, make assignment, in other words, assign to x

You can usually spot a dereference operator because it is not part of a type either in a return type specifier, an argument, or a variable declaration. In most other cases it's the dereference operator.

To my understanding the return type is ' list '(?) which is a structure tag

In your example list is both a struct tag and a typedef name. The name space rules of C allow four different categories of identifiers:

  • lables (for goto etc)
  • struct/union/enum tags (struct this_is_a_tag).
  • struct/union members
  • everything else

It's valid to name identifiers from these different name spaces the same.


In the example

typedef struct list{ int data; struct list *next;} list;

the typedef list identifier isn't available until at the end of the declaration (after the ;). The struct tag struct list is, however. So the struct list *next; member refers to the struct tag, which is a convenient way create a self-referencing struct. Once the typedef is declared, we can either use list to refer to the typedef:ed struct type, or we can use struct list which means the very same thing - when used outside the struct declaration it's just a style preference which form to use.

So list* create_list(int d) is using the typedef list to declare the return type of the function as a pointer to struct, list*. No different from returning any variable by value vs returning a pointer to it.

In this case the function is calling malloc to create a struct variable, so the function needs to return a pointer because anything allocated by malloc is always accessed through pointers.

Related