结构体浅析

来源:互联网 发布:虚拟串口调试软件 编辑:程序博客网 时间:2024/06/03 20:58

结构体浅析

C语言提供了两种聚合数据类型:数组和结构。结构变量属于标量类型(例如:int,char等),所以可以像对待标量那样子对待结构变量,

1.     结构变量可以作为传递给函数的参数

2.     可以作为返回值

3.     相同类型的结构变量还可以互相赋值

 

结构体声明和定义变量的几种模式

1.    声明:struct  tag{member_list};

定义:struct  tag variable1;

2.    声明:struct tag{member_list}variable_list;

定义:已在variable_list定义,亦可使用 1 中定义方法

3.    声明:typedef struct  tag{member_list};

定义:tag variable1;

4.    (使用频率最高的方式,可以少写很多东西)

声明:typedef struct  tag{member_list}variable_list;

定义:已在variable_list定义,亦可使用 3 中定义方法

5.    (几乎不这样子使用,只有在声明时能够定义变量,很不方便)

声明+定义:struct {member_list}variable_list;

注:

member_list可以包括:普通标量(int 、char、标量指针、结构体指针),其他结构体 。

variable_list可以是普通变量,数组,指针等

 

结构的自引用

上面已经说过了member_list的成员了,那么现在我们再来讨论下成员是否可以有自身结构,首先看看下面的这两个声明结构

【错】

struct test {

                            int a;

                            struct test1 b;

};

【对】

struct test {

                            int a;

                            struct test1  *b;

};

显然区别就在‘*’,前者的成员是结构b,而后者的成员是结构指针b,前者的成员就是自己,成员里面还有成员,这样子就陷入了死循环,编译器绝对不允许这样的事情出现,而后者的结构指针就不一样了,因为指针所占的空间大小是一定的,所以编译器可以很轻易的就给该结构变量分配内存空间

 

注:struct{

                     Int a;

                     Variable b;

}*Variable;

它是错误的,因为在member_list中,变量Variable还没有声明,编译器还不知道Variable是个什么东西,所以是上面的声明是错误的,正确的应该是下面的:

struct  test{

                     Int a;

                     struct test  *b;

}*Variable;

 

结构体的互相引用

结构体的互相引用,必然存在这样的问题:无论先声明哪个结构体

,它里面总包含另一个结构体,但是我们又没有声明另一个结构体,反之亦然。因而我们可以利用不完整的声明解决这个问题

例如:我们需要结构体A中包含结构体B,结构体B中包含结构体A。

struct  B;

struct  A{

                     struct  B;

};

struct  B{

                     struct  A;

};

这样子就完美解决结构体互相引用的问题了。

 

结构的存储

大家先看看下面这两个结构体:

typedef  struct  first{

                                          int  a;

                                          char b;

                                          char c;

};

typedef  struct  second{

                                          char b;

int  a;

                                          char c;

};

他们两个有什么区别呢?

只是member_list的顺序不同罢了,但是由于边界对齐技术(CPU在工作时只能按照某长度的整倍数为边界进行内存操作)的存在,因而产生了不同的效率。

first:

b

█c

 

 


 

 

前面的四个为a占用的空间,紧接着的是b,c占用的,最后的两个由于对齐而保留,下次cpu将从空白后面的地址开始访问内存。空间利用率:75%

Second:

b

 

 

 

c

 

 

 

 前面的四个空间存储的是b,中间的是a,下来的是c,空间利用率:50%

下面是测试我的测试程序,仅供大家参考:

 注:函数offsetof(type,member)       type:结构体类型;    member:结构体成员;       功能:求得member开始存储的位置距离存储的位置偏移的字节数

 运行结果截图如下:

<img src="http://img.blog.csdn.net/20140620233055156?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY29sZW9wdGlsZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

经过上面的许多测试,我们可以得出这样的结论:尽量把占用空间最大的类型放在member_list的最上面,这样子可以使空间利用率最大,甚至达到100%,节约的这点内存空间在程序创建成百上千个结构上体现的尤为明显。

 

作为函数参数的结构

例:typedef  struct {

                                          int stu_id;

                                          char stu_name[20];

}stu;

void  print( stu student)

{

       Printf(“id:%d\n”,student.stu_id;);

       Printf(“name:%s\n”,student.stu_name);

}

这样子传结构体参数是可以的,可是由于在c语言中传递传递参数就是把参数拷贝一份,然后供函数使用,这样子拷贝就有点多了,远不如传递结构体指针简单,但是传递指针可能改变结构内容,因而我们可以加上关键字const,实现如下:

void  print( stu const *student)

{

       Printf(“id:%d\n”,student->stu_id;);

       Printf(“name:%s\n”,student->stu_name);

}

传递指针的效率就很高了,只需要拷贝一个指针标量就行了,是不是很能提高效率,尤其是在大量调用一个函数的情况下。

 

 

#include<stdio.h>#include<stddef.h>#include<windows.h> typedef struct test1{       char c;       double a;       char b;        };typedef struct test2{       char b;       char c;       double a;       };typedef struct test3{       double a;        char b;       char c;       };typedef struct test4{       double a;        int b;       int c;       };       int main(){    /*测试编译器给予不同类型标量的大小*/    printf("测试编译器给予不同类型标量的大小!\n");    printf("sizeof(char):%d\n",sizeof(char));    printf("sizeof(int):%d\n",sizeof(int));     printf("sizeof(double):%d\n\n",sizeof(double));         /*测试不同排序下结构体的空间利用率*/    printf("sizeof(struct test1):%d\n",sizeof(struct test1));    printf("offsetof(struct test1,c):%d\n",offsetof(struct test1,c));     printf("test1空间利用率:%.2lf\n\n",(double)(sizeof(double)+2*sizeof(char))/(double)sizeof(struct test1));     printf("sizeof(struct test2):%d\n",sizeof(struct test2));    printf("offsetof(struct test2,c):%d \n",offsetof(struct test2,c));     printf("test2空间利用率:%.2lf\n\n",(double)(sizeof(double)+2*sizeof(char))/(double)sizeof(struct test2));     printf("sizeof(struct test3):%d\n",sizeof(struct test3));    printf("offsetof(struct test3,c):%d\n",offsetof(struct test3,c));    printf("test3空间利用率:%.2lf\n\n",(double)(sizeof(double)+2*sizeof(char))/(double)sizeof(struct test3));      /*验证结论猜想是否正确*/     printf("sizeof(struct test4):%d\n",sizeof(struct test4));    printf("offsetof(struct test4,c):%d\n",offsetof(struct test4,c));    printf("test4空利用率:%.2lf\n\n",(double)(sizeof(double)+2*sizeof(int))/(double)sizeof(struct test4));     system("PAUSE");    return 0;}

 

 

0 0
原创粉丝点击