摘要:总结了空结构体所占内存大小的情况,分析了柔性数组的使用方法,利用柔性数组存储任意长度斐波那契数列,介绍了union和struct的区别,以及使用union判断系统大小端的模式。
一、空struct所占内存大小
可以写一个程序验证一下,这里程序如下:
<span style="font-size:18px;">#include <stdio.h>
struct _null
{
}n1,n2;
int main(void)
{
printf("%d\n",sizeof(struct_null));
printf("%d %0x\n",sizeof(n1),&n1);
printf("%d %0x\n",sizeof(n2),&n2);
return0;
}</span>
定义了2个结构体变量n1和n2,结构体_null为空,然后打印结构体大小,以及两个结构体变量的大小和他们的地址,然后编译,这里使用gcc和g++两种编译方式,得到的结果是不同的,如下:
可以看到用g++编译出来的空结构体占一个字节,两个变量的起始地址也不一样,而gcc编译出来的,空结构体大小为0,并且两个不同的变量起始地址一样,这属于一个灰色地带。现代c以及编译器,更倾向于g++的这种结果,也就是空结构体占用一个字节的大小。
二、柔性数组使用分析
柔性数组是一种数组大小待定的数组,在c语言中,结构体里面的最后一个元素可以是大小未知的数组,C语言可以有结构体产生柔性数组,例如:
structsoftArray
{
intlen;
intarray[];
}soft_array;
int len是数组的长度,比如等于10就表示有十个元素,下面值给出了数组名,是一个占位符。我们可以打印看一下,这个柔性数组的结构体占多大内存,使用下面的程序:
<span style="font-size:18px;">#include <stdio.h>
struct _soft_array
{
intlen;
intayyay[];
}soft_array;
int main(void)
{
printf("%d\n",sizeof(soft_array));
return0;
}</span>
编译后运行结果如下:
为什么是4呢,因为这个结构体里面,有一个int类型的len,占了四个字节,下面一个数组只是一个占位符,并没有大小,它的大小在使用的时候才会给出来。怎么给呢?参照下面的程序:
<span style="font-size:18px;">#include <stdio.h>
#include <malloc.h>
typedef struct _soft_array
{
int len;
int array[];
}SoftArray;
int main()
{
int i = 0;
SoftArray* sa =(SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) * 10);
sa->len = 10;
for(i=0; i<sa->len; i++)
{
sa->array[i] = i + 1;
}
for(i=0; i<sa->len; i++)
{
printf("%d\n", sa->array[i]);
}
free(sa);
return 0;
}</span>
这个程序是给柔性数组赋值并打印,我们主要关注红色字体的两行:
SoftArray* sa = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) *10);
sa->len = 10;
第一句,主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组,第二个是定义len的长度。这样做的好处是什么呢?第一点,有时候我们需要使用数组进行操作,比如操作一个unsigned int类型的数据,有10个,但是我们为了冗余和防止数组越界,我们就创建一个20个元素大小的数组,这样就浪费了10个元素的存储空间。第二就是,很多时候我们并不知道需要操作的对象需要多大的内存空间,或者每次过来的大小都不一样,这样我们就可以灵活的使用柔性数组动态地来开辟内存,节约内存,提高空间使用效率。程序再下面就是使用刚才的len,来进行循环赋值和循环打印,编译运行结果如下:
三、柔性数组存储任意长度斐波那契数列
要使用柔性数组存储任意长度的斐波那契数列,我想需要按照以下步骤完成
1.创建柔性数组
2.生成斐波那契数列
3.将斐波那契数列放到柔性数组里
4.释放柔性数组
按照以上步骤,编写程序如下:
<span style="font-size:18px;">#include<stdio.h>
#include <malloc.h>
typedef struct _soft_array
{
int len;
int array[];
}SoftArray;
SoftArray* create_soft_array(int size)
{
SoftArray* ret = NULL;
if( size > 0 )
{
ret = (SoftArray*)malloc(sizeof(*ret) + sizeof(*(ret->array)) *size);
ret->len = size;
}
return ret;
}
void fac(SoftArray* sa)
{
int i = 0;
if( NULL != sa )
{
if( 1 == sa->len )
{
sa->array[0] = 1;
}
else
{
sa->array[0] = 1;
sa->array[1] = 1;
for(i=2; i<sa->len; i++)
{
sa->array[i] =sa->array[i-1] + sa->array[i-2];
}
}
}
}
void delete_soft_array(SoftArray* sa)
{
free(sa);
}
int main()
{
int i = 0;
int enter_len;
printf ( "Enter the Fibonacci length : \n" ) ;
scanf( "%d" , &enter_len ) ;
SoftArray* sa = create_soft_array(enter_len);
fac(sa);
for(i=0; i<sa->len; i++)
{
printf("%d\n", sa->array[i]);
}
delete_soft_array(sa);
return 0;
}</span>
编译运行,我们可以输入斐波那契数列的长度,这里我输入的数字是15,然后它会自动的打印出来:
四、union和struct的区别
我们的struct中的每个元素在内存中都独立分配空间,而union值分配最大域的空间,所有域共享这个空间。可以用 下面这段程序来演示:
<span style="font-size:18px;">#include <stdio.h>
struct A
{
inta;
intb;
intc;
}A_size;
union B
{
chara;
shortb;
intc;
}B_size;
int main(void)
{
printf("%d\n",sizeof(A_size));
printf("%d\n",sizeof(B_size));
return0;
}</span>
编写完了之后,编译运行,结果如下:
可以看到一个是12个字节,一个是4字节,这就是对应的刚才所说的,struct中每个int型的都分配四个字节,而union中,只分配了最大域的空间,也就是int的所占空间,就是四个字节。
五、union判断系统的大小端
union的使用受到系统大小端的影响,这是因为它只分配其中元素域最大的那个空间,然后几个元素共用这个空间,大小端的意思如下:
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
比如我们有一个程序如下:
<span style="font-size:18px;"> unionC
{
inti;
charb;
}c;
c.i=1;
printf("%d",c.b);</span>
假如使用的是大端模式,那么高字节保存在低地址,打印c.b的值的时候,只有一个字节,我们打印是从低地址开始打印,也就是最高的一个字节,那么就会是0;假如使用的是小端模式,那么高字节保存在高地址,就是我们常见的那种,打印c.b是一个自己,也就是低地址开始的一个字节,那么就会输出1。
上面这个特性可以用来检测系统是大端还是小端,方法如下:
<span style="font-size:18px;">#include <stdio.h>
union C
{
inti;
charb;
}c;
int main(void)
{
c.i=1;
if(c.b==1)
{
printf("thisis a small side mode\n");
}
else
printf("thisis a big side mode\n");
printf("%d\n",c.b);
return0;
}</span>
编译运行结果如下,我的系统是小端模式:
这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!