Loading... # 七、结构体与C++引用 ## 1. 结构体的定义、初始化、结构体数组 有时候需要将不同类型的数据组合为一个整体,以便于引用。例如, 一名学生有学号、姓名、性别、年龄、地址等属性,如果针对学生的学号、姓名、年龄等都单独定义一个变量,那么在有多名学生时,变量就难以分清。为此,C语言提供结构体来管理不同类型的数据组合。 声明一个结构体类型的一般形式为 ```c struct 结构体名 {成员表列}; ``` ```c struct student { int num;char name[20];char sex; int age;float score;char addr[30]; }; ``` 先声明结构体类型, 再定义变量名。 ```c struct student student1, student2; ``` 【例】结构体的 scanf读取和输出。 ```c #include <stdio.h> struct student{ int num; char name[20]; char sex; int age; float score; char addr[30]; };//结构体类型声明,注意最后一定要加分号 int main() { struct student s={1001,"lele",'M',20,85.4,"Shenzhen"}; struct student sarr[3];//定义一个结构体数组变量 int i; //结构体输出必须单独去访问内部的每个成员 s.num=1003; printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr); printf("--------------------------------------\n"); // scanf("%d%s %c%d%f%s",&s.num,s.name,&s.sex,&s.age,&s.score,s.addr); for(i=0;i<3;i++) { scanf("%d%s %c%d%f%s",&sarr[i].num,sarr[i].name,&sarr[i].sex,&sarr[i].age,&sarr[i].score,sarr[i].addr); } for(i=0;i<3;i++)//结构体数组的输出 { printf("%d %s %c %d %f %s\n",sarr[i].num,sarr[i].name,sarr[i].sex,sarr[i].age,sarr[i].score,sarr[i].addr); } return 0; } ``` 结构体类型声明要放在main函数之前,这样main函数中才可以使用这个结构体,工作中往往把结构体声明放在头文件中,注意,**结构体类型声明最后一定要加分号**, 否则会编译不通。另外, 定义结构体变量时, 使用 struct student来定义, 不能只有struct或student, 否则也会编译不通,sarr是结构体数组变量. **结构体的初始化只能在一开始定义**,如果 struct students={1001,"lele",'M',20,85.4,"Shenzhen"}已经执行, 即 struct student s已经定义, 就不能再执行s={1001,"lele",'M',20,85.4,"Shenzhen"}. **如果结构体变量已经定义, 那么只能对它的每个成员单独赋值, 如 s. num=1003.** 采用“结构体变量名.成员名”的形式来访问结构体成员,例如用s.num访问学号。在进行打印输出时,必须访问到成员,而且printf中的%类型要与各成员匹配,使用scanf读取标准输入时,也必须是各成员取地址,然后进行存储,不可以写成&s,即不可以直接对结构体变量取地址.整型数据(%d)、浮点型数据(%f) 、字符串型数据(%s)都会忽略空格,但是字符型数据(%c)不会忽略空格,所以如果要读取字符型数据,那么就要在待读取的字符数据与其他数据之间加入空格. 例中代码的运行结果如下 ```c 1003 lele M 20 85.400002 Shenzhen -------------------------------------- 1001 Lele M 20 85.4 Shenzhen 1005 leli M 21 86.4 Shenzhen 1002 lile M 25 81.4 Shenzhen 1001 Lele M 20 85.400002 Shenzhen 1005 leli M 21 86.400002 Shenzhen 1002 lile M 25 81.400002 Shenzhen ``` ## 2. 结构体对齐 结构体本身的对齐规则有好几条,考研初试只需要记住一条,**结构体的大小必须是其最大成员的整数倍!** ```c #include <stdio.h> struct student_type1{ double score;//double是一种浮点类型,8个字节,浮点分为float和double,记住有这两种即可 short age;//short 是整型,占2个字节 }; struct student_type2{ double score; int height;//如果两个小存储之和是小于最大长度8,那么它们就结合在一起 short age; }; struct student_type3{ int height; char sex; short age; }; //结构体对齐 int main() { struct student_type1 s1; struct student_type2 s2={1,2,3}; struct student_type3 s3; printf("s1 size=%d\n",sizeof(s1)); printf("s2 size=%d\n",sizeof(s2)); printf("s3 size=%d\n",sizeof(s3)); return 0; } ``` ```c s1 size=16 s2 size=16 s3 size=8 ``` ## 3. 结构体指针 一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设置一个指针变量,用它指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素, 从而能够通过结构体指针快速访问结构体内的每个成员。 【例】结构体指针的使用。 ```c #include <stdio.h> struct student{ int num; char name[20]; char sex; }; //结构体指针的练习 int main() { struct student s={1001,"wangle",'M'}; struct student sarr[3]={1001,"lilei",'M',1005,"zhangsan",'M',1007,"lili",'F'}; struct student *p;//定义了一个结构体指针变量 p=&s; printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员 printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种 p=sarr; printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员 printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种 printf("------------------------------\n"); p=p+1; printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员 printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种 return 0; } ``` ```c 1001 wangle M 1001 wangle M 1001 lilei M 1001 lilei M ------------------------------ 1005 zhangsan M 1005 zhangsan M ``` p就是一个结构体指针, 可以对结构体s取地址并赋给 p,这样借助成员选择操作符,就可以通过 p访问结构体的每个成员,然后进行打印。我们知道数组名中存储的是数据的首地址,所以可以将sarr赋给p,这样就可以通过两种方式访问对应的成员。 使用(\*p). num访问成员为什么要加括号呢? 原因是“.”成员选择的优先级高于“\*”(即取值) 运算符, 所以必须加括号, 通过\*p 得到 sarr[0], 然后获取对应的成员。 ## 4. typedef 的使用 前面定义结构体变量时使用的语句是 struct students,有些麻烦,可以选择使用 typedef 声明新的类型名来代替已有的类型名 例。 ```c #include <stdio.h> //stu 等价于 struct student,pstu等价于struct student* typedef struct student{ int num; char name[20]; char sex; }stu,*pstu; typedef int INGETER;//特定地方使用 //typedef的使用,typedef起别名 int main() { stu s={1001,"wangle",'M'}; stu *p=&s;//定义了一个结构体指针变量 pstu p1=&s;//定义了一个结构体指针变量 INGETER num=10; printf("num=%d,p->num=%d\n",num,p->num); return 0; } ``` ```c num=10,p->num=1001 ``` 使用 stu定义结构体变量和使用 struct student定义结构体变量是等价的; 使用 INTEGER定义变量i和使用 int定义变量i是等价的; pstu等价于 struct student*, 所以p 是结构体指针变量. ## 5. C++的引用 对于 C++, 首先新建源文件时, 名字需要叫main. cpp,以cpp后缀结尾 使用了引用后,在子函数内的操作和函数外操作手法一致,这样编程效率较高,对于初学者理解也非常方便, 王道数据结构书籍中均采用了这种手法。 那这种C++的写法, 和C语言的代码又是如何对应的呢? 下面我们来看一下代码对应关系。 【例】在子函数内修改主函数的普通变量 ```c++ #include <stdio.h> //当你在子函数中要修改主函数中变量的值,就用引用,不需要修改,就不用 void modify_num(int &b)//形参中写&,要称为引用 { b=b+1; } //C++的引用的讲解 //在子函数内修改主函数的普通变量的值 int main() { int a=10; modify_num(a); printf("after modify_num a=%d\n",a); return 0; } ``` 改为纯c ```c #include <stdio.h> void modify_num(int *b) { *b=*b+1; } int main(){ int a=10; modify_num(&a); printf("after modify_num a=%d\n",a); return 0; } ``` 【例】子函数内修改主函数的一级指针变量(**重要!**) ```c++ #include <stdio.h> void modify_pointer(int *&p,int *q)//引用必须和变量名紧邻 { p=q; } //子函数内修改主函数的一级指针变量 int main() { int *p=NULL; int i=10; int *q=&i; modify_pointer(p,q); printf("after modify_pointer *p=%d\n",*p); return 0;//进程已结束,退出代码为 -1073741819 ,不为0,那么代表进程异常结束 } ``` ```c after modify_pointer *p=10 ``` 改为纯c,就需要使用到二级指针(可以不理解) ```c #include <stdio.h> void modify_pointer(int **p, int *q)//相对于 C++这里是 int **p; { *p=q;//这里的写法和例中的是非常类似的 } int main(){ int*p=NULL; int i=10; int*q=&i; modify_pointer(&p,q);//相对于 C++这里是&p printf("after modify_pointer *p=%d\n",*p); return 0; } ``` ## 6. C++的布尔类型 布尔类型在C语言没有, 是C++的, 有 true和 false 【例】 布尔类型也是有值的 ```c #include <stdio.h> int main() { bool a= true; bool b= false; printf("a=%d,b=%d\n",a,b); return 0; } ``` ```c a=1,b=0 ``` ## 7.例题 使用C++的引用,注意提交时把代码选为C++;在主函数定义字符指针 char *p,然后在子函数内malloc申请空间(大小为100个字节),通过fgets读取字符串,然后在主函数中进行输出;要求子函数使用C++的引用,注意在C++中从标准输入读取字符串,需要使用fgets(p,100,stdin) | Sample Input 1 | Sample Output | | ----------------- | ----------------- | | I love C language | I love C language | | how are you | how are you | ```c #include <stdio.h> #include <stdlib.h> //当子函数要修改主函数中的p,那么就加引用。引用如何实现的,完全不需要去关心 void modify_pointer(char *&p) { p=(char*)malloc(100);//申请100个字节大小的空间 fgets(p,100,stdin);//stdin代表标准输入,fgets是安全的 } //课时8作业2 练习C++的引用的使用 int main() { char *p=NULL; modify_pointer(p); puts(p); free(p);//申请的空间不使用后,记得free,避免扣分 return 0; } ``` End 本文作者: 彼岸花露 文章标题:七、结构体与C++引用(C语言) 本文地址:https://www.tianlei.work/archives/115/ 版权说明:若无注明,本文皆悟思记原创,转载请保留文章出处。 最后修改:2024 年 04 月 14 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏
此处评论已关闭