结构和共用体

我们知道一些C语言的基本数据类型,例如整型、单精度型、双精度型、字符型以及构造数据类型数组,这些数据类型在实际应用当中都是非常有效的,特别是数组,数组是把若干个类型相同的数据集合在一起便于整理和统计,然而现实中往往会遇到关系密切但数据类型不同的数据难以用单一数据类型或数组进行处理,这就需要引出另外两种构造数据类型结构和共用体。

结构类型与结构变量
结构类型是一种自定义的数据类型。

  • 结构类型的定义:

对于结构化程序设计,程序的处理对象是数据,需要根据数据类型的不同给存储数据的变量分配适当大小的存储单元。例如一个学生的基本信息有:学号/姓名/性别/年龄/地址等属性,如果将这些属性分别定义为互相独立的简单变量则难以反映相互间的内在联系,因为他们是同一个学生的属性,又由于这些属性的类型是不同的,也不能用构造数据类型数组来表示,为此需要定义一种新的数据类型——结构。

  1. 结构是逻辑上相互联系的一组分量的集合。
  2. 结构中的分量可以是不同类型的数据,称为结构的成员(这也是结构与数组的区别)。
  3. 在使用结构之前,首先根据具体问题,利用已有的数据类型对结构的组成进行描述,称为结构的定义(声明)。它说明了该结构的组成成员以及每个成员的类型。

一般形式:

struct 结构类型名
{
    成员表列;
};

例如:

struct student   
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};
//student是类型的标签,由用户自己定义,命名规则与变量名相同
//struct student是结构类型名
//学生的基本信息就是由不同类型的成员构成的
//整个类型定义是以分号结束的

又如:

struct date1
{
    int year;
    int month;
    int day;
};
struct student
{
    int num;
    char name[20];
    char sex;
    struct date1 age;
    char addr[30];
};
//这个栗子说明结构的组成成员可以是简单的数据类型也可以是已定义的构造类型

结构类型只是结构数据的组织形式,目的是告诉C的编译系统定义的结构类型是由哪些成员构成的,各占多少个字节,按什么形式存储的,并把它们当成一个整体来处理。

  • 结构变量的定义:

为了与结构变量的定义区分开我们今后称定义结构类型为结构类型声明。
在定义结构类型之后,表示声明了一种新的数据类型,并没有内存空间的分配。必须用结构类型定义相应的变量才能使用。
例如:

struct student   
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};

这是一个结构类型struct student的声明,也就是说这是一条类型声明语句而分号是语句的一个组成部分,所以后面必须是以分号结束。
定义结构变量的几种方法:
[方法一]:先声明结构类型再定义变量
一般形式:

struct 结构类型名
{
    成员表列;
};
struct 结构类型名 变量名表列;

栗子:

struct student   
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};
struct student s1,s2;

[方法二]:在声明结构类型的同时定义变量
一般形式:

struct 结构类型名
{
    成员表列;
}变量名表列;

栗子:

struct student   
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
}s1,s2;

[方法三]:省去结构标签直接定义变量
一般形式:

struct
{
    成员表列;
}变量名表列;

栗子:

struct   
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
}s1,s2;

上述三种方法的区别:
与变量一样在函数内部声明的结构类型只能在函数内部使用,在函数外部声明的结构类型就可以被多个函数使用了,显然,如果在程序中某个结构类型只在一个函数中使用,就可以使用第二种方法反之就得使用第一种方法,当然如果某个结构类型是程序中唯一的一种自定义的结构类型且只在一个函数中使用那么就可以用省去了标签的第三种方法。

由于这个关键字struct和结构标签合起来是结构类型名,每次用它来定义变量的时候都要写两个词,显得有些麻烦,我们可以用符号常量即宏名去代表一个结构类型名。如:

#define STUDENT struct student
STUDENT
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
}

这样可直接用STUDENT定义变量,如STUDENT s1,s2;此时不必再写:struct student s1,s2;
如果不想用编译预处理命令也可以用typedef语句给已有的数据类型定义一个新的名字,如:

typedef struct student STUDENT;

或者在声明结构的时候它她起一个名字:

typedef struct student
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
}STUDENT;

这样,可直接用STUDENT定义变量,如:

STUDENT s1,s2;
  • 结构变量的存储:

