C++复盘笔记4

typedef详解

typedef的作用是取别名
1、自定义数据类型 typedef int A[3];
这样 A 就变成了一个数据类型 A B;//这里就定义了一个数组 int B[3]
2、结构体中的应用
typedef struct
{
int a;
float b;
}snake;
这样你创建结构体变量的时候就可以不用写struct了 (针对于c语言 c++本来就不用写struct)
struct snake temp; —>snake temp;

数组元素的多种表示方法

例如现在有一个二维数组 int a[n][n];

下表表示法:

a[i][j];//表示a中第i-1行第j-1列的元素
a[i]表示a中的第i行 也是 a[i][0]的地址

指针表示法:

a+i;//表示a中的第i行 也就是a[i] 为什么呢 ???
因为a就是a[0]是一个二级指针 而且是一个int[3];数组的内存是连续的类型的指针
指针在做加减法运算的时候就是加上加上或者减去他只想的数据类型的大小乘以它加上或者减去的那个数
所以 a+i 就是把a[0] 往后移动了 34i 个位置 所以就变成了a[i]
(a+i)+j//表示&a[i][j] 按照上面的说法 a+i表示 a[i] 是一个二级指针 (a+i)就是对a[i]解引用一次 所以(a[i]) 就就成了a[i][0]的指针 然后再加上j就是往后移动j4个位置 所以就变成了 a[i][j]的指针
所以再解引用一次才是a[i][j]的值:即*(*(a+i)+j);

混合表示法:

*(a[i]+j);//表示 a[i][j] 这里容易和上面发生矛盾但是记住 如果直接写a[i]+j的时候就是在第i行移动到j列的位置 所以就是a[i][j]的地址

指针

变量内存的实质

内存就是存放数据的空间 就像电影院的作为编号一样 内存也要编号 这就是内存编址 电影院是一个座位一个编号 而内存则是一个字节一个地址
定义一个变量的时候 type 变量名;
这样就定义了一个type类型的变量 同时在内存中开辟了一块空间来储存该变量 占sizeof(type)个字节的空间 地址就是第一个字节的地址

指针是什么

指针其实就是一个特殊的变量,只不过它储存的是变量的地址

指针和数组名

其实数组名也是一个指针只不过它所储存的地址不可以改变 其它的功能和一般的指针一样

指针常量和常量指针

const int ic = 20; //定义了一个常变量 ic
int const ic = 20;//定义了一个常变量 ic
所以const int和int const的效果一样
const int a;和 int const a 也是一样的 都是定义了一个常量指针(常量的指针) 不可以通过指针来修改所存地址所指内存储存的值 因为指向的是一个常量 这好理解 因为const修饰的是a 而a不就是地址所指内存的值吗

再看int const a;//这里a就是指针常量(指针是常量)了 因为const修饰的是指针a 所以a的指向不能改变了
再看下面三种情况
1、 int pi;
const int i=10;
pi=&i;//错误 不可以用普通的指针指向常量
但是改成pi=(int
)&i;//这样编译可以通过 但是还是不能同故宫pi修改i的值
2、 const int
pi;
const int i=10;
pi=&i;//可以 类型相同 但是不可以通过pi修改i的值
3、 int i=10;
const int *const pi=&i;//这样 pi既不可以修改指向也不可以通过pi修改i的值
这也叫指向常量的指针常量

多级指针

指向指针的指针叫多级指针
一般最多也就二级指针

函数名和函数指针

函数名是一个指向函数的指针常量 而函数指针是指向函数的指针变量
他们都是指针
int add(int a,int b);//这里声明了一个函数
int *func(int,int);//这里定义了一个函数指针
给函数指针赋值:
func=&add;
func=add;
上面两种方式都对
其实调用函数的时候也有两种写法
(*add)(int a,int b);
add(int a,int b);
如果用函数指针来调用函数也有两种写法:
func(int a,int b);
(*func)(int a,int b);

指针的赋值

int p=100;//错误 100是一个int型常量 不是一个常量地址
int p=(char)100;//危险 100是一个无意义的地址 可能指向危险区域
int
p=nullptr;//空指针 也可以写成 int*p=0;

