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


     0. 前言

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

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

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

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

    1. 试验代码:

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

    1. #include
    2. #include
    3. typedef struct page_info{
    4. int index;
    5. const char *contents;
    6. struct page_info *pre;
    7. struct page_info *next;
    8. }PAGE_INFO;
    9. typedef struct {
    10. int page_num; // 一本书一共有多少页可以写;
    11. int count; // 记录当前写了多少页;
    12. struct page_info *head;
    13. struct page_info *end;
    14. struct page_info *current;
    15. } BOOK;
    16. static BOOK *BOOKCreate(const char *homepage, int page_num)
    17. {
    18. BOOK *sys = (BOOK *)malloc(sizeof(BOOK));
    19. sys->page_num = page_num;
    20. printf("head address is %x\n",sys->head);
    21. sys->head = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    22. sys->end = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    23. sys->current = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    24. printf("head address is %x\n",sys->head);
    25. sys->count = 1;
    26. sys->head->index = 1;
    27. sys->head->pre = NULL;
    28. sys->head->next = NULL;
    29. sys->head->contents = homepage;
    30. sys->end = sys->head;
    31. sys->current = sys->head;
    32. return sys;
    33. }
    34. int addPage(BOOK *sys, const char *contents){
    35. PAGE_INFO *temp = (PAGE_INFO *)malloc(sizeof(PAGE_INFO));
    36. temp->contents = contents;
    37. temp->index = sys->current->index + 1;
    38. sys->end->next = temp;
    39. temp->pre = sys->end;
    40. sys->end = temp;
    41. sys->count ++;
    42. return sys->count;
    43. }
    44. const char *prePage(BOOK *sys)
    45. {
    46. if (sys->current->pre != NULL){
    47. sys->current = sys->current->pre;
    48. }
    49. return sys->current->contents;
    50. }
    51. const char *nextPage(BOOK *sys){
    52. if (sys->current->next != NULL){
    53. sys->current = sys->current->next;
    54. }
    55. return sys->current->contents;
    56. }
    57. static void BOOKFree(BOOK *sys)
    58. {
    59. free(sys);
    60. }
    61. int main() {
    62. printf("size of int is %d\n",sizeof(int));
    63. printf("size of PAGE_INFO is %d\n",sizeof(PAGE_INFO));
    64. printf("size of BOOK is %d\n",sizeof(BOOK));
    65. BOOK *sys = BOOKCreate("this is first page.",100);
    66. printf("%s\n",prePage(sys));
    67. printf("%d\n",addPage(sys,"this is second page"));
    68. printf("%s\n",nextPage(sys));
    69. printf("%s\n",prePage(sys));
    70. BOOKFree(sys);
    71. return 0;
    72. }

    上述代码执行结果:

     2. 试验一:

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

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

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

    3. 试验二:

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

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

     结果:

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

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

    4. 为什么?

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

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

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

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

    哈哈哈,badfood 

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

  • 相关阅读:
    vue--vuerouter缓存路由组件
    基于JAVA仁爱公益网站计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    企业选型OA系统 ,如何选择合适的?
    Java版企业电子招标采购系统源码—企业战略布局下的采购寻源
    SQL 改写系列七:谓词移动
    [附源码]计算机毕业设计宁财二手物品交易网站Springboot程序
    Java JavaMail通过SMPT发送邮件
    AV1 视频编码标准资源
    韩顺平0基础学java——第15天
    5.1 Apache Hive DML语句与函数使用
  • 原文地址:https://blog.csdn.net/qq_19760839/article/details/134318301