结构变量的存储分配与计算机系统及其所定义的结构有关。为了提高CPU的存储速度,多数编译系统对结构总的成员变量的存储分配采用按字节“对齐”的方法。分配原则如下:

  • 各成员按照定义顺序依次存放,但并不是紧密排列,成员的存储位置存储在自己宽度的整数倍上开始。
  • 检查所有成员的存储单元长度之和是否为成员中最宽的元素长度的整数倍,若不是,则补齐为整数倍。
struct MM
{
    char a;
    int i;
    char c;
};
struct MM m;

这里声明的结构类型struct MM,成员i需要的空间时宽度最长的,在使用的系统当中占4个字节,第一个成员a是字符型即使只分配给它一个字节,成员i也要从4的整数倍这个位置开始存储,这样结构变量m所占的存储空间的大小就是4*3,即是4的整数倍。

  • 结构变量的初始化和引用:

结构变量的初始化:
结构类型 结构变量名={初始值表};
栗子:

//使用方法一:
struct student
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};
struct student s1={201701,"madongshenme",'m',21,"No18.Xueyuan Street"};

//使用方法二:
struct student
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
}s1={201701,"madongshenme",'m',21,"No18.Xueyuan Street"};

也可以给部分成员赋初值,但需要指出初值是赋给哪个成员的:

struct student
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};
struct student s1={.name="madongshenme",.sex='m',.addr="No18.Xueyuan Street"};
//这里用成员运算符.加上成员名来标识
//成员运算符实际上就是用来访问结构变量的成员的,即结构变量的引用

数组用[]运算符和下标访问其单元a[0]=1;,结构变量是用.运算符和成员名字访问其成员s1.num=201701;
结构变量的引用:结构变量名.成员名
如果一个结构类型当中的某些成员是结构类型成员,我们就要使用多个成员运算符,一直引用到简单数据类型成员为止,如:
这里写图片描述
下面这个栗子实现了输入某学生的姓名、年龄和五门课的成绩,计算平均成绩并输出

#include<stdio.h>
struct student
{
   char name[10];
   int age;
   float score[5],ave;
};
int main(){
   struct student stu;
   int i;
   stu.age=0;
   printf("\n请输入学生的姓名和年龄:");
   scanf("%s%d",stu.name,&stu.age);
   printf("\n请输入学生五门课的成绩:");
   for(i=0;i<5;i++){
      scanf("%f",&stu.score[i]);
      stu.ave+=stu.score[i];
   }
   printf(" average=%6.1f\n",stu.ave/5);
   return 0;
}
  • 结构变量的使用规则:

对于整个结构可以做赋值、取地址,也可以传递给函数参数,如:

struct point
{
    int x;
    int y;
}p1,p2;
p1=(struct point){5,10}; //相当于p1.x=5;p1.y=10;
p2=p1; //相当于p2.x=p1.x;p2.y=p1.y;
//注意数组是不能进行上述两种情形赋值的!

不能将一个结构变量作为一个整体输入和输出;只能对其各成员分别进行操作:

scanf("%d%s%c%d%s",&s1);
printf("%d,%s,%c,%d,%s",s1);

上述两条语句试图想用结构变量s1作为一个整体进行输入和输出,很显然是错误的,正确的做法必须像下面这样:

scanf("%d%s%c%d%s",&s1.num,s1.name,&s1.sex,&s1.age,s1.addr);
printf("%d,%s,%c,%d,%s",s1.num,s1.name,s1.sex,s1.age,s1.addr);

若成员本身又属于一个结构体类型,只能对最低级的成员进行存取以及运算。如:student1.birthday.year=2016;
对成员变量可以像普通变量一样进行各种运算,如:sumage=s1.age+s2.age;
可以引用成员的地址,也可以引用结构体变量的地址,如:

scanf("%d",&s1.num); //输入s1.num的值
printf("%o",&s1); //输出s1的首地址

与数组不同,结构变量的名字不是其地址,如果想要获得其地址,需要使用&运算符。

  • 小结:
    结构类型是一种复合的数据类型,通常在所有函数之外的声明。
    类型与变量是不同的概念,只对变量分配单元,不对类型分配存储空间。
    结构变量使用成员运算符和名字访问其成员的。
    结构中的成员可以单独使用,其地位与作用相当于普通变量。
    成员名可以与程序中的变量名相同,二者不代表同一对象。如:num与s1.num。

结构数组

  • 结构数组的定义:

结构数组是指数组当中的每一个元素都是结构类型的,结构数组的定义方法是先声明一个结构,再用结构类型定义一个数组变量,一般形式如下:

struct 结构类型名
{
    成员表列
};
struct 结构类型名 结构数组名[尺寸];

