【C语言】嵌套结构体初始化 - 一个有趣的结论

 0. 前言

        A. 嵌套结构体(比如双链表)的初始化一般是什么流程?

        B. 嵌套结构体的内存是如何分布的?

        C. 结构体中的结构体指针是否需要再次分配内存?不分配会怎么样?

        关于嵌套结构体的初始化问题,我找了网上的一些资料,发现能够解决我上述疑问的文章,自己试验后总结一下,欢迎交流。

【C语言】嵌套结构体初始化 - 一个有趣的结论_第1张图片

1. 试验代码:

        如下代码实现的功能是这样的:假设有一本空白的本子,你可以使用addPage函数按顺序从第一页开始写入内容,并且可以通过prePage和nextPage查看已经写入的内容。

#include 
#include 

typedef struct page_info{
    int index;
    const char *contents;
    struct page_info *pre;
    struct page_info *next;
}PAGE_INFO;

typedef struct {
    int page_num;               // 一本书一共有多少页可以写;
    int count;                  // 记录当前写了多少页;
    struct page_info *head;
    struct page_info *end;
    struct page_info *current;
} BOOK;

static BOOK *BOOKCreate(const char *homepage, int page_num)
{
    BOOK *sys = (BOOK *)malloc(sizeof(BOOK));
    sys->page_num = page_num;
    printf("head address is %x\n",sys->head);
    sys->head = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    sys->end = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    sys->current = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    printf("head address is %x\n",sys->head);
    sys->count = 1;
    sys->head->index = 1;
    sys->head->pre = NULL;
    sys->head->next = NULL;
    sys->head->contents = homepage;
    sys->end = sys->head;
    sys->current = sys->head;
    return sys;
}

int addPage(BOOK *sys, const char *contents){
    PAGE_INFO *temp = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    temp->contents = contents;
    temp->index = sys->current->index + 1;

    sys->end->next = temp;
    temp->pre = sys->end;

    sys->end = temp;
    sys->count ++;
    return sys->count;
}

const char *prePage(BOOK *sys)
{
    if (sys->current->pre != NULL){
        sys->current = sys->current->pre;
    }
    return sys->current->contents;
}

const char *nextPage(BOOK *sys){
    if (sys->current->next != NULL){
        sys->current = sys->current->next;
    }
    return sys->current->contents;
}

static void BOOKFree(BOOK *sys)
{
    free(sys);
}

int main() {
    printf("size of int is %d\n",sizeof(int));
    printf("size of PAGE_INFO is %d\n",sizeof(PAGE_INFO));
    printf("size of BOOK is %d\n",sizeof(BOOK));

    BOOK *sys = BOOKCreate("this is first page.",100);
    printf("%s\n",prePage(sys));
    printf("%d\n",addPage(sys,"this is second page"));
    printf("%s\n",nextPage(sys));
    printf("%s\n",prePage(sys));
    BOOKFree(sys);
    return 0;
}

上述代码执行结果:

【C语言】嵌套结构体初始化 - 一个有趣的结论_第2张图片

 2. 试验一:

        上述代码不做改动的情况下,我们可以得到如下结论:

        1). BOOKCreate函数在调用malloc时,已经给head/end/current这些结构体指针分配了地址;

        2). 因为结构体内存分配时要遵循对齐原则(详情可参考这篇文章),BOOK和PAGE_INFO结构体都占用了32个字节,符合预期;

3. 试验二:

        基于第二小节的第一个结论,我们对上述代码做如下调整,即,注释掉再次给head/end/current分配堆内存的操作,应该也能正常运行。我们可以看下运行效果:

【C语言】嵌套结构体初始化 - 一个有趣的结论_第3张图片

做上述注释,然后再次运行:

【C语言】嵌套结构体初始化 - 一个有趣的结论_第4张图片

 结果:

        1. 我们可以看到对sys结构体指针分配内存后,sys->head的内存也已经分配好了,做如上注释后,sys->head的地址没有发生变动;

        2. 程序异常退出,不符合预期;

4. 为什么?

        我们用IDE debug,单步运行,发现在第一次使用sys->head的时候,程序就已经报错了:

【C语言】嵌套结构体初始化 - 一个有趣的结论_第5张图片

        这里我们可以看到sys->head/sys->end/sys->current的地址每次执行都是这个0xbaadf00d,有点奇怪。那这个地址又是什么?

【C语言】嵌套结构体初始化 - 一个有趣的结论_第6张图片

 从网上找到了一些资料大家可以参考:地址。资料中提到:

LocalAlloc/GlobalAlloc,如果指定的是LMEM_FIXED(默认就指定了这个),并且没有指定LMEM_ZEROINIT,则分配的内存中初始化值为BAADF00D(可以理解成badfood,也就是不能直接吃的意思,呵呵)。调用LocalFree/GlobalFree则其值会变为FEEEFEEE)可以理解成Free)。

哈哈哈,badfood 

        到这里我们就很容易得到结论了,结构体使用malloc初始化时,结构体中的指针并没有被分配地址,我们需要通过使用malloc分配内存。(注,第3小节的时延不同的环境打印的结果不同,但是结论一致)。

你可能感兴趣的:(数据结构,c语言,数据结构,结构体,双链表)