欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第八章 结构体和共用体

程序员文章站 2022-05-07 18:33:01
...

第一节 结构体变量

第八章 结构体和共用体

  • 什么是结构体?

    将多种数据类型结合构建在一起的数据类型称为结构体类型;需要多个数据类型来表示某一信息时,可以使用结构体。

    例如学生李四和赵六参加比赛需要在网络上填写信息包含:存在不同的数据类型

    name:lisi, age:23, sex:M, student_number:20193055;
    name:zhaoliu, age:22, sex:M, student_number:20193091;

    代码示例:

    #include <stdio.h>
    struct test
    {
    	char name[30];
    	int age; 
    	char sex;
    	int student_number; 
    };
    
    int main()
    {
    	struct test lisi , zhaoliu;  
    
    	printf("请输入学生的姓名 年龄 性别 学号:");
    	scanf("%s %d %c %d",lisi.name,&lisi.age,&lisi.sex,&lisi.student_number);
    	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",lisi.name,lisi.age,lisi.sex,lisi.student_number);
    	printf("请输入学生的姓名 年龄 性别 学号:");
    	scanf("%s %d %c %d",zhaoliu.name,&zhaoliu.age,&zhaoliu.sex,&zhaoliu.student_number);
    	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",zhaoliu.name,zhaoliu.age,zhaoliu.sex,zhaoliu.student_number);
        return 0;
    }
  • 创建结构体类型:

    结构体类型的创建方法:

    struct 结构体名{
        类型名 成员表列1;
        类型名 成员表列2;
            ···
    };

    说明:

    1. 创建结构体类型是指创建的数据类型;

    2. 结构体名是指对应创建的数据类型名,例如之前学习的int型、float型,其中int和float是数据类型名;

    3. 成员表列可以包含多个同类型及不同类型的数据,每个成员以;分隔。结构体的花括号{}之后有一个;

    4. 成员也可以是另一个结构体类型。

    代码示例:

    struct score
    {
    	int shuxue;
    	int yuwen;
    	int zhengzhi;
    	char tiyu;
    };
    
    struct test
    {
    	char name[30];
    	int age; 
    	char sex;
    	int student_number; 
    	struct score gaokao;
    };
  • 定义结构体变量

    在没有定义结构体之前,系统不会分配存储空间。为了使用结构体变量,需要在使用之前进行定义。

    1. 先创建结构体类型,再定义。

      在文件的开头创建好结构体类型,然后在函数中使用定义结构体变量。定义的方法为:

      struct 结构体名 结构体变量名
      //例如:
      struct test lisi;

      代码示例:

      #include <stdio.h>
      struct test
      {
      	char name[30];
      	int age; 
      	char sex;
      	int student_number; 
      };
      
      int main()
      {
      	struct test lisi , zhaoliu;  
      
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",lisi.name,&lisi.age,&lisi.sex,&lisi.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",lisi.name,lisi.age,lisi.sex,lisi.student_number);
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",zhaoliu.name,&zhaoliu.age,&zhaoliu.sex,&zhaoliu.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",zhaoliu.name,zhaoliu.age,zhaoliu.sex,zhaoliu.student_number);
          return 0;
      }

      第八章 结构体和共用体

    2. 在创建结构体类型的同时进行定义。

      说明:结构体成员表名在结构体内唯一,但可以和其他变量名相同。

      struct 结构体名 {
          类型名 成员表列1
          类型名 成员表列2
              ···
      }变量名表列;

      代码示例:

      #include <stdio.h>
      int main()
      {
      	struct test
      	{
      		char name[30];
      		int age; 
      		char sex;
      		int student_number; 
      	}lisi,zhaoliu;
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",lisi.name,&lisi.age,&lisi.sex,&lisi.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",lisi.name,lisi.age,lisi.sex,lisi.student_number);
      		
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",zhaoliu.name,&zhaoliu.age,&zhaoliu.sex,&zhaoliu.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",zhaoliu.name,zhaoliu.age,zhaoliu.sex,zhaoliu.student_number);
          return 0;
      }
    3. 不指定结构体名而直接定义。

      struct {
          类型名 成员表列1
          类型名 成员表列2
              ···
      }变量名表列;

      代码示例:

      #include <stdio.h>
      int main()
      {
      	struct 
      	{
      		char name[30];
      		int age; 
      		char sex;
      		int student_number; 
      	}lisi,zhaoliu;
      
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",lisi.name,&lisi.age,&lisi.sex,&lisi.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",lisi.name,lisi.age,lisi.sex,lisi.student_number);
      		
      	printf("请输入学生的姓名 年龄 性别 学号:");
      	scanf("%s %d %c %d",zhaoliu.name,&zhaoliu.age,&zhaoliu.sex,&zhaoliu.student_number);
      	printf("参加比赛的学生有%s\t年龄:%d\t性别:%c\t学号:%d\n",zhaoliu.name,zhaoliu.age,zhaoliu.sex,zhaoliu.student_number);
          return 0;
      }
  • 结构体变量的使用:

    1. 使用结构体变量成员的方法:结构体变量名.成员名
    2. 当成员又是一个结构体时,使用对应结构体的方法:结构体变量名.成员名.成员名
    3. 当在输入.时,visual C++能自动识别出对应结构体中所包含的成员
    4. 同类的结构体变量可以互相赋值,例如lisi = zhaoliu