栗子:

struct student
{
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
};
struct student stu[3];

也可以在声明结构类型的同时,定义结构数组,如:为记录100个人的基本情况,定义一个有100个元素的数组。

struct date1
{
    int month;
    int day;
    int year;
};
struct person
{
    char name[30];
    char sex;
    struct date1 birthday;
}man[100];
//man就是有100个元素的结构数组,数组的每个元素为struct person类型。

结构数组的初始化和引用:
结构数组的初始化的一般形式是在定义数组后面加上:={初值表列};
如:

struct student 
{
    int number;
    char name[20];
    char sex;
    int age;
};
struct student stu[2]={{1101,"madongshenme",'M',21},{1102,"nodeBill",'M',20}};

也可以在声明结构类型的同时定义数组并完成初始化:

struct student 
{
    int number;
    char name[20];
    char sex;
    int age;
}stu[2]={{1101,"madongshenme",'M',21},{1102,"nodeBill",'M',20}};

访问结构数组中的具体元素,必须遵守数组使用的规定——按下标进行访问。
要访问结构数组中某个具体元素的成员,又要遵守有关访问结构成员的规定——使用“.”和成员名。
如:

struct student 
{
    int number;
    char name[20];
    char sex;
    int age;
}stu[2];
stu[0].number=1101;
strcpy(stu[1].name,"nodeBill");
stu[1].age=20;

栗子:设有三个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票数。

#include<stdio.h>
#include<string.h>
struct person{
   char name[20];
   int count;
}leader[3]={{"madongshenme",0},{"nodeBill",0},{"大帝",0}};
int main(){
   int i,j;
   char leader_name[20];
   printf("输入十个得票人的名字(madongshenme,nodeBill,大帝):\n");
   for(i=1;i<=10;i++){
      scanf("%s",leader_name);
      for(j=0;j<3;j++)
         if(strcmp(leader_name,leader[j].name)==0)
            leader[j].count++;
   }
   printf("三个候选人的得票分数为:\n");
   for(i=0;i<3;i++)
      printf("%12s:%d\n",leader[i].name,leader[i].count);
   return 0;
}

栗子:编写一个30名学生信息状况的检索程序,每名学生的信息包括:xh(学号)、xb(性别)、cj(成绩)、xm(姓名)。输入30名学生的信息;输出男同学中成绩大于等于90的学生的xm、xb、cj。

#include<stdio.h>
struct student{
   int xh;
   char xb;
   int cj;
   char xm[20];
};
int main(){
   struct student stu[30];
   int i,n;
   printf("输入要处理的学生数:");
   scanf("%d",&n);
   printf("\n请依次输入学号 性别 成绩 姓名:\n");
   for(i=0;i<n;i++){
      scanf("%d %c %d",&stu[i].xh,&stu[i].xb,&stu[i].cj);
      gets(stu[i].xm);
   }
   printf("\n性别为'M'且成绩>=90的有:\n");
   for(i=0;i<n;i++)
      if(stu[i].xb=='M'&&stu[i].cj>=90)
         printf("%s,%c,%d\n",stu[i].xm,stu[i].xb,stu[i].cj);
   return 0;
}
  • 小结:
    结构数组的定义与结构变量的定义类似。
    与数组一样,结构数组的初始化也可以在定义时进行。
    一维结构数组的初始化格式与二维数组类似。

结构指针

  • 指向结构变量的指针

结构变量指针说明的一般形式:
struct 结构类型名 *结构指针变量名;
例如:

struct date1 *pdate,today;
pdate=&today;

这里写图片描述
与数组的区别:虽然结构和数组都是构造数据类型,数组的名字就是数组的首地址,但结构变量的名字并不是结构变量的地址。必须用&运算符。

struct student
{
    int number;
    char name[15];
    float score[3];
}x,*p;
p=&x; //正确
p=x; //错误

引用结构变量x的成员有三种方法:

  1. x.成员名,如:x.number
  2. (*p).成员名,如:(*p).number如果省略这里的括号即*p.number,由于运算符的优先级原因,它就相当于*(p.number),这时由于p是指针变量所以这样编译时就会出错。
  3. p->成员名,如:p->number

结构变量成员的三种引用方法栗子:

