08结构体与C++引用讲解
一、上节作业(重点)
-
假如有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?为便于读者理解题意,这里举例说明如下:假如有3个台阶,那么总计就有3种走法:第一种为每次上1个台阶,上3次;第二种为先上2个台阶,再上1个台阶;第三种为先上1个台阶,再上2个台阶。输入为n,输出为走到第n个台阶有几种走法
#include <stdio.h>
int step(int i)
{
if(i==1 || i==2)
{
return i;
}
return step(i-1)+step(i-2);
}
int main() {
int i,res;
scanf("%d",&i);
res=step(i);
printf("%d\n",res);
return 0;
}
二、结构体-结构体对齐-结构体数组
1.结构体的定义、初始化、结构体数组
-
有时候需要将不同类型的数据组合为一个整体, 以便于引用, C 语言提供结构体来管理不同类型的数据组合。
-
声明一个结构体类型的一般形式
struct 结构体名
{成员表列};
-
先声明结构体类型, 再定义变量名。
-
例子
#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"};
//结构体输出必须单独去访问内部的每个成员
printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr);
scanf("%d%s %c%d%f%s",&s.num,s.name,&s.sex,&s.age,&s.score,s.addr);
printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr);
return 0;
}
-
结果
1001 lele M 20 85.400002 shenzhen
2002 lili F 22 88 chongqing
2002 lili F 22 88.000000 chongqing
-
例子
#include <stdio.h>
struct student{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
int main() {
struct student sarr[3];
int i;
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;
}
-
结果
1001 lily M 20 45 shenzhen
1002 bily F 22 78 chongqing
1003 Mary F 23 99 hubei
1001 lily M 20 45.000000 shenzhen
1002 bily F 22 78.000000 chongqing
1003 Mary F 23 99.000000 hubei
-
结构体类型声明要放在main函数之前,这样main函数中才可以使用这个结构体。工作中往往把结构体声明放在头文件中。
-
结构体类型声明最后一定要价分好,否则会编译不通。
-
定义结构体变量时,使用struct 结构体名来定义,否则也会编译不通。
-
结构体的初始化只能在一开始定义,如果结构体变量已经定义,那么职能对它的每个成员单独赋值。 如果 struct student s={1001,"lele",'M',20,85.4,"Shenzhen"}已经执行, 即 struct student s 已经定义, 就不能再执行 s={1001,"lele",'M',20,85.4,"Shenzhen"}。
-
采用结构体变量名.成员名形式来访问结构体成员。 例如用 s.num 访问学号。
-
在进行打印输出时, 必须访问到成员, 而且 printf 中的%类型要与各成员匹配。
-
使用 scanf 读取标准输入时, 也必须是各成员取地址, 然后进行存储, 不可以写成&s, 即不可以直接对结构体变量取地址。
-
整型数据(%d) 、 浮点型数据(%f) 、 字符串型数据(%s) 都会忽略空格, 但是字符型数据(%c) 不会忽略空格, 所以如果要读取字符型数据, 那么就要在待读取的字符数据与其他数据之间加入空格。
2.结构体对齐
-
结构体的大小必须是其最大成员的整数倍。
-
sizeof(s)=68的由来:int num为4字节;char name为20字节;char sex为1字节;int age为4字节;float score为4字节;char addr为30字节;总计63字节;因为结构体的大小必须是其最大成员的整数倍,则char sex处+3字节,char addr处+2字节;总计为68字节。
-
为什么要进行结构体对齐?为了CPU能够高效读取内存中的数据。
-
通过地址总线找到数据(每次4个字节),通过数据总线传递数据。
-
浮点类型分为float(占用4个字节)和double(占用8个字节)。
-
整型分为short(占用2个字节)和int(占用4个字节)。
-
例子
#include <stdio.h>
struct student_type1{
double score;
short age;
};
struct student_type2{
double score;
int height;
short age;
};
struct student_type3{
int height;
char sex;
short age;
};
int main() {
struct student_type1 s1;
struct student_type2 s2;
struct student_type3 s3;
printf("s1=%d\n",sizeof(s1));
printf("s2=%d\n",sizeof(s2));
printf("s3=%d\n",sizeof(s3));
return 0;
}
-
结果
s1=16//double占用8字节,int占用4字节,short占用2字节,int+short+补齐的2字节
s2=16//double占用8字节,char占用1字节,short占用2字节,char+short+补齐的5字节
s3=8//int占用4字节,char占用1字节,short占用2字节,char+short+补齐的1字节
-
如果两个小存储之和是小于最大长度,那么他们就结合在一起。
三、结构体指针与typedef的使用
1.结构体指针
-
一个结构体变量的指针就是该变量所占据的内存段的起始地址。
-
可以设置一个指针变量,用它指向一个结构体变量, 此时该指针变量的值是结构体变量的起始地址。 指针变量也可以用来指向结构体数组中的元素, 从而能够通过结构体指针快速访问结构体内的每个成员。
-
使用(*p).num 访问成员为什么要加括号呢? 原因是“.” 成员选择的优先级高于“*” (即取值) 运算符, 所以必须加括号, 通过*p 得到 sarr[0], 然后获取对应的成员。
-
结构体指针访问成员,优先使用“→”成员选择。
-
例子
#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,"zhangshan",'M',1007,"lily",'M'};
struct student *p;//定义结构体指针
p=&s;
printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);
printf("%d %s %c\n",p->num,p->name,p->sex);
p=sarr;//数组名中存储的是数据的首地址,等价于p=&sarr[0];
printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);
printf("%d %s %c\n",p->num,p->name,p->sex);
p=p+1;
printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);
printf("%d %s %c\n",p->num,p->name,p->sex);
return 0;
}
-
结果
1001 wangle M
1001 wangle M
1001 lilei M
1001 lilei M
1005 zhangshan M
1005 zhangshan M
2.typedef的使用
-
可以选择使用 typedef 声明新的类型名来代替已有的类型名。
-
使用 stu 定义结构体变量和使用 struct student 定义结构体变量是等价的。
-
pstu 等价于 struct student*, 所以 p 是结构体指针变量。
-
例子
#include <stdio.h>
//struct student{
// int num;
// char name[20];
// char sex;
//};
//int main() {
// struct student s={0};
// return 0;
//}
typedef struct student{
int num;
char name[20];
char sex;
}stu,*pstu;
int main() {
stu s={0};
pstu p=&s;//等价于stu *p=&s;
return 0;
}
-
使用 INTEGER定义变量 i 和使用 int 定义变量 i 是等价的。
-
例子
#include <stdio.h>
typedef int INTEGER;//可以修改int类型,后续INTEGER统一修改类型
int main() {
INTEGER num=10;
printf("%d\n",num);
return 0;
}
-
局部变量名可以与成员名相同。
四、C++引用的讲解
1.C++的引用讲解
-
对于 C++, 首先新建源文件时, 名字需要叫 main.cpp,以 cpp 后缀结尾。
-
我们在修改函数外的某一变量时, 使用了引用后, 在子函数内的操作和函数外操作手法一致, 这样编程效率较高, 对于初学者理解也非常方便。
-
当需要在子函数中修改主函数中变量的值,就用引用,否则,则不用。
-
例子
main.cpp
#include <stdio.h>
//C++完全兼容C
//在子函数内修改主函数的普通变量的值
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;
}
-
结果
after modify_num a=11
-
例子( 上面的代码如果改为纯 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);
}
-
结果
after modify_num a=11
-
例子
#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;
}
-
结果
after modify_pointer *p=10
-
例子( 上面的代码如果改为纯 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;
}
-
结果
after modify_pointer *p=10
2.C++的布尔类型
-
布尔类型在C语言中没有,在C++中有true和false。
-
例子
#include <stdio.h>
int main() {
bool a=true;
bool b=false;
printf("a=%d,b=%d\n",a,b);
return 0;
}
-
结果
a=1,b=0

5万+