第二节 结构体数组

  • 可以定义int、char、float等类型的数组;也可以为结构体定义数组,表示一次性开辟多个结构体空间。

  • 结构体数组定义的方法:

    1. 创建的结构体类型之后,再定义结构体数组:结构体类型 数组名[数组个数]

      代码示例:

      #include <stdio.h>
      struct test
      {
      	char name[30];
      	int age; 
      	char sex;
      	int student_number; 
      };
      
      int main()
      {				
      	struct test class_five[10];	//定义了一个test类型的结构体数组,数组名为class_five,包含10个结构体  
      	return 0;
      }
    2. 创建结构体类型的同时定义结构体数组:

      struct 结构体名 {
          类型名 成员表列1
          类型名 成员表列2
              ···
      }变量名表列;

      代码示例:

      #include <stdio.h>
      int main()
      {
      	struct test
      	{
      		char name[30];
      		int age; 
      		char sex;
      		int student_number; 
      	}class_five[10]; //定义了一个test类型的结构体数组,数组名为class_five,包含10个结构体  
      	return 0;
      }

      实例:投票系统,为无忧村选举1名村长,预备村长有张三、李四、王五,村中一共有10名村民

      #include <string.h>
      #include <stdio.h>
      int main()
      {
      	struct piaoshu
      	{
      		char name[3];
      		int number; 
      	}ybcz[3] = {"zs",0,"ls",0,"ww",0};  // ybcz[0].name = "zs",ybcz[0].number =0;ybcz[1].name = "ls",ybcz[0].number =0;ybcz[0].name = "ww",ybcz[0].number =0;
      	int i,j ;
      	char name[3];
      	for(i = 0;i <10;i++)
      	{
      		printf("请投票:");
      		scanf("%s",name);
      		for(j = 0 ; j <3; j++)
      			if(strcmp(ybcz[j].name, name) == 0) ybcz[j].number++;
      	}
      	for(i = 0;i<3;i++)
      	printf("村名:%s\t的票数是:%d\n",ybcz[i].name,ybcz[i].number);
          return 0;
      }

第三节 结构体指针

  • 什么是结构体指针?

    一个结构体变量的起始地址就是结构体变量的指针。用一个指针变量存储结构体指针就是一个结构体指针变量。

    struct 结构体名 {
        类型名 成员表列1;
        类型名 成员表列2;
        	···
    }lisi;

    第八章 结构体和共用体

  • 指针指向结构体变量的使用

    指向结构体成员的方法:

    (*p).name
    (*p).age
    p -> name
    p -> age
    p -> student_number

    其中*p表达指向对应地址的内容,(*p)加上括号是由于.的优先级高于*

    ->表示指向运算符。

    代码示例:

    #include <string.h>
    #include <stdio.h>
    int main()
    {	
    	struct test
    	{
    		char name[30];
    		int age; 
    		char sex;
    		int student_number; 
    	}lisi ={"lisi",32,'M',20190305};
    
    	struct test *p;
    	p = &lisi;
    
    	strcpy((*p).name,"caojiu");
    	(*p).age = 28;
    	printf("姓名:%s\t年龄:%d\t性别%d\t学号:%d\n",p->name, p->age,p->sex,p->student_number);
        return 0;
    }
  • 指针指向结构体数组

    struct test {
        类型名 成员表列1;
        类型名 成员表列2;
        	···
    }student[3];

    第八章 结构体和共用体

    代码示例:

    #include <stdio.h>
    int main()
    {	
    	struct test
    	{
    		char name[30];
    		int age; 
    		char sex;
    		int student_number; 
    	}student[3];
    	struct test *p;
    
    	for(p = student;p< student+3; p++)
    	{
    		printf("请输入姓名 年龄 性别 学号:");
    		scanf("%s %d %c %d",p->name,&(p->age),&(p->sex),&(p->student_number));
    	}
    	for(p = student;p< student+3;p++)
    		printf("姓名:%s\t年龄:%d\t性别%d\t学号:%d\n",p->name, p->age,p->sex,p->student_number);
        return 0;
    }
  • 结构体与函数传递

    1. 结构体中的成员作为实参传递,和变量的使用方法一致;
    2. 结构体变量作为实参传递,由于形参接收实参时,也会在内存中开辟一个行同大小的空间,并且形参内容改变时,对应实参的内容不会被改变,因此这种传递方式不仅浪费空间,也不利于操作,一般不使用;
    3. 当结构体指针变量作为实参传递时,将指针地址赋值给形参。

    代码示例:

    #include <string.h>
    #iunclude <stdio.h>
    struct test
    {
    	char name[30];
    	int age; 
    	char sex;
    	int student_number; 
    };
    
    void change_info(char name[30],struct test *q)
    {
    	printf("修改%s的信息\n",name);
    	printf("修改为姓名 年龄 性别 学号:");
    	scanf("%s %d %c %d",q->name,&(q->age),&(q->sex),&(q->student_number));
    }
    
    int main()
    {
    	struct test lisi, *p = &lisi;
    	strcpy(lisi.name,"lisi");
    	change_info(lisi.name,p );
    	printf("姓名:%s\t年龄:%d\t性别%d\t学号:%d\n",p->name, p->age,p->sex,p->student_number);
        return 0;
    }

