1、结构体的定长表示

C语言中结构体的使用基本上都是定长的,就如以下这种:

typedef struct
{int a;int b;char c[100];double d;
}STRU;

2、结构体的不定长表示

2.1、指针形式

但在很多的场景下,结构体的定义成不定长反而更容易解决问题,最典型的就是需要通过Socket发送一个结构体数据,但是结构体中包含了一个不定长的信息。可以采用以下方式来定义结构体:

typedef struct
{int  a;char *b;char *c;
}STRU;

对于该种类型的结构体可以采用以下两种方式来申请并分配内存:

1)、直接分配

 char b[] = "ahsdggc adgfas";char c[] = "asjdhvbaegegfgasdjv";int len = sizeof(STRU);int len_b = strlen(b)+1;    //+1是因为字符串有一个字节存放'\0'int len_c = strlen(c)+1;STRU *stru = (STRU *)malloc(len + len_b + len_c);memset(stru, 0, len);printf("Before - STRU 的地址为:%x \n", stru);printf("Before - STRU_B 的地址为:%x \n", stru->b);printf("Before - STRU_C 的地址为:%x \n", stru->c);stru->b = (char *)stru + len;    //重新分配 stru->b 的地址stru->c = stru->b + len_b;     //重新分配 stru->c 的地址printf("After - STRU 的地址为:%x \n", stru);printf("After - STRU_B 的地址为:%x \n", stru->b);printf("After - STRU_C 的地址为:%x \n", stru->c);strcpy(stru->b, b);              //将 b 的内容复制到 stru->bstrcpy(stru->c, c);               //将 c 的内容复制到 stru->ccout << ">>> b: " << stru->b << endl;cout << ">>> c: " << stru->c << endl;

运行的结果如下所示:

2)、 间接分配

还有另外一种分配的方式:

    char b[] = "ahsdggc adgfas";char c[] = "asjdhvbaegegfgasdjv";int len = sizeof(STRU);int len_b = strlen(b)+1;    //+1是因为字符串有一个字节存放'\0'int len_c = strlen(c)+1;STRU *stru = (STRU *)malloc(len);memset(stru, 0, len);char *cb = (char *)calloc(0, len_b);  // 申请 len_b 长的内存并初始化为0memcpy(cb, b, len_b);                 // 将 b 的内容复制到 cb 中char *cc = (char *)calloc(0, len_c); // 申请 len_c 长的内存并初始化为0memcpy(cc, c, len_c);                 // 将 c 的内容复制到 cc 中printf("Before - STRU 的地址为:%x \n", stru);printf("Before - STRU_B 的地址为:%x \n", stru->b);printf("Before - STRU_C 的地址为:%x \n", stru->c);printf("Before - cb 的地址为:%x \n", cb);printf("Before - cc 的地址为:%x \n", cc);stru->b = cb;stru->c = cc;printf("After - STRU_B 的地址为:%x \n", stru->b);printf("After - STRU_C 的地址为:%x \n", stru->c);printf("After - cb 的地址为:%x \n", cb);printf("After - cc 的地址为:%x \n", cc);cout << ">>> b: " << stru->b << endl;cout << ">>> c: " << stru->c << endl;

下图为验证的结果:

以上两种方式,一个是在申请结构体的内存时也分配字符串长度的内存;还有一种是先分配结构体的内存,然后再申请结构体长度的内存,然后通过地址赋值的方式使结构体中的元素指向那些内存;

2.2、空数组方式

但是还有一种形式的结构体:

typedef struct
{int a;int b;char c[0];
}STRU;

在上面的定义中,char c[0]定义了一个长度为0的字符串数组,此时,在结构体中实际上只包含了a和b的地址空间,即sizeof(STRU)== 8,

此时c被当成一个指针,指向了结构体后面的内存地址的起始地址,c = &stru + sizeof(STRU),如下所示:

struct test3{int a;int b;char c[0];  //不占用结构体的内存地址,此时c指向的就是结构体后面的内存空间的起始地址
};test3 t3;
test3* pt3 = &t3;
printf("t3 address: %x\n", pt3);
printf("t3.c address: %x\n", t3.c);
cout << "sizeof(test3) = " << sizeof(test3) << endl;   //8

最终输出结果为:

这样就可以直接将结构体后面的数据当成字符串数组c的内容 ,这种使用方式被称为柔性数组,关于柔性数组的更多内容可以参考:https://www.cnblogs.com/pluviophile/p/7571410.html