不同类型的指针之间的赋值

对于不同类型的指针不可以直接赋值
但是可以进行强转以后再赋值
char*p=nullptr;
int pi=(int)p;

特殊类型指针—void型指针

void v;//错误 不能定义void 型变量
void *pv;//定义void 型指针
int pi,i;
pv=&i;//void 型指针指向int型变量
pv=pi;//将int型地址赋值给void 型指针
pi=pv;//错误 注意其他类型的指针可以直接赋值给void型指针 但是要把void型指针赋值给其他类型指针必须先强转为那个类型
pi=(int
)pv;//把void型指针强转为int型指针才可以赋值给pi

引用

什么是引用

从逻辑上讲引用时已存在变量的别名 通过引用可以间接访问变量 而且比指针安全
引用一般是用来描述函数的参数 和返回值 特别是传递较大的数据变量
对引用的操作实际上就是对被引用变量的操作
例如:
int a=0;
int&p=a;//p就是a的引用
p=10;//可以直接通过引用修改被引用变量的值 a=10
引用其实是一个隐性的指针 引用于被引用的变量看似直接访问实际上是间接访问
这幕后的工作时由编译来完成的 编译将引用转换为指针 因此引用不能直接操作自身的地址

相较于指针引用有很多好处:
引用不占用新的地址 节省了内存开销
隐去了地址操作 封锁了对地址的可修性 这使得通过引用访问更安全
考虑到引用的安全性 高级编程多用引用

引用与函数

引用作为函数参数

注意:传进来的实参必须是左值
可以通过引用修改实参的值(引用传递)

引用作为函数返回值

注意:返回的必须是左值
返回的变量不能是临时变量(例如函数里面定义的变量)

常引用

const type&引用变量名=变量名;
定义一个常引用之后就不能通过引用来修改引用变量的值了
但是可以通过变量自身来修改
常引用作为函数的形参的时候 成为只读形参 保证了实参的值不被修改
形参为常引用的时候 实参可以是常量 也可以是变量表达式

结构体和联合体

结构体

基本概念

定义结构体:
struct 结构类型名
{
type1 a;
type2 b;

typen n;
};
注意:在定义结构体的时候不能够初始化成员变量 因为定义结构体的时候并没有分配内存
只有在定义结构体变量的时候才分配了内存
定义结构体变量:
1、定义结构体的时候定义、
struct student
{
int a;
float b;
}s001;//定义了结构体变量s001
2、定义结构体后定义
studnet s002;
3、结构体名缺省
struct
{
int a;
int b;
}t1,t2,t3;//没有结构体名 定义了三个结构体变量 t1 t2 t3但是后面就不能再定义结构体变量了
结构体成员访问
结构体变量名.成员名;
结构体指针名->成员名;
结构体数组
元素为结构体变量的数组

结构体内存对齐问题详解

#include<iostream>
using namespace std;
//c++结构体内存对齐:即一般情况下结构体内的每一个成员储存的内存内部首地址要被该数据的大小(字节数)整除第一个成员的内部地址为0
//下面是结构体内存对齐的四条规则
//1、结构体成员的内部偏移量(内部地址,这里把第一个成员的首地址看成0,例如一个结构体有两个成员 int 和 short 那么int成员首地址为0 sgort成员首地址为4)要被这个成员的大小整除
//2、整个结构体的大小必须为最大成员大小的整数倍 空出来的有编译器填充空白字节
//3、对于结构体中的结构体,按照结构体展开后的内存对齐来处理(相当于把成员结构体的成员拿出来当成主结构体的成员)
//4、认为指定特定的对齐规则
//一般使用 #pragma pack(n) (n为2的指数 1,2,4,8,16)这样书写后后面的结构体成员对齐字节为结构体成员字节和n中较小的那个  如果要取消该对齐规则只要写一个#pragma pack()就行了
//如果n>最大成员字节 那么就按照默认对齐规则来对齐
//注意:字符数组的对齐规则还是1不是数组长度 默认对齐规则是根据数据类型而定的
//

