结构体和共用体
结构体变量
C语言数据类型:
- 基本类型
- 整型类型:基本整型(int)、短整型(short int)、长整型(long int)、双长整型(long long int)、字符型(char)、布尔型(bool)
- 浮点类型:单精度浮点型(float_complex)、双精度浮点型(double_complex)、复数浮点型(float_complex,double_complex,long long_complex)
- 枚举类型(enum)
- 空类型(void)
- 派生类型:指针类型(*)、数组类型([ ])、结构体类型(struct)、共用体类型(union)、函数类型
什么是结构体
将多种数据类型结合构建在一起的数据类型称为结构体类型
应用场景:需要多个数据类型来表示某一信息时,可以使用结构体
例如:学生李四和赵六参加比赛需要在网络上填写信息包含:存在不同的数据类型
name:lisi,sex:M,age:23,student_number:20193055;
name:zhaoliu,sex:M,age:22,student_number:20193091;
...
传统示例:
#include "stdio.h"
void main()
{
// 第一个学生的信息
char name_1[10];
char sex_1;
int age_1;
int student_number_1;
printf("请输入学生的姓名 性别 年龄 学号:");
scanf("%s %c %d %d", name_1, &sex_1, &age_1, &student_number_1);
printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", name_1, sex_1, age_1, student_number_1);
// 第二个学生的信息
char name_2[10];
char sex_2;
int age_2;
int student_number_2;
printf("请输入学生的姓名 性别 年龄 学号:");
scanf("%s %c %d %d", name_2, &sex_2, &age_2, &student_number_2);
printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", name_2, sex_2, age_2, student_number_2);
/* ... */
}
结果:
请输入学生的姓名 性别 年龄 学号:lisi M 23 20193055
参加比赛的学生有:lisi, 性别:M, 年龄:23, 学号:20193055
请输入学生的姓名 性别 年龄 学号:zhaoliu M 22 20193091
参加比赛的学生有:zhaoliu,性别:M, 年龄:22, 学号:20193091
/* ... */
Press any key to continue
创建结构体类型
创建结构体类型方法:
struct 结构体名
{
类型名 成员表1
类型名 成员表2
...
};
示例:
#include "stdio.h"
struct test
{
char name[10];
char sex;
int age;
int student_number;
};
void main()
{
struct test lisi, zhaoliu /* ... */;
// 第一个
printf("请输入学生的姓名 性别 年龄 学号:");
scanf("%s %c %d %d", lisi.name, &lisi.sex, &lisi.age, &lisi.student_number);
printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", lisi.name, lisi.sex, lisi.age, lisi.student_number);
// 第二个
printf("请输入学生的姓名 性别 年龄 学号:");
scanf("%s %c %d %d", zhaoliu.name, &zhaoliu.sex, &zhaoliu.age, &zhaoliu.student_number);
printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", zhaoliu.name, zhaoliu.sex, zhaoliu.age, zhaoliu.student_number);
/* ... */
}
结果:
请输入学生的姓名 性别 年龄 学号:lisi M 23 20193055
参加比赛的学生有:lisi, 性别:M, 年龄:23, 学号:20193055
请输入学生的姓名 性别 年龄 学号:zhaoliu M 22 20193091
参加比赛的学生有:zhaoliu,性别:M, 年龄:22, 学号:20193091
/* ... */
Press any key to continue
说明:
-
创建结构体类型是指创建的数据类型
-
结构体名是指对应创建的数据类型名,例如之前学习的int型,float型,其中int 和float是数据类型名
-
成员表列可以包含多个同类型及不同类型的数据,每个成员以 ; 分隔,结构体{}之后有一个 ;
-
成员也可以是另一个结构体类型
例如:
struct score { int Chinese; int Math; int English; /* ... */ } struct test { char name[10]; char sex; int age; int student_number; struct score examination; };
定义结构体变量
在没有定义结构体之前,系统不会分配存储空间。为了使用结构体变量,需要在使用之前进行定义
-
先创建结构体类型,再定义
在文件的开头创建好结构体类型,然后在函数中使用定义结构体变量
定义的方法为:
struct 结构体名 结构体变量名
例如:
struct test lisi;
-
在创建类型同时定义
struct 结构体名 { 类型名 成员表1 类型名 成员表2 ... }变量名表列;
示例:
#include "stdio.h" void main() { struct test { char name[10]; char sex; int age; int student_number; }lisi, zhaoliu /* ... */; // 第一个 printf("请输入学生的姓名 性别 年龄 学号:"); scanf("%s %c %d %d", lisi.name, &lisi.sex, &lisi.age, &lisi.student_number); printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", lisi.name, lisi.sex, lisi.age, lisi.student_number); // 第二个 printf("请输入学生的姓名 性别 年龄 学号:"); scanf("%s %c %d %d", zhaoliu.name, &zhaoliu.sex, &zhaoliu.age, &zhaoliu.student_number); printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", zhaoliu.name, zhaoliu.sex, zhaoliu.age, zhaoliu.student_number); /* ... */ }
结果:
请输入学生的姓名 性别 年龄 学号:lisi M 23 20193055 参加比赛的学生有:lisi, 性别:M, 年龄:23, 学号:20193055 请输入学生的姓名 性别 年龄 学号:zhaoliu M 22 20193091 参加比赛的学生有:zhaoliu,性别:M, 年龄:22, 学号:20193091 /* ... */ Press any key to continue
-
不指定结构体名而直接定义
struct { 类型名 成员表1 类型名 成员表2 ... }变量名表列;
示例:
#include "stdio.h" void main() { struct { char name[10]; char sex; int age; int student_number; }lisi, zhaoliu /* ... */; // 第一个 printf("请输入学生的姓名 性别 年龄 学号:"); scanf("%s %c %d %d", lisi.name, &lisi.sex, &lisi.age, &lisi.student_number); printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", lisi.name, lisi.sex, lisi.age, lisi.student_number); // 第二个 printf("请输入学生的姓名 性别 年龄 学号:"); scanf("%s %c %d %d", zhaoliu.name, &zhaoliu.sex, &zhaoliu.age, &zhaoliu.student_number); printf("参加比赛的学生有:%s,性别:%c,年龄:%d,学号:%d\n", zhaoliu.name, zhaoliu.sex, zhaoliu.age, zhaoliu.student_number); /* ... */ }
结果:
请输入学生的姓名 性别 年龄 学号:lisi M 23 20193055 参加比赛的学生有:lisi,性别:M,年龄:23,学号:20193055 请输入学生的姓名 性别 年龄 学号:zhaoliu M 22 20193091 参加比赛的学生有:zhaoliu,性别:M,年龄:22,学号:20193091 /* ... */ Press any key to continue
说明:结构体成员表名在结构体内唯一,但可以和其他变量名相同
结构体变量的使用
-
使用结构体变量成员的的方法:
结构体变量名.成员名
例如:
lisi.name,lisi.sex, lisi.age, lisi.student_number
-
当成员又是一个结构体时,使用对应结构体的方法:
结构体变量名.成员名.成员名
例如:
lisi.examination.Chinese
-
当在输入.时,软件能自动识别出对应结构体中所包含的成员
-
同类的结构体变量可以互相赋值
例如:
lisi = zhaoliu
结构体数组
可以定义int、 char、float等类型的数组;也可以为结构体定义数组,表示一次性开辟多个结构体空间
结构体数组定义的方法:
-
创建的结构体类型之后,再定义结构体数组:
结构体类型 数组名[数组个数]
例如:
#include "stdio.h" struct test { char name[10]; char sex; int age; int student_number; }; void main() { struct test class_five[10]; //定义一个test类型的结构体数组,数组名为class_five,包含10个结构体 }
-
创建的结构体类型同时定义结构体数组:
struct 结构体名 { 类型名 成员表1 类型名 成员表2 ... }变量名表列;
例如:
struct test { char name[10]; char sex; int age; int student_number; }class_five[10];
实例:投票系统
示例:
#include "stdio.h"
void main()
{
struct ticket_number
{
char name[3];
int number;
} initial_number[3] = {"A", 0, "B", 0, "C", 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(initial_number[j].name, name) == 0)
initial_number[j].number++;
}
for (i = 0; i < 3; i++)
printf("%s\t的票数是:%d\n", initial_number[i].name, initial_number[i].number);
}
结果:
请输入准备投票的姓名:A
请输入准备投票的姓名:A
请输入准备投票的姓名:A
请输入准备投票的姓名:B
请输入准备投票的姓名:B
请输入准备投票的姓名:B
请输入准备投票的姓名:B
请输入准备投票的姓名:B
请输入准备投票的姓名:C
请输入准备投票的姓名:C
A 的票数是:3
B 的票数是:5
C 的票数是:2
Press any key to continue
结构体指针
什么是结构体指针
一个结构体变量的起始地址就是结构体变量的指针。用一个指针变量存储结构体指针就是一个结构体指针变量
struct 结构体名
{
类型名 成员表1
类型名 成员表2
...
}lisi;
指针指向结构体变量的使用
指向结构体成员的方法:
(*p).name
(*p).age
//其中*p表达指向对应地址的内容。(*p)加上括号是由于.的优先级比*高
或
p->name
p->age
p->student_number
//->表示指向运算符
示例:
#include "stdio.h"
#include "string.h"
void main()
{
struct test
{
char name[10];
char sex;
int age;
int student_number;
} lisi = {"lisi", 23, 'M', 20193055};
struct test *p;
p = &test;
strcpy((*p).name, "zhaoliu");
(*p).age = 30;
printf("姓名:%s\t性别:%c\t年龄:%d\t学号:%d\n", (*p).name, (*p).sex, (*p).age, (*p).student_number);
}
结果:
姓名:zhaoliu 性别:M 年龄:30 学号:20193055
Press any key to continue
指针指向结构体数组
struct test
{
类型名 成员表1
类型名 成员表2
...
}student[3];
例如:
struct test (*p) = student;
示例:
#include "stdio.h"
void main()
{
struct test
{
char name[10];
char sex;
int age;
int student_number;
} student[3];
struct test *p;
for (p = student; p < student + 3; p++)
{
printf("请输入姓名 性别 年龄 学号:");
scanf("%s %c %d %d", p->name, &(p->sex), &(p->age), &(p->student_number));
printf("姓名:%s\t性别:%c\t年龄:%d\t学号:%d\n", p->name, p->sex, p->age, p->student_number);
}
}
结果:
请输入姓名 性别 年龄 学号:zhangsan W 20 1000
请输入姓名 性别 年龄 学号:lisi M 25 2000
请输入姓名 性别 年龄 学号:wangwu M 30 3000
姓名:zhangsan 性别:W 年龄:20 学号:1000
姓名:lisi 性别:M 年龄:25 学号:2000
姓名:wangwu 性别:M 年龄:30 学号:3000
Press any key to continue
结构体与函数传递
- 结构体中的成员作为实参传递,和变量的使用方法一致
- 结构体变量作为实参传递,由于形参接收实参时,也会在内存中开辟一个相同大小的空间,并且形参内容改变时,对应实参 的内容不会被改变,因此这种传递方式不仅大大的浪费空间,也不利于操作,一般不适用(这个方法几乎不使用)
- 当结构体指针变量作为实参传递时,将指针地址赋值给形参
示例:
#include "stdio.h"
#include "string.h"
struct test
{
char name[10];
char sex;
int age;
int student_number;
};
void revise_info(char name[10], struct test *p)
{
printf("修改%s的信息\n", name);
printf("修改为姓名 性别 年龄 学号:");
scanf("%s %c %d %d", p->name, &(p->sex), &(p->age), &(p->student_number));
}
void main()
{
struct test lisi, *q = &lisi;
strcpy(lisi.name, "lisi");
revise_info(lisi.name, q);
printf("姓名:%s\t性别:%c\t年龄:%d\n学号:%d\n", q->name, q->sex, q->age, q->student_number);
}
结果:
修改lisi的信息
修改为姓名 性别 年龄 学号:lisi W 30 4000
姓名:lisi 性别:W 年龄:30 学号:4000
Press any key to continue
按需分配的空间
创建一个数据,在以前使用int、char、数组、结构体等来创建都是必须在使用之前给出固定的空间长度;但是大部分数据在使用之前是没有办法确定的,例如:统计每天上网的网名(网名上网的人数是一个动态的数据)
如何创建一个按需分配的空间
链表可以实现存储空间动态分配的一种结构。它不是数据类型,而是通过代码人为的创建出的一种空间动态分配方法
例如:
struct test
{
char name[10];
int age;
int student_number;
struct test *next; //指向struct test类型数据的指针 //struct test NULL;
};
NULL表示指针的内容为空,void表示数据类型为空
- 有一个“头指针”变量存放链表中第一个表
- 每一个表包含实际的数据和下一个表的地址
- 每个表的地址由系统分配的不连续空间
建一个简单链表(静态链表)
示例:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
void 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;
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;
}
}
结果:
1703700
姓名:zhangsan 年龄:16 学号:1001
1703656
姓名:lisi 年龄:19 学号:1102
1703612
姓名:wangwu 年龄:18 学号:1009
Press any key to continue
创建动态链表
示例:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
struct test
{
char name[10];
int age;
int student_number;
struct test *next;
};
void 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;
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;
}
}
结果:
请输入姓名 年龄 学号:zhangsan 20 1000
请输入姓名 年龄 学号:lisi 25 2000
请输入姓名 年龄 学号:wangwu 30 3000
请输入姓名 年龄 学号:0 0 0
姓名:zhangsan 年龄:20 学号:1000
姓名:lisi 年龄:25 学号:2000
姓名:wangwu 年龄:30 学号:3000
Press any key to continue
共用体
什么是共用体
多种不同的变量共用同一段内存的结构,称为共用体类型的结构
例如:在内存中开辟了4个字节的空间,可以用来存储int、float、char型数据
构建一种数据类型,使得开辟的空间可以存放几种不同类型的数据,但在使用的一瞬间只能存放一个数据,而不是同时存放多个数据
创建共用体类型
union 共用体名
{
类型名 成员表1
...
类型名 成员表n
};
示例:
#include "stdio.h"
union info
{
int a;
char b;
float c;
};
void main()
{
union info x; //占内存4字节
x.a = 100;
printf("%d\t%c\t%f\n",x.a,x.b,x.c);
}
结果:
100 d 0.000000
Press any key to continue
定义共用体变量的方法
-
在定义之前已经创建好共用体类型的时:
union 共用体名 变量名
-
union 共用体名 { 类型名 成员表1 ... 类型名 成员表n }变量名表列;
注:结构体变量所占内存大小是成员中占内存最大的那一个
共用体变量的使用方法
注:使用共用体变量之前需要定义
例如:定义了共用体变量x
x.a 引用共用体变量中的整型变量a
x.b 引用共用体变量中的字符变量b
x.c 引用共用体变量中的浮点型变量c
示例:
#include "stdio.h"
void main()
{
union info
{
int a;
char b;
float c;
}x={100};
x.c = 3.14f;
x.b = 'y';
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);
}
结果:
1078523257 y 3.139982
1703740 1703740 1703740
Press any key to continue
说明:
- 共用体初始化时,只能存储一个数据,不能同时存储多个数据
- 对共用体变量非同时的赋多次值,则共用体变量中的数据是最近一次赋值的数据
- 共用体的成员都使用相同的地址
- 同类型的共用体变量可以互相赋值 y = x
实例:填写公司员工信息
示例:
#include "stdio.h"
struct info
{ char name[10];
int age;
char work;
union
{ int gzsc;
char xueli[10];
}fen;
};
void main()
{
struct info a[2];
int i;
for(i = 0; i <2; ++i)
{
printf("请填写入职信息:姓名 年龄 职务(‘c’表示程序员,‘s’表示设计师):");
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);
}
}
结果:
请填写入职信息:姓名 年龄 职务(‘c’表示程序员,‘s’表示设计师):lisi 25 c
请输入你的学历:benke
请填写入职信息:姓名 年龄 职务(‘c’表示程序员,‘s’表示设计师):wangwu 27 s
请输入你的工作时长:3
姓名:lisi 年龄:25 职务:c 学历:benke
姓名:wangwu 年龄:27 职务:s 工作时长:3
Press any key to continue
枚举
如果一个变量只有几种可能的值,则可以使用枚举的方法定义数据类型
什么是枚举
枚举是将一个变量所有可能的值一一列举出来,对应的值只能是列举出来的值中的一个
例如:猜丁壳的游戏里面,只有剪子包子锤这三种
如何构建枚举类型
enum 枚举类型名{值1,值2,...,值n}
例如:
enum cdk{jianzi,chui,baozi}
定义枚举变量
enum cdk a,b
其中 a 和 b 分别为 cdk 类型的数据,且 a , b 的值只能是 jianzi ,cuizi ,baozi
示例:
#include "stdio.h"
void main()
{
enum cdk {jianzi,chui,baozi};
enum cdk a;
a = jianzi;
printf("%d\n",a);
printf("%d\n",jianzi);
printf("%d\n",chui);
printf("%d\n",baozi);
}
结果:
0
0
1
2
Press any key to continue
说明:其中枚举元素(jianzi,baozi,chui)都代表一个整数,默认按照顺序元素值为0,1,2,3,…,也可以人为修改元素值
替换类型名
可以使用typedef将已有的类型名进行替换
typedef如何替换类型名
按定义变量的方式,将变量名替换为需要的类型名,并在最开头写上typedef
例如:
typedef int x[100];
typedef char y[30];
typedef char *z;
x a; //int a[100];创建一个类型代表数组
y s; //char s[30];
z p; //char *p;
示例:
#include "stdio.h"
void main()
{
typedef int y;
typedef char c;
y a = 1; //int a =1;
c b = 'w'; //char b = 'w';
printf("%d\n",a);
printf("%c\n",b);
}
结果:
1
w
Press any key to continue
结构体类型名替换
示例:
#include "stdio.h"
void main()
{
typedef struct test
{
char name[10];
int age;
}x;
x lisi; //struct test lisi;
lisi.age = 10;
printf("%d\n",lisi.age);
}
结果:
10
Press any key to continue
标签:name,int,age,number,lisi,student,共用,结构
From: https://www.cnblogs.com/ruoxianshi/p/17033117.html