柔性数组,也叫动态数组,先看个示例
#include <stdio.h> struct msg_buf { long type; char msg[0]; }; int main() { printf("sizeof(struct msg_buf):%d", sizeof(struct msg_buf)); return 0; }
输出:
sizeof(struct msg_buf):4
先不看输出,先说msg[0],我们平时用数组时不时都要明确指明数组大小,数组大小不为0(不能分配常量大小为 0 的数组),但这里却可以编译通过。
其实呢,这个msg[0]也可以是msg[]明确来说不算是结构体成员,只是挂羊头卖狗肉而已,地址连在一起,这样的好处就是申请内存的时候可以额外申请到动态数组
演示:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct msg_buf { long type; char msg[0]; }MSG_BUF; int main() { char buf[128]; fgets(buf, 128, stdin); printf("sizeof(struct msg_buf):%d\n", sizeof(struct msg_buf)); MSG_BUF *ptr = (MSG_BUF *)malloc(sizeof(MSG_BUF) + strlen(buf) + 1); ptr->type = 1; memcpy(ptr->msg, buf, strlen(buf) + 1); printf("%s\n", ptr->msg); free(ptr); return 0; }
- 那么好,问题来了,什么是柔性数组?
柔性数组既数组大小待定的数组, C语言中结构体的最后一个元素可以是大小未知的数组,也就是所谓的0长度,所以我们可以用结构体来创建柔性数组。
- 柔性数组有什么用途 ?
它的主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。
- 用法 :
在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量,但对于这个数组的大小,我们可以进行动态分配,解决数据冗余问题。
Linux网络编程里面的System V IPC 通信机制里面的XSI消息队列就有用到柔性数组(当时我不知道这个叫什么,百度的)
消息队列里面的发送消息和接收消息都是通过类似这样的结构体实现的
//发送 int msgrsnd(int msqid,const void *msg_ptr,size_t sz,int msgflg); //接收 int msgrcv(int msqid,void *msg_ptr,size_t sz,long int msgtype,int msgflg);
msg_ptr指针结构体必须以一个长整形的成员变量(字段)开始,接收函数将使用该成员来确定信息类型.即使用以下结构体形式
struct msgbuf { long mtype, /* message type, must be > 0 */ char mtext[0] /* message data */ };
msg_sender_examps:
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<string.h> struct msgbuf{ int type; char ptr[0]; }; int main(int argc,char *argv[]) { key_t key; key=ftok(argv[1],100); int msgid; msgid=msgget(key,IPC_CREAT | 0600); pid_t pid; pid=fork(); if(pid==0){ while(1){ printf("pls input msg to send:"); char buf[128]; fgets(buf,128,stdin); struct msgbuf *ptr=malloc(sizeof(struct msgbuf)+strlen(buf)+1); ptr->type=1; memcpy(ptr->ptr,buf,strlen(buf)+1); msgsnd(msgid,ptr,strlen(buf)+1,0);free(ptr); } } else{ struct msgbuf{ int type; char ptr[1024]; }; while(1){ struct msgbuf mybuf;memset(&mybuf,'\0',sizeof(mybuf)); msgrcv(msgid,&mybuf,1024,2,0); printf("recv msg:%s\n",mybuf.ptr); } } }
msg_receiver_example
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<string.h> struct msgbuf{ int type; char ptr[0]; }; int main(int argc,char *argv[]) { key_t key; key=ftok(argv[1],100); int msgid; msgid=msgget(key,IPC_CREAT|0600); pid_t pid; pid=fork(); if(pid==0) //send { while(1) { printf("pls input msg to send:"); char buf[128]; fgets(buf,128,stdin); struct msgbuf *ptr=malloc(sizeof(struct msgbuf)+strlen(buf)+1); ptr->type=2; //send msg type=2 memcpy(ptr->ptr,buf,strlen(buf)+1); msgsnd(msgid,ptr,strlen(buf)+1,0); free(ptr); } } else { struct msgbuf{ int type; char ptr[1024]; }; while(1) { struct msgbuf mybuf; memset(&mybuf,'\0',sizeof(mybuf)); msgrcv(msgid,&mybuf,1024,1,0); //recv msg type=2 printf("recv msg:%s\n",mybuf.ptr); } } }