Initialize recursive struct type in C properly

2019-09-20 12:09发布

问题:

I am new to C programming and I have the following struct:

typedef struct _date {
    char d[10], t[5], s[3];
    struct _date *next;
} *date;

How can I properly create an instance of this?

My solution:

date neuerTermin(char *d, char *t, char *s, date cal) {
    struct _date d = {*d, *t, *s, NULL};
    date d_ptr = malloc(sizeof *d);
    cal->next = d_ptr;

    return d;
}

But I get an error: warning: initialization makes integer from pointer without a cast

回答1:

You can do it as follows:

#include <stdio.h>

typedef struct _date {
    char d[11], t[6], s[4]; // +1 to size for null-terminator ('\0')
    struct _date *next;
} *date;


int main() {
    struct _date a = { "15.07.2017", "16:00", "Foo", NULL };
    date a_ptr = &a;

    printf("Description: %s\nDate: %s\nTime: %s\n", a_ptr->s, a_ptr->d, a_ptr->t);
    return 0;
}

The brace-enclosed, comma-separated list in the example above is the struct initializer.


To respond to the edits of your question, if you wish to dynamically allocate struct _date instances and initialize them in a function, then use malloc as follows:

date neuerTermin(const char* d, const char* t, const char* s) {
    date cal = (date)malloc(sizeof(struct _date));

    strncpy(cal->d, d, 10);
    strncpy(cal->t, t, 5);
    strncpy(cal->s, s, 3);
    cal->next = NULL;

    return cal;
}

In this case you have to fill the memory block pointed by cal member-by-member. Sample usage:

date root = neuerTermin("15.07.2017", "16:00", "Foo");
root->next = neuerTermin("27.07.2017", "10:00", "Bar");
root->next->next = neuerTermin("01.08.2017", "12:30", "Baz");

Important: if you used malloc to allocate memory, you have to deallocate it too with using free when you don't need it anymore.



回答2:

While Akira has a very good answer for you (I voted for it), I would caution you about typedeffing pointers. Why? As your projects grow, when you start hiding levels of indirection behind a typedef, the level of confusion and potential for error grows.

If you need a pointer of a typedeffed type, declare an instance of one, but keep your typedefs to types so an not to mask levels of indirection.

You can do the same thing without hiding the level of indirection as follows:

#include <stdio.h>

typedef struct _date {
    char d[11], t[6], s[4]; // +1 for '\0'
    struct _date *next;
} date;


int main() {
    date a = { "15.07.2017", "16:00", "Foo", NULL };
    date *a_ptr = &a;

    printf("Description: %s\nDate: %s\nTime: %s\n", a_ptr->s, a_ptr->d, a_ptr->t);
    return 0;
}

Example Use/Output

PS> .\bin\structtypedef.exe
Description: Foo
Date: 15.07.2017
Time: 16:00

Typedeffing pointers is now wrong, it just creates pitfalls. See: In C, is it good form to use typedef for a pointer?.