#include<stdio.h>
#include<string.h>
struct student{
   long int number;
   char name[20];
   char sex;
};
int main(){
   struct student s1,*p;
   p=&s1;
   s1.number=201701;
   strcpy(s1.name,"madongshenme");
   s1.sex='M';
   printf("No.:%ld\nname:%s\nsex:%c\n",s1.number,s1.name,s1.sex);
   printf("\nNo.:%ld\nname:%s\nsex:%c\n",(*p).number,(*p).name,(*p).sex);
   printf("\nNo.:%ld\nname:%s\nsex:%c\n",p->number,p->name,p->sex);
   return 0;
}

结构指针的运算栗子:

#include<stdio.h>
struct student
{
   int number;
   int age;
};
int main(){
   struct student stu[3]={{1000,20},{2000,19},{3000,23}};
   struct student *p;
   p=stu;
   //用p指针取来0号成员number,1000显示到屏幕上,然后number增1
   printf("%d\n",p->number++);
   //求得p指向元素的值,使其自加1
   printf("%d\n",++p->number);
   //求的p指向元素的值,然后使p自加1
   printf("%d\n",(*p++).number++);
   //先使p自加1,然后求得p指向元素的值
   printf("%d\n",(*++p).number++);
   return 0;
}

这里写图片描述
结果:
这里写图片描述

  • 指向结构数组的指针:

存储空间的分配栗子:

struct student
{
    int num;
    char name[15];
    float score[3];
}x,*p;
p=&x;

结构变量内存分配是占内存最宽的成员的额整数倍,在我们使用的系统中整型和浮点类型的变量都是占四个字节,字符型占一个字节,成员name是尺寸是15的字符数组,那么它的下一个成员就得从4的整数倍开始存储,相当于分配给name4*4个字节,分配给成员score就是4乘3个字节,所以结构类型struct student类型的变量所占用的存储空间的大小如果用sizeof(struct student)测试下,那就是4乘8=32个字节。

struct student
{
    int num;
    char name[15];
    float score[3];
}x,stu[5],*p,*q;
p=&x;
q=stu;
q=q+1;

同样,如果我们定义stu是一个结构数组,p,q是两个结构类型指针变量,stu赋给q就相当于q指向了stu的0号元素,q+1赋给q就是q指向了stu的1号元素。

struct student
{
    int num;
    char name[15];
    float score[3];
};
struct student stu[5],*p;
p=stu; //或p=&stu[0];

如果把数组的名字赋给指针变量p,实际上把数组stu的0号元素stu[0]的地址赋给p。那么用指针p和用变量stu[0]访问成员的效果就是等价的。

  • 小结:
    指向结构的指针成为结构变量的指针。
    指针变量的指针是该结构变量所占的内存段的起始地址。
    结构指针的运算同普通变量。

结构类型数据在函数间的传递

如果声明了一个结构,就有了一个自定义的类型,就像int和float一样,int和float类型的变量可以作为函数的参数,那么结构变量也可以作为函数的参数。

  • 结构变量作为函数参数:

整个结构作为函数的参数:
将结构作为整体,在函数之间传递整个结构;
在函数内新建一个结构变量,并接受调用者的值。

void getpoint(struct point p);

结构成员作为函数的参数:
在函数之间传递成员的值;
与传递简单变量的方法相同。

函数也可以返回一个结构。这些都与数组完全不同!

结构变量作为函数参数的栗子:

#include<stdio.h>
struct point
{
   int x;
   int y;
};
void getpoint(struct point);
void output(struct point);
int main(){
   struct point q={0,0};
   getpoint(q);
   output(q);
   return 0;
}
void getpoint(struct point p){
   scanf("%d",&p.x);
   scanf("%d",&p.y);
   printf("%d,%d\n",p.x,p.y);
}
void output(struct point p){
   printf("%d,%d\n",p.x,p.y);
}

结果:
这里写图片描述

函数返回一个结构栗子:

#include<stdio.h>
struct point
{
   int x;
   int y;
};
struct point sumpoint(struct point,struct point);
int main(){
   struct point pp1={1,2},pp2={3,4},pp3;
   pp3=sumpoint(pp1,pp2);
   printf("%d,%d\n",pp3.x,pp3.y);
   return 0;
}
struct point sumpoint(struct point p1,struct point p2){
  struct point q;
  q.x=p1.x+p2.x;
  q.y=p1.y+p2.y;
  return q;
};

结果:
这里写图片描述

  • 结构指针变量作为函数的参数:

结构变量作为函数参数属于参数的传值方式,在被调用函数当中是无法改变主调函数中的实参值的。另外如果结构的成员较多,一方面要新建形参变量,浪费存储空间,另一方面也要浪费程序的运行时间,因此可以使用结构指针作为函数的参数。这样向函数传递的就是结构的首地址而不是整个结构,形参可以是结构数组,传递的是结构指针的值,传入传出的只是一个指针的大小,而不是整个结构,这样节省了存储空间也加快了传值速度。函数也可以返回一个结构指针。
结构指针作为函数参数的栗子:

#include<stdio.h>
struct point
{
   int x;
   int y;
};
struct point *getpoint(struct point *p);
void output(struct point p);
int main(){
   struct point q={0,0},*r;
   r=getpoint(&q);
   output(q);
   output(*r);
   return 0;
}
struct point *getpoint(struct point *p){
  scanf("%d",&p->x);
  scanf("%d",&p->y);
  return p;
};
void output(struct point p){
   printf("%d,%d\n",p.x,p.y);
}

结构变量和结构指针作为函数参数的对比栗子:

#include<stdio.h>
struct point{
   int x;
   int y;
};
void f(struct point b);
int main(){
   struct point p;
   p.x=3;
   p.y=4;
   f(p);
   printf("%d,%d\n",p.x,p.y);
   return 0;
}
void f(struct point b){
   b.x=5;
   b.y=6;
}

结果:3,4

#include<stdio.h>
struct point{
   int x;
   int y;
};
void f(struct point *b);
int main(){
   struct point p;
   p.x=3;
   p.y=4;
   f(&p);
   printf("%d,%d\n",p.x,p.y);
   return 0;
}
void f(struct point *b){
   b->x=5;
   b->y=6;
}

结果:5,6
综上,我们可知通过传址的方式才能改变调用函数的参数值。

  • 结构数组作为函数参数:

结构变量可以作为函数参数,结构指针可以作为函数参数,结构数组也可以作为函数参数。
数组名是数组的首地址,向函数传递的就是结构数组的首地址,形参可以是结构数组,也可以是结构指针,这时仅复制结构的首地址而不是整个结构,这种按地址传递方式效率更高。
用结构数组作为函数参数的栗子:输入学生数据、计算学生平均成绩并输出学生的数据。

#include<stdio.h>
#define N 10
typedef struct student
{
   int stuid;
   char name[10];
   int score[5];
}STUDENT;
void inputscore(STUDENT s[],int n,int m);/*形参是结构数组*/
void averscore(STUDENT s[],float aver[],int n,int m);
void printscore(STUDENT s[],float aver[],int n);
int main(){
   STUDENT stu[N];
   float aver[N];
   int n;
   printf("请输入要处理的学生数?");
   scanf("%d",&n);
   inputscore(stu,n,5);
   averscore(stu,aver,n,5);
   printscore(stu,aver,n);
   return 0;
}
void inputscore(STUDENT s[],int n,int m){
   int i,j;
   printf("请输入学生的学号、姓名和5门课的成绩\n");
   for(i=0;i<n;i++){
      printf("Input recored %d:\n",i+1);
      scanf("%d",&s[i].stuid);
      scanf("%s",s[i].name);
      for(j=0;j<5;j++)
         scanf("%d",&s[i].score[j]);
   }
}
void averscore(STUDENT s[],float aver[],int n,int m){
   int i,j,sum[N];
   for(i=0;i<n;i++){
      sum[i]=0;
      for(j=0;j<5;j++)
         sum[i]+=s[i].score[j];
      aver[i]=(float)sum[i]/m;
   }
}
void printscore(STUDENT s[],float aver[],int n){
   int i;
   printf("学生的平均成绩为:\n");
   for(i=0;i<n;i++)
      printf("%10d%10s%6.1f\n",s[i].stuid,s[i].name,aver[i]);
}

用结构数组作为函数参数的栗子:输入学生数据、计算学生平均成绩并输出学生的数据。