结构体 — C 语言中不定长结构体的使用相关推荐

  1. c语言如何宏定义枚举型结构体,C语言学习笔记--枚举结构体

    枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法格式来声明: enum 枚举类型名字 {名字0,名字1,...,名字n}: 枚举类型名字通常并不真的使用,要用的是大括号里面的名字,因为 ...

  2. c语言自定义的结构体,c语言定义多个结构体

    本文收集整理关于c语言定义多个结构体的相关议题,使用内容导航快速到达. 内容导航: Q1:C语言中定义一个结构体如何在不同的.C文件中使用. #include 然后就用啊 正式一点的,可以声明 ext ...

  3. C语言中的分支结构和循环结构有哪些,【单选题】下面哪种不是C语言中的基本结构______。 A. 顺序结构 B. 分支结构 C. 跳转结构 D. 循环结构...

    [单选题]下面哪种不是C语言中的基本结构______. A. 顺序结构 B. 分支结构 C. 跳转结构 D. 循环结构 更多相关问题 [单选,A2型题,A1/A2型题] 金瓷基底冠进行氧化处理时,理想 ...

  4. C语言 函数不定长参数 ##__VA_ARGS__经典案例 - C语言零基础入门教程

    目录 一.##__VA_ARGS__简介 二.##__VA_ARGS__经典案例 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.## ...

  5. C语言 函数不定长参数 - C语言零基础入门教程

    目录 一.前言 二.函数不定长参数简介 1.va_start 2.va_arg 3.va_end 三.自定义不定长参数的函数 1.va_start/va_arg/va_end 案例一 2.va_sta ...

  6. storm目录结构及在zk中的目录结构

    storm目录结构及在zk中的目录结构 @(STORM)[storm] storm目录结构及在zk中的目录结构 一storm在磁盘中的内容 一nimbus中的目录结构 1inbox目录 2stormd ...

  7. java 不定参数方法_java中不定长参数的使用方法

    java中不定长参数的使用方法 不定长参数方法的语法如下:返回值 方法名(参数类型...参数名称) 在参数列表中使用"..."形式定义不定长参数,其实这个不定长参数a就是一个数组, ...

  8. java 不定参数_java中不定长参数的实例用法

    java中不定长参数的使用方法 不定长参数方法的语法如下: 返回值 方法名(参数类型...参数名称) 在参数列表中使用"..."形式定义不定长参数,其实这个不定长参数a就是一个数组 ...

  9. c语言不同类型指针间的强转,C语言中不同的结构体类型的指针间的强制转换详解...

    C语言中不同类型的结构体的指针间可以强制转换,很自由,也很危险.只要理解了其内部机制,你会发现C是非常灵活的. 一. 结构体声明如何内存的分布, 结构体指针声明结构体的首地址, 结构体成员声明该成员在 ...

最新文章

  1. [软件工程基础]团队作业Week3
  2. Hyperledger Besu企业以太坊快速教程
  3. 在C#中利用SharpZipLib进行文件的压缩和解压缩
  4. YUV2RGB源码详解(参考Opencv4.1)
  5. std::recursive_mutex嵌套锁/递归锁
  6. 中国国民休闲状况调查(2020)
  7. 微软发布了Visual Stduio 2010 RTM版本的虚拟机vhd文件,包含样例和动手实验(免费)...
  8. MFC中使用CTabCtrl或CPropertySheet实现标签页
  9. Ubuntu21.04安装网易有道词典
  10. ssh整合之四单独搭建struts的运行环境
  11. Linux中级之netfilter/iptables应用及补充
  12. 允许外部访问Windows本机的指定端口
  13. win10 html字体设置,IT之家学院:如何解决Win10屏幕字体缩放模糊问题
  14. hashMap底层原理
  15. 吴恩达—机器学习的六个核心算法
  16. 哪款投影仪做家庭影院效果好?家用投影仪哪个好
  17. win7系统ftp服务器构建,win7系统构建ftp服务器
  18. Android 手札小记
  19. uniapp 基础框架模板
  20. 【单细胞分析】P2.5、聚类,筛选marker基因,可视化

热门文章

  1. <12>springboot集成thymeleaf模板引擎
  2. 关于VS2017许可证过期问题
  3. 漫步者蓝牙自动断开_比苹果AirPods体验更好的蓝牙耳机,漫步者lollipods体验小感...
  4. linux操作系统具有哪些特性,Linux系统拥有哪些特性?这些你必须知道!
  5. twitter三方登录的实现
  6. 积分球辐射光源照度均匀性
  7. 可能改变世界的13个“终结”(上)
  8. 赛氪2020上半年 A.转换AV号(avtobv)[神奇的输入][神奇的getchar()][进制转换]
  9. OB0201 obsidian dataview插件使用
  10. 视频监控系统 摄像头与网络存储服务器兼容,网络视频监控系统技术要点