文章目录
1. 指针
1.1 内存和地址
在计算机中数据是在内存中存储,且内存也被划分为一个个内存单元,每个内存单元大小为1个字节,1个字节也是8个比特位
而上图中0XFFFFFFFF
这就是内存单元的编号,通过访问编号我们可以找到对应的字节空间,因此也可以理解为内存单元的编号=地址=指针
1.2 初始指针
这里我们用指针pa来接收a的地址,通过解引用操作符*找到a在内存中存储的位置,并对其值进行修改,可以理解为*pa=a
1.3 指针变量的大小
32位的操作系统假设有32位地址线,而一个地址就是32位组成的二进制序列,存储起来需要4个字节的空间,因为1个字节是8个比特位,而1个比特位存储一个二进制数,则指针变量为4个字节
64位的操作系统假设有64根地址线,则一个地址就是64位组成的二进制序列,存储时需要8个字节的空间,则指针变量大小为8个字节.
对比上图得知,指针变量的大小与指针变量的类型无关,而与操作系统有关
32位操作系统下指针变量大小为4个字节,64位操作系统下指针变量大小为8个字节
1.4 指针的解引用
char*
类型的解引用只能访问一个字节,int*
类型的解引用能访问4个字节,因此通过不同类型的解引用访问的字节数也不同.
1.5 指针±整数
1.6 void*类型指针
这时只需将地址用(void*的指针)无符号类型指针接收就可避免该问题
void*类型的指针无法进行运算
void*类型的指针可以接受不同类型的地址,因此无法进行相应的指针计算
2. const修饰指针
2.1 const修饰变量
那么const修饰变量后到底能不能修改呢?请看下面的代码
通过上图我们可以看到,即使变量n被const修饰后,我们还可以通过调用变量的地址对其值进行修改,这就破坏了语法的规则,我们应该让const修饰变量后使其不能被修改
2.2 const修饰指针变量
3. 指针运算
3.1 指针变量±整数
3.2 指针-指针
3.3 指针的关系运算
4. 野指针
野指针指的是指向的位置是未知的、随机的、没有明确限制的指针
典型的三种野指针
4.1 未初始化的野指针
4.2 越界访问的野指针
4.3 指针指向的空间释放
4.4 如何避免野指针
- 指针初始化
- 指针变量不用时,及时置NULL
- 防止指针越界
- 避免返回局部变量的地址
4.5 assert断言
assert.h
头文件定义了宏assert.h
,主要用于运行时确保程序符合指定条件,不符合会报错终止运行,因此也被称为“断言”
如果我们确定程序没有问题了,可以在assert头文件前定义宏#define NDEBUG
,此时编译器就会禁用assert语句
5. 传值调用和传址调用
5.1 求字符串长度
5.2 传值调用
通过传值调用我们发现a与b的值并未调换成功,那么这时为何呢?
通过调试我们发现,函数在传参时,形参会单独创建一个地址来接收实参,因此对形参的修改也不会影响到实参
5.3 传址调用
当我们把地址传过去时,形参的变化就会影响到实参中的变量