第四节 按需分配的空间

创建一个数据,在以前使用int、char、数组、结构体等来创建都是必须在使用之前给出固定的空间长度,但是大部分数据在使用之前是没有办法确定的,例如统计每天上网的网名,这一类的人数是一个动态的数据。

  • 如何创建一个按需分配的空间?

    链表可以实现存储空间动态分配的一种结构。它不是数据,而是通过代码人为的创建出一种空间动态分配方法。

    第八章 结构体和共用体

    NULL表示指针的内容为空,void表示数据类型为空。

    1. 由一个“头指针”变量存放链表中的第一个表;
    2. 每一个表包含实际的数据和下一个表的地址;
    3. 每个表的存储地址都是由系统分配的不连续的存储空间。

    代码示例:

    struct test
    {
    	char name[30];
    	int age; 
    	int student_number;
    	struct test *next;			//指向struct test类型数据的指针。
    };
    • 创建一个简单链表

      第八章 结构体和共用体

      代码示例:

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      struct test
      {
      	char name[30];
      	int age; 
      	int student_number;
      	struct test *next;			//指向struct test类型数据的指针。
      };
      int main()
      {
      	struct test a,b,c, *head,*p;
      
      	strcpy(a.name,"zhangsan");		//给各个结构体赋值
      	a.age = 16;
      	a.student_number = 1001;
      	strcpy(b.name,"lisi");
      	b.age = 19;
      	b.student_number = 1102;
      	strcpy(c.name,"wangwu");
      	c.age = 18;
      	c.student_number = 1009;
      
      	head =&a;					//把3个结构体构建成链表
      	a.next = &b;
      	b.next = &c;
      	c.next = NULL;
      	p = head;
      	while(p!= NULL)					//输出链表内容
      	{
      		printf("%d\n",p);
      		printf("姓名:%s\t年龄:%d\t学号:%d\n",p->name,p->age,p->student_number);
      		p = p->next;
      	}
          return 0;
      }
    • 创建动态链表

      第八章 结构体和共用体

      代码示例:

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      struct test
      {
      	char name[30];
      	int age; 
      	int student_number;
      	struct test *next;			//指向struct test类型数据的指针。
      };
      int main()
      {
      	struct test *head, *p1,*p2;
      	int n = 0;
      	
      	p1 = p2 = malloc(sizeof(struct test));			//添加第一个表的内容
      	printf("请输入姓名 年龄 学号:");
      	scanf("%s %d %d",p1->name,&p1->age,&p1->student_number);
      	head = NULL;
      	while(p1->student_number > 0)
      	{
      		n = n+1;								//	n =3
      		if(n == 1)	head = p1;						//创建链表
      		else p2->next = p1;
      		p2 = p1;
      		p1 = malloc(sizeof(struct test));			//循环添加表的内容
      		printf("请输入姓名 年龄 学号:");
      		scanf("%s %d %d",p1->name,&p1->age,&p1->student_number);
      	}
      	p2->next = NULL;
      													
      	p1 = head;
      	while(p1 != NULL)				//检查链表是否有内容,如果有内容就打印输出
      	{
      		printf("姓名:%s\t年龄:%d\t学号:%d\n",p1->name,p1->age,p1->student_number);
      		p1 = p1->next;
      	}
          return 0;
      }