struct person
{
	int s_a;
	char s_b;
	double s_c;
};//结构体大小为16个字节因为int 占用的内部内存地址为0 1 2 3 char 占用的为4 double 占用的为 8 9 10 11 12 13 14 15  又要为8的倍数所以为16
 
struct hhh
{
	int an;
	struct person bb;
};//0123 ~31 大小应为32  结果为24说明成员结构体在算内存的时候不能看成一个数据类型而是把相当于直接把他的成员直接搬到主结构中了
//在书写结构体成员的时候尽量从小到大或者从大到小  相同类型写一起这样节省空间   例如下面第二个结构体比第一个小
struct an1
{
	char a[3];
	short b;
	int c;
	char d;
};//16个字节

struct an2
{
	char a;
	short b;
	char c[3];
	int d;
};//12个字节

struct s1
{
	char a;
	int b;

};//8个字节

#pragma pack(1)
struct s2
{
	char a;
	int b;

};//5个字节
#pragma pack()
struct s3
{
	char a;
	int b;

};//8个字节

void test()
{
	cout << "size of struct person为: " << sizeof(person) << endl;//16
	cout << "size of struct an1为: " << sizeof(an1) << endl;//16
	cout << "size of struct an2为: " << sizeof(an2) << endl;//12
	cout << "size of struct s1为: " << sizeof(s1) << endl;//8
	cout << "size of struct s2为: " << sizeof(s2) << endl;//5
	cout << "size of struct s3为: " << sizeof(s3) << endl;//8
	cout << "sizeof(hhh):" << sizeof(hhh);//24
}

int main()
{
	test();
	system("pause");
	return 0;
}

联合体(共用体)

联合体也称共用体 是一种与结构体类似的数据类型
它提供了一种可以将几种不同类型数据存放再同一段内存 对其中各个成员可以按名存取的机制
联合类型变量所占的内存大小为各个成员所占内存大小的最大值 如果其中由构造的数据类型(数组 类 结构体)那么大小为其中最长的***基本数据类型**的整数倍 比如一个联合体有两个成员 char a[10] 和double b 那么它的大小就是2sizeof(double)=18
定义:
union 联合类型名
{
type1 a;
type2 b;

typen n;
};

联合体变量只能初始化第一个成员
定义无名联合类型的时候 其中的成员可以直接当作变量使用
例如:
union {
char c;
int i;
};
c=‘a’;
i=10;
cout<<c;//A 因为c和i有着共同的内存单元 所以最终c=65(ASCLL码值为65) 也就是’A’
由于无名联合体既有联合成员共内存的性质 又有直接存取联合成员的性质 所以常用于结构体中
定义联合体变量:
联合类型名 变量名;
存取成员变量:变量名.成员变量名
指针名->成员变量名;

联合变量在内存中的排列

规则:各成员在内存中的排列都从低地址开始 遵循“”低地址低字节 高地址高字节“的原则
数据在内存中存放的原则

什么是低地址,高地址,高字节,低字节呢

比如一个整形变量 int a=10;
a所占的内存空间的每一个字节的地址分别为:0x000~0x003
其中0x000就是低地址 0x003就是高地址

再比如一个十六进制的数
一个16进制数有两个字节组成,例如:A9。
高字节就是指16进制数的前8位(权重高的8位),如上例中的A。
低字节就是指16进制数的后8位(权重低的8位),如上例中的9。

不同的数据的存储规则

(1)一个整数类型内部
低地址存储低位,高地址存储高位。
(2)若干个局部变量(在栈中存储的)
先定义的高地址,后定义的低地址。
(3)类、结构体或数组的元素
先定义的低地址,后定义的高地址。

现在通过一个具体的例子来理解一下:

union UData{
char Ch;
short Sint;
long Lint;
unsigned Uint;
float f;
double d;
char str[10];
};
UData u;
strcpy(u.str,"123456789");
cout<<u.Ch;//1
cout<<u.Sint;//3231
cout<<u.Lint;//34333231
cout<<u.Uint;//34333231
cout<<u.f;//1.66889e-007
cout<<u.d;//6.82132e-038
cout<<u.str;//123456789

在这里插入图片描述
上面的0x31 0x32 …分别是这些字符对应的十六进制的ascll/码值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pp不会算法^v^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值