结构体类型( struct)
1 结构体相关的概念
C语言属于面向过程的一门语言,C语言开发工程师在编写代码时也要具有对象的思想,
C语言表示对象的方式就是结构体类型。在C语言中通过结构体类型描述一个对象。什么是对象?
事件的万事万物都可以看出一个对象,通过编程语言抽象的描述一个对象。如何描述一个对象?
将一类对象具有共同的属性和行为剥离处理,非共性的东西剥离出去;
比如人:姓名,年龄,身高,体重,性别,外貌, 吃喝拉撒睡。属性:对象的名词,形容词,量词 —> 抽象成代码:使用变量表示
行为:对象的动词(可以干什么)—> 抽象成代码:使用函数表示结构体的概念
结构体属于C语言中的一个自定义的构造类型,关键字(struct)。
将很多不同的数据类型封装成一个新的数据类型,这个数据类型就是结构体类型,
结构体中的成员在内存空间中是连续的,并且每个成员都有其独立的内存空间。声明一个结构体类型
没有结构体的沟通类型,如何描述一个对象:char name[20]; int age; char sex; int score; ----> 只能描述一个对象,
如果描述多个对象,在重新定义多次。
如果描述多个对象,在重新定义多次。
有结构体的沟通类型,如何描述一个对象:
struct student{ // 声明一个结构体类型,此时struct student就表示一个结构体类型名, // 使用此类型可以定义结构体类型的变量 char name[20]; int age; char sex; int score; };
// 定义一个对象
struct student stu1;
// 定义100个对象
struct student stu_arr[100];
2 声明结构体类型的语法格式
// 1. 声明一个结构体类型, 声明结构体类型时并没有在内存中分配空间
struct 结构体名{
数据类型 变量名1;
数据类型 变量名2;
数据类型 变量名3;
…
数据类型 变量名n;
};
此时"struct 结构体名"就是自己构造的新的结构体类型,使用此结构体类型定义结构体类型的变量。
结构体中的成员的类型可以是:基本的数据类型,数组类型,指针类型,指针数组,数组指针,函数指针,
函数指针数组,嵌套的结构体类型,枚举类型,联合体类型。
3 定义结构体类型的变量
- 定义普通的结构体类型的变量:
struct 结构体名 结构体变量名;- 定义结构体指针类型的变量:
struct 结构体名 *结构体指针变量名;
4 结构体中成员的访问
- 定义普通的结构体类型的变量:
结构体变量名.成员变量名;- 定义结构体指针类型的变量:
结构体指针变量名->成员变量名;
5 定义普通的结构体类型的变量,并访问
5.1 先声明结构体类型,在定义结构体类型的变量
声明结构体类型
struct student{ char name[20]; int age; char sex; int score; };
定义普通结构体类型的变量 : struct 结构体名 结构体变量名;
struct student stu;
对结构体中的成员进行初始化
3.1> 定义结构体类型变量的同时进行初始化
struct student stu1 = {"yy", 18, 'M', 100};
// 要求按照结构体中成员的类型依次进行初始化
3.2> 先定义结构体类型变量,后进行初始化 : 结构体变量名.成员变量名 = 初始值;struct student stu2; strcpy(stu2.name, "yy"); stu2.age = 18; stu2.sex = 'M'; stu2.score = 100;
3.3> 定义结构体类型变量的同时进行初始化
struct student stu1 = { .name = "yy", .age = 18, .sex = 'M', .sorce=100 };
优点:可以只对部分成员初始化,成员初始化的顺序没有要求。
#include <stdio.h>
#include <string.h>
// 1. 声明结构体类型,结构体类型中的成员根据自己的对象添加对应的成员
struct student
{
char name[20];
int age;
char sex;
int score;
};
// 相同结构体类型的变量,可以进行赋值操作,
// 结构体类型作为函数的形参使用
void print(struct student s)
{
printf("我的名字叫%s,我的年龄%d,我的性别%c,我的成绩%d\n",
s.name, s.age, s.sex, s.score);
}
int main(int argc, const char *argv[])
{
/*your code*/
// 1. 先定义结构体类型的变量,在对结构体变量中的成员初始化
struct student stu1;
strcpy(stu1.name, "yy");
stu1.age = 18;
stu1.sex = 'M';
stu1.score = 100;
print(stu1);
// 2. 定义结构体类型变量的同时进行初始化
struct student stu2 = {"yy", 28,'M',88};
print(stu2);
// 3. 定义结构体类型变量的同时进行初始化
struct student stu3 = {
.name = "lisi",
.sex = 'W',
.age = 24,
.score = 99
};
print(stu3);
return 0;
}
5.2 声明结构体类型的同时定义结构体类型的变量
声明结构体类型的同时定义结构体类型的变量
struct student{ char name[20]; int age; char sex; int score; }stu1, stu2, stu3;
对结构体类型的变量进行初始化
2.1> 声明结构体类型的同时定义结构体变量,同时初始化。struct student{ char name[20]; int age; char sex; int score; }stu1={"yy",18,'M',100};
2.2> 声明结构体类型的同时定义结构体变量,同时初始化。
struct student{ char name[20]; int age; char sex; int score; }stu2 = { .name = "yy", ,age = 18, .sex = 'M', .score = 100};
2.3> 声明结构体类型的同时定义结构体变量,最后在进行初始化。
struct student{ char name[20]; int age; char sex; int score; }stu3; strcpy(stu3.name, "yy"); stu3.age = 18; stu3.sex = 'M'; stu3.score = 100;
没有结构体名字的结构体:
声明结构体类型的同时定义结构体类型的变量, 省略结构体的名字,
后续不可以单独使用这个结构体类型在定义新的变量。struct { char name[20]; int age; char sex; int score; }stu1, stu2, stu3;
对结构体类型的变量进行初始化
2.1> 声明结构体类型的同时定义结构体变量,同时初始化。struct { char name[20]; int age; char sex; int score; }stu1={"yy",18,'M',100};
2.2> 声明结构体类型的同时定义结构体变量,同时初始化。
struct { char name[20]; int age; char sex; int score; }stu2 = { .name = "yy", ,age = 18, .sex = 'M', .score = 100 };
2.3> 声明结构体类型的同时定义结构体变量,最后在进行初始化。
struct { char name[20]; int age; char sex; int score; }stu3; strcpy(stu3.name, "yy"); stu3.age = 18; stu3.sex = 'M'; stu3.score = 100;
练习题:定义教师结构体类型,成员姓名(字符数组name),年龄(age),工资(salary)。
并使用类定义结构体变量,对成员进行初始化。
#include <stdio.h>
#include <string.h>
// 声明结构体类型的同时定义结构体变量
struct teacher
{
char name[20];
int age;
int salary;
}tea1 = {"yy", 18, 30000},
tea2 = {
.name = "yy",
.age = 18,
.salary = 35000},
tea3;
void print(struct teacher t)
{
printf("姓名:%s, 年龄:%d, 工资:%d\n",
t.name, t.age, t.salary);
}
int main(int argc, const char *argv[])
{
/*your code*/
// 先声明结构体类型,定义结构体变量,后进行初始化
strcpy( tea3.name, "yy");
tea3.age = 16;
tea3.salary = 32000;
print(tea1);
print(tea2);
print(tea3);
return 0;
}
6 定义结构体指针类型的变量,并访问
声明结构体类型
struct student { char name[20]; int age; char sex; int score; };
定义结构体指针变量
struct student *p;
对结构体指针变量进行初始化
3.1 结构体指针变量指向栈区的空间:struct student stu = {"yy", 18, 'M', 100}; // 定义普通结构体变量 struct student *p = &stu; struct student *p = NULL; p = &stu;
3.2 结构体指针变量指向堆区的空间:
struct student *p = (struct student *)malloc(sizeof(struct student)); strcpy(p->name, "yy"); p->age = 18; p->sex = 'M'; p->score = 100;
如果定义的是结构体指针变量,没有以下初始化的方式,原因是结构体指针变量占8字节空间(64位系统)
struct student *p = { ->name = "yy", ->age = 18, ->sex = 'M', ->score = 100, };
测试:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 1. 声明结构体类型
struct student
{
char name[20];
int age;
char sex;
int score;
};
// 函数的形参是一个结构体指针类型
void print(struct student *t)
{
printf("姓名:%s, 年龄:%d, 性别:%c, 成绩:%d\n",
t->name, t->age, t->sex, t->score);
}
int main(int argc, const char *argv[])
{
/*your code*/
// 2. 定义结构体指针类型的变量,指向一个栈区的结构体变量
struct student stu = {"yy", 18, 'M', 100};
print(&stu);
struct student *p1 = &stu;
print(p1);
// 3. 定义结构体指针类型的变量,指向一个堆区的空间。
struct student *p2 = (struct student *)malloc(sizeof(struct student));
if (p2 == NULL)
{
printf("malloc memory failed!\n");
return -1;
}
strcpy(p2->name, "yy");
p2->age = 18;
p2->sex = 'M';
p2->score = 100;
print(p2);
return 0;
}
7 结构体中的成员包含指针类型的成员
1. 声明结构体类型
struct student {
char *name;
int *age;
};
2. 定义结构体类型的变量并进行初始化
int m_age = 18;
struct student stu = {"yy", &m_age}; // char *name指向的是一个字符串常量
char m_name[20]= "yy";
int m_age = 18;
struct student stu = {m_name, &m_age}; // char *name指向的是一个字符数组
struct student stu;
stu.name = (char *)malloc(sizeof(char)*20); // char *name成员指向堆区空间
stu.age = (int *)malloc(sizeof(int)); // int *age成员指向堆区空间
strcpy(stu.name, "yy");
*stu.age = 18;
struct student *p1 = &stu;
struct student *p2 /*定义结构体指针变量,p2在栈区分配8字节空间 */
= (struct student *)malloc(sizeof(struct student));
/* 让P2指向堆区空间, 给p2->name成员分配8字节空间,存放地址
给p2->age成员分配8字节空间,存放地址 */
/*对p2中的name成员分配堆区空间并指向堆区的空间 */
p2->name = (char *)malloc(sizeof(char)*20); // char *name成员指向堆区空间
/*对p2中的age成员分配堆区空间并指向堆区的空间 */
p2->age = (int *)malloc(sizeof(int)); // int *age成员指向堆区空间
// 对堆区的空间进行初始化。
strcpy(p2->name, "yy");
*p2->age = 18;
测试:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char *name;
int *age;
};
void print(struct student *s)
{
printf("姓名:%s, 年龄:%d\n", s->name, *s->age);
}
int main(int argc, const char *argv[])
{
/*your code*/
int m_age = 18;
// 定义普通的结构体变量,并进行初始化
struct student stu1 = {"yy", &m_age}; // char *name指向的是一个字符串常量
// int *age 指向的一个int类型的变量
print(&stu1);
char m_name[20] = "yy";
// 定义普通的结构体变量,并进行初始化
struct student stu2 = {m_name, &m_age}; // char *name指向的是一个字符数组
// int *age 指向的一个int类型的变量
print(&stu2);
// 定义普通结构体变量,让结构体中的指针类型的成员指向堆区空间
struct student stu3;
stu3.name = (char *)malloc(sizeof(char) * 20); // char *name成员指向堆区空间
stu3.age = (int *)malloc(sizeof(int)); // int *age成员指向堆区空间
// 对堆区的空间进行初始化操作
strcpy(stu3.name, "ff");
*stu3.age = 18;
print(&stu3);
// 定义结构体指针变量, 指向普通的结构体类型的变量
struct student *p1 = &stu3;
print(p1);
// 定义结构体指针变量,指向堆区空间,结构体中的成员也指向堆区空间
struct student *p2 /*定义结构体指针变量,p2在栈区分配8字节空间 */
= (struct student *)malloc(sizeof(struct student));
/* 让P2指向堆区空间, 给p2->name成员分配8字节空间,存放地址
给p2->age成员分配8字节空间,存放地址 */
/*对p2中的name成员分配堆区空间并指向堆区的空间 */
p2->name = (char *)malloc(sizeof(char) * 20); // char *name成员指向堆区空间
/*对p2中的age成员分配堆区空间并指向堆区的空间 */
p2->age = (int *)malloc(sizeof(int)); // int *age成员指向堆区空间
// 对堆区的空间进行初始化。
strcpy(p2->name, "ff");
*p2->age = 18;
print(p2);
return 0;
}
8 定义结构体数组
声明结构体类型
struct student { char name[20]; int age; char sex; int score; };
定义结构体数组变量 : struct student 结构体数组名[数组的长度];
struct student arr[2];
对数组的成员进行初始化
3.1> 定义的同时进行初始化
struct student arr[2] = {{"yy",18,'M',100},{"yy",18,'M',90}};
3.2> 定义的同时进行初始化
struct student arr[2] = { [0] = { .name = "yy", .age = 18, .sex = 'M', .score = 100 }, [1] = { .name = "yy", .age = 18, .sex = 'M', .score = 90 } };
3.3> 先定义结构体数组,后进行初始化
struct student arr[2]; strcpy(arr[0].name, "yy"); arr[0].age = 18; arr[0].sex = 'M'; arr[0].score = 100; strcpy(arr[1].name, "yy"); arr[1].age = 18; arr[1].sex = 'M'; arr[1].score = 90;
结构体数组中每个元素中的每个结构体成员的访问
void print(struct student *s, int len) { int i; for (i = 0; i < len; i++) { printf("%s %d %c %d\n", s[i].name, s[i].age, s[i].sex, s[i].score); printf("%s %d %c %d\n", (s + i)->name, (s+i)->age, (s+i)->sex, (s+i)->score); } }
练习题:定义教师结构体类型,成员姓名(字符数组name),年龄(age),工资(salary)。
并使用类定义结构体变量,对成员进行初始化
结构体数组实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct teacher
{
char name[20];
int age;
int salary;
};
int main(int argc, const char *argv[])
{
struct teacher tea[10];
int n=0;//教师人数
printf("请输入教师人数>");
scanf("%d",&n);
for(int i=1;i<=n;i++){
printf("教师%d的姓名:",i);
scanf("%s",tea[i].name);
printf("年龄:");
scanf("%d",&(tea[i].age));
printf("工资:");
scanf("%d",&(tea[i].salary));
}
printf("打印教师工资表>\n");
for (int i=1; i<=n;i++)
{
printf("教师%d的姓名:%s 年龄:%d 工资:%d\n",i,tea[i].name,tea[i].age,tea[i].salary);
}
return 0;
}
结构体指针实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct teacher
{
char name[20];
int age;
int salary;
};
int main(int argc, const char *argv[])
{
int n=0;//教师人数
printf("请输入教师人数>");
scanf("%d",&n);
// struct teacher tea[10];
struct teacher *tea=(struct teacher *)malloc(sizeof(struct teacher)*n);
if(NULL==tea) printf("malloc memory filed!\n");
for(int i=0;i<n;i++){
printf("教师%d的姓名:",i+1);
// scanf("%s",(*(tea+i)).name);
scanf("%s",(tea+i)->name);
printf("年龄:");
// scanf("%d",&((*(tea+i)).age));
scanf("%d",&(tea+i)->age);
printf("工资:");
// scanf("%d",&((*(tea+i)).salary));
scanf("%d",&(tea+i)->salary);
}
printf("打印教师工资表>\n");
for (int i=0; i<n;i++)
{
// printf("教师%d的姓名:%s 年龄:%d 工资:%d\n",i+1,(*(tea+i)).name,(*(tea+i)).age,(*(tea+i)).salary);
printf("教师%d的姓名:%s 年龄:%d 工资:%d\n",i+1,(tea+i)->name,(tea+i)->age,(tea+i)->salary);
}
return 0;
}
9 定义结构指针数组
结构指针数组:本质是一个数组,数组中的成员都是结构体的指针。
格式:
struct 结构体名 *结构体指针数组名[元素个数];初始化:
struct 结构体名 结构体变量0;
struct 结构体名 结构体变量1;
…定义结构体指针数组的同时进行初始化:
struct 结构体名 *结构体指针数组名[元素个数] = {&结构体变量0, &结构体变量1};先定义结构体指针数组,后进行初始化:
struct 结构体名 *结构体指针数组名[元素个数];
结构体指针数组名[下标] = &结构体变量0;
结构体指针数组名[下标] = &结构体变量1;访问结构体指针数组的每个元素,每个元素都是一个结构体指针类型,并访问结构体中的每个成员。
结构体指针数组名[下标]->结构体成员名;
10 定义结构体数组指针
结构体数组指针 : 本质是一个指针,指向的是一个结构体二维数组
格式:
struct 结构体名 (*结构体数组指针名)[元素个数];初始化
定义的同时进行初始化:
struct 结构体名 结构体数组名[元素个数] = {{},{},…};
struct 结构体名 (*结构体数组指针名)[元素个数] = &结构体数组名;先定义后进行初始化:
struct 结构体名 (*结构体数组指针名)[元素个数];
结构体数组指针名 = &结构体数组名;成员的访问
(*结构体数组指针名)[下标].结构体成员名;或者
((*结构体数组指针名)+下标)->结构体成员名;
11 相同结构体类型变量可以进行赋值操作
相同结构体类型的变量可以进行赋值操作。
struct student
{
char name[20];
int age;
char sex;
int score;
};
struct student stu1 = {"yy", 18, 'M', 100};
struct student stu2 = stu1; // 普通结构体变量进行赋值
struct student *p = NULL; // 结构体指针变量进行赋值
*p = &stu1;
struct student *p2 = p; // 结构体指针变量进行赋值
12 小结
声明一个结构体类型:
struct teacher{ char *name; int age; char sex; int salary; };
// 1. 定义普通的结构体变量,并初始化,完成成员的访问(3种)
// 2. 定义结构体指针, 并初始化,指向堆区的空间或者栈区空间,并访问成员(堆区、栈区)
// 3. 定义结构体数组,并初始化,已经完成数组的每个元素及元素中的每个成员的访问(3种)
// 4. 定义结构体指针数组, 并初始化,访问成员(2种)
// 5. 定义结构体数组指针,并初始化,以及成员的访问
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct teacher{
char *name;
int age;
char sex;
int salary;
}tea;
int main(int argc, const char *argv[])
{
//1. 定义普通的结构体变量,并初始化,完成成员的访问(3种)
tea t1={"y1",18,'M',10000};//方法一
tea t2={.name="y2",.age=19,.sex='M',.salary=100};//方法二
//方法三
tea t3;
t3.name="y3";
t3.age=20;
t3.sex='M';
t3.salary=10000;
// 2. 定义结构体指针, 并初始化,指向堆区的空间或者栈区空间,并访问成员
//在栈区
tea t4={"y4",18,'M',10000};
tea *p1_t4=&t4;
//在堆区
tea *p2=(tea *)malloc(sizeof(tea));
if(NULL==p2)printf("malloc memory filed!\n");
// 给结构体中的指针赋值的方式(3种)
//结构体中name指针直接指向常量区
p2->name="p2";
//结构体中name指针指向栈区
char name[20]="yy";
p2->name=name;
//结构体中name指针指向堆区
p2->name=(char *)malloc(sizeof(20));
strcpy(p2->name,"yy");
p2->age=20;
p2->sex='M';
p2->salary=1000;
free(p2);
p2=NULL;
// #define DEBUG
#ifdef DEBUG1
//error初始化,原因:指针的大小只有8字节(64位系统),不能存储那么多数据
int *p3={
->name="p3",
->age=20,
->sex='M',
->salary=200}
#endif
// 3. 定义结构体数组,并初始化,已经完成数组的每个元素及元素中的每个成员的访问(3种)
tea t5[2]={{"y5",18,'M',10000},{"y6",18,'M',10000}};//方法一
tea t6[2]={
[0]={"y5",18,'M',10000},
[1]={"y6",18,'M',10000}
};//方法二
//方法三
tea t7[2];
t7[0].name="y7";
t7[0].age=20;
t7[0].sex='M';
t7[0].salary=2000;
t7[1].name="y8";
t7[1].age=20;
t7[1].sex='M';
t7[1].salary=2000;
//访问
for(int i=0;i<2;i++){
printf("%s %d %c %d\n",t7[i].name,t7[i].age,t7[i].sex,t7[i].salary);
printf("%s %d %c %d\n",(*(t7+i)).name,(*(t7+i)).age,(*(t7+i)).sex,(*(t7+i)).salary);
printf("%s %d %c %d\n",(t7+i)->name,(t7+i)->age,(t7+i)->sex,(t7+i)->salary);
}
// 4. 定义结构体指针数组, 并初始化,访问成员(2种)
tea t9={"y9",18,'M',10000};
tea t10={"y10",18,'M',10000};
tea *t8[2]={&t9,&t10};//方法一,定义结构体指针数组的同时进行初始化
//访问
for(int i=0;i<2;i++){
printf("%s %d %c %d\n",(*t8[i]).name,(*t8[i]).age,(*t8[i]).sex,(*t8[i]).salary);
}
//方法二,先定义结构体指针数组,后进行初始化
tea *t11[2];
t11[0]=&t9;
t11[1]=&t10;
//访问
for(int i=0;i<2;i++){
printf("%s %d %c %d\n",t11[i]->name,t11[i]->age,t11[i]->sex,t11[i]->salary);
}
// 5. 定义结构体数组指针,并初始化,以及成员的访问(2种)
//方法一:定义的同时进行初始化
tea t13[2]={{"y13",18,'M',10000},{"y13",19,'M',10000}};
tea (*t12)[2]=&t13;
//访问:
for(int i=0;i<2;i++){
printf("%s %d %c %d\n",(*t12)[i].name,(*t12)[i].age,(*t12)[i].sex,(*t12)[i].salary);
printf("%s %d %c %d\n",(*((*t12)+i)).name,(*((*t12)+i)).age,(*((*t12)+i)).sex,(*((*t12)+i)).salary);
printf("%s %d %c %d\n",((*t12)+i)->name,((*t12)+i)->age,((*t12)+i)->sex,((*t12)+i)->salary);
}
//方法二:先定义后进行初始化
tea (*t14)[2];
t14=&t13;
//访问:
for(int i=0;i<2;i++){
printf("%s %d %c %d\n",(*t14)[i].name,(*t14)[i].age,(*t14)[i].sex,(*t14)[i].salary);
printf("%s %d %c %d\n",(*((*t14)+i)).name,(*((*t14)+i)).age,(*((*t14)+i)).sex,(*((*t14)+i)).salary);
printf("%s %d %c %d\n",((*t14)+i)->name,((*t14)+i)->age,((*t14)+i)->sex,((*t14)+i)->salary);
}
return 0;
}