第五节 共用体

  • 什么是共用体?

    多种不同的变量共用同一段内存的结构,称为共用体的结构。

    第八章 结构体和共用体

    例如在内存中开辟了4个字节的空间,可以用来存储int、float、char型数据,构建一种数据类型,使得开辟的空间可以存放几种不同类型的数据,但在使用的一瞬间只能存放一个数据,而不是同时存放多个数据。

    • 创建共用体类型:

      union 共用体名 {
          类型名 成员表列1;
          类型名 成员表列2;
          	···
          类型名 成员表列n;
      };
    • 定义共用体变量的方法:

      union 共用体名 变量名

      1. 在定义之前已经创建好共用体类型时,结构体变量所占内存大小是成员中占内存最大的那个;

      2. union 共用体名 {
            类型名 成员表列1;
            类型名 成员表列2;
            	···
            类型名 成员表列n;
        }

        代码示例:

        #include <stdio.h>
        union info
        {
        	int a;
        	char b;
        	float c;
        };
        
        int main()
        {
        	union info x;				//占内存4字节
        
        	x.a = 100;
        	printf("%d\t%c\t%f\n",x.a,x.b,x.c);
            return 0;
        }
    • 共用体变量的使用方法:

      注:使用共用体之前需要定义。

      例如:定义了共同体变量x

      x.a 		//引用共用体变量中的整型变量a
      x.b 		//引用共用体变量中的字符变量b
      x.c 		//引用共用体变量中的浮点型变量c

      说明:

      1. 共用体初始化时,只能存储一个数据,不能同时存储多个数据;
      2. 对共用体变量非同时的进行多次赋值在,则共用体变量中的数据是最近一次赋值的数据;
      3. 共用体的成员都使用相同的地址;
      4. 同类型的共用体变量可以相互赋值 `y = x;`
      

      代码示例:

      #include <stdio.h>
      int main()
      {
      	union info
      	{	int a;
      		char b;
      		float c;
      	}x={100};				
      	
      	x.c = 3.14f;				
      	x.b = 'y';										//ASCII码后部分是成员c遗留的
      
      	printf("%d\t%c\t%f\n",x.a,x.b,x.c);
      	printf("%d\t%d\t%d\n",&x.a,&x.b,&x.c);
          return 0;
      }

      实例:填写公司员工信息

      #include <stdio.h>
      struct	info		//一般配合struct,上节课的链表一般在处理大型数据的时候使用
      {	char name[20];
      	int age;
      	char work;
      	union
      	{	int gzsc;
      		char xueli[10];		
      	}fen;
      };
      
      int main()
      {
      	struct info a[2];
      	int i;
      	for(i = 0; i <2; ++i)
      	{
      		printf("请填写入职信息:姓名 年龄 职务[c表示程序员,s表示设计师]\n");
      		scanf("%s %d %c",a[i].name,&a[i].age,&a[i].work);
      		if(a[i].work == 's')
      		{	printf("请输入您工作时长:");
      			scanf("%d",&a[i].fen.gzsc);		
      		}
      		else
      		{	printf("请输入您的学历:");
      			scanf("%s",a[i].fen.xueli);		
      		}
      	}
      	for(i = 0; i <2 ; ++i)
      	{
      		if(a[i].work == 's') printf("姓名:%s\t年龄%d\t职务:%c\t工作时长:%d\n",a[i].name,a[i].age,a[i].work,a[i].fen.gzsc);
      		else 	printf("姓名:%s\t年龄%d\t职务:%c\t学历:%s\n",a[i].name,a[i].age,a[i].work,a[i].fen.xueli);
      	}
          return 0;
      }

第六节 枚举

如果一个变量只有几种可能的值,则可以使用枚举的方法定义数据类型。

  • 什么是枚举

    枚举是将一个变量所有可能的值一一列举出来,对应的值只能是列举出来的值中的一个,例如猜丁壳的游戏里面,只有石头剪刀布这三种。

  • 如何构建枚举类型

    enum 枚举类型名 {1,2, ···, 值n
    }
    //enum cdk{shitou, jiandao, bu}
  • 定义枚举变量

    enum cdk a, b	//其中a和b分别为cdk类型的数据,且a,b的值只能是shitou, jiandao, bu

    说明:枚举元素(shitou, jiandao, bu)都代表一个整数,元素值的默认顺序为0,1,2,3, ···,也可以人为修改元素值。

第七节 替换类型名

可以使用typedef将已有的类型名进行替换。

  • typedef替换类型名的方式:按定义变量的方式,将变量名替换为需要的类型名,并在最开头写上typedef

    typedef int ii[100];			//int a[100];创建一个类型代表数组
    typedef char cc[30];			//char s[30];
    typedef char *zhi;			//char *p;
    ii a;
    cc s;
    zhi p;