#include<stdio.h>
#define N 10
typedef struct student
{
   int stuid;
   char name[10];
   int score[5];
}STUDENT;
void inputscore(STUDENT *s,int n,int m);/*形参是结构指针*/
void averscore(STUDENT *s,float aver[],int n,int m);
void printscore(STUDENT *s,float aver[],int n);
int main(){
   STUDENT stu[N];
   float aver[N];
   int n;
   printf("请输入要处理的学生数?");
   scanf("%d",&n);
   inputscore(stu,n,5);
   averscore(stu,aver,n,5);
   printscore(stu,aver,n);
   return 0;
}
void inputscore(STUDENT *s,int n,int m){
   int i,j;
   printf("请输入学生的学号、姓名和5门课的成绩\n");
   for(i=0;i<n;i++){
      printf("Input recored %d:\n",i+1);
      scanf("%d",&(s+i)->stuid);
      scanf("%s",(s+i)->name);
      for(j=0;j<5;j++)
         scanf("%d",&(s+i)->score[j]);
   }
}
void averscore(STUDENT *s,float aver[],int n,int m){
   int i,j,sum[N];
   for(i=0;i<n;i++){
      sum[i]=0;
      for(j=0;j<5;j++)
         sum[i]+=(s+i)->score[j];
      aver[i]=(float)sum[i]/m;
   }
}
void printscore(STUDENT *s,float aver[],int n){
   int i;
   printf("学生的平均成绩为:\n");
   for(i=0;i<n;i++)
      printf("%10d%10s%6.1f\n",(s+i)->stuid,(s+i)->name,aver[i]);
}
  • 小结:

结构变量可以在函数间传递,传递方式有两种:

  1. 值传递:调用函数的实参和被调用函数的形参都是结构变量。
  2. 地址传递:调用函数的实参时结构变量的首地址,被调用函数的形参是结构指针变量。如果传递的是结构数组,则实参时数组名,形参可以是结构指针变量或数组名。

共用体

  • 共用体类型的定义:

一般形式:

union 共用体类型
{
    共用体成员表;
};

如:

union data
{
    int i;
    char ch;
    float f;
};

共用体与结构的异同点:
相似点:共用体的类型声明、变量定义及引用方式与结构相似。
不同点:结构变量所占内存长度,根据编译系统环境有所不同,采用字节对齐的办法。共用体变量所占内存长度等于最长的成员长度。

  • 共用体变量的定义:

[方法一]:先声明共用体类型再定义变量
一般形式:

union 共用体名
{
    成员表列;
};
union 共用体名 变量名表列;

栗子:

union data   
{
    int i;
    char ch;
    float f;
};
union data a,b,c;

[方法二]:在声明类型的同时定义变量
一般形式:

union 共用体名
{
    成员表列;
}变量名表列;

栗子:

union data   
{
    int i;
    char ch;
    float f;
}a,b,c;

[方法三]:直接定义共用体类型变量
一般形式:

union
{
    成员表列;
}变量名表列;

栗子:

union
{
    int i;
    char ch;
    float f;
}a,b,c;
  • 共用体变量的存储:

所有成员共享一个空间,同一时间只有一个成员是有效的。如:

union data 
{
    int i;
    char ch;
    float f;
}a;

我门常用的系统中整型和浮点型都是占4个字节,所以分配给a的空间的大小就是4个字节。也就是说这三个成员将共享这4个字节,只不过同一个时刻只有一个成员是有效的。
这里写图片描述
用sizeof(union data)得到的占内存最长的成员的长度。

  • 共用体变量的初始化和引用:

只能初始化第一个成员

union data
{
    int i;
    char ch;
    float f;
};
union data a={12};//正确
union data a={12,'a',3.14};//错误

共用体变量的引用方式与结构变量相同:
共用体变量名.成员名
(*指针变量名).成员名
指针变量名->成员名
对前面所定义的共用体变量a,用以下赋值语句:a.i=1;a.ch='b';a.f=1.5;但同一时间只有一个成员是有效的,此时只有最后一个赋值是有效的。
共用体变量的内存分配栗子:

#include<stdio.h>
typedef union pp
{
   int i;
   char ch[2];
}ICH;
int main(){
   ICH a;
   a.ch[0]='0';
   a.ch[1]='1';
   printf("%d,%x\n",sizeof(a),a.i);
   return 0;
}

a的内存分配情况:
由于给共用体变量的成员只分配一段内存,空间的大小是按照最长的成员分配的,这里显然为4个字节,这4个字节可以存储成员i也可以存储成员ch,不同的时刻可以存储不同的成员,当然某一时刻只有一个成员是有效的,至于为何要从右端(低字段)而不是从高字段开始,这取决于我们所使用的CPU是X86,它是属于小端机器也就是说它是从低地址开始存放的。
小结:
共用体变量的地址和它的各成员的地址都是同一地址;不能对共用体变量名赋值,也不能通过引用变量名来得到成员的值,不能在定义共用体变量时对它初始化;不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可使用指向共用体变量的指针;共用体类型可以出现在结构类型定义中,也可以定义共用体数组。而结构也可以出现在共用体类型定义中,数组也可作为共用体的成员。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值