指针
1. 什么是指针:
指针即地址,我们在编写程序时,每创建一个变量,计算机就分配一块内存空间来存储这个变量,而指针就是一个标记,能让我们通过指针来访问其指向的空间的内容,并对该空间的内容进行修改
2. 指针变量:
- 指针变量的类型与大小:我们熟知的数据类型有int, short, float, double, char等,而不同的类型的变量就需要相对应的指针变量来存储。而指针变量的大小只与当前所处的环境有关在X86环境下,任何类型的指针变量大小均为4字节;在X64情况下,大小均为8字节
- 如何使用指针变量:见示例代码
//示例:
#include<iostream>
using namespace std;
int main() {
int p = 0;
int *ptr = &p;//创建一个名为ptr的指针变量,并将其初始化为p的地址(&为取地址符)
*ptr = 3;//*与指针变量结合就可以访问存在ptr的地址的变量,改变*指针变量的值,
//就可以改变存在这个指针变量所存储的地址的变量
cout << p << ' ';
return 0;
}
3. 野指针与空指针:
1. 野指针与空指针的定义:
- 野指针:指针指向的位置是不确定的
- 空指针:明确被赋值为NULL的指针,表示不指向任何有效的地址
2. 野指针的成因:
- 指针未初始化
#include <iostream>
using namespace std;
int main()
{
int* p;//局部变量未初始化,默认未随机值
*p = 20;
return 0;
}
- 指针越界访问
#include <iostream>
using namespace std;
int main()
{
int arr[10] = { 0 };//0 0 0 0 0 0 0 0 0 0(10个数)
int* p = &arr[0];
int i = 0;
for (i = 0; i <= 11; i++);//循环了12次
{
*p = i;
p++;
}
cout << n << endl;
return 0;
}
- 指针指向的空间已被释放
#include <iostream>
using namespace std;
int* test()
{
int n = 100;//n是局部变量
return &n;
}
int main()
{
int* p = test();
cout << *p << endl;
return 0;
}
/*
上诉代码中,n是局部变量,所以n的生命周期就是局部范围,当出了范围后,n会被销毁。通过
return &n导致n的地址被返回。p接收了这个地址。在&n返回的时候,n所占的空间就不属于n了。
这时候p在拿着刚才返回的地址去找n,根本找不到。因此,当p得到地址的时候,就已经是野指针了
*/
3. 如何避免野指针:
- 使用指针变量时初始化,明确指针指向哪里时直接赋地址;不知道时直接赋为NULL
- 指针变量被释放时及时置空
- 注意指针越界问题
- 指针使用前检查指针变量是否为空指针
4. 指针作为函数参数传递:
见文章:C++函数参数的传递方式(值传递、址传递、引用传递、const在传递函数参数时的作用)_c++ 编译器 对函数参数 值传递和const引用传递 优化-优快云博客
5. 指针数组与数组指针:
- 指针数组:本质上是数组,数组内元素存的是指针
定义方式: 数据类型 *数组名[指针数组长度];
- 数组指针:本质上是指针,存放的是数组的地址
定义方式: 数据类型 (* 数组名)[数组指针的长度]
6. 函数指针:
C 语言中,函数不能嵌套定义,也不能将函数作为参数传递。但是可以取得函数名为该函数的入口地址。我们可以定义一个指针指向该地址,将指针作为参数传递。
函数指针的定义方式:
数据类型 (*函数指针名)(函数参数);
注意:函数指针在进行“*”操作时,可以理解为执行该函数。函数指针不同与数据指针,不能进行+整数操作。
函数指针的使用示例:
#include <iostream>
using namespace std;
// 定义一个普通函数
int add(int a, int b) {
return a + b;
}
int main() {
// 定义一个函数指针,该指针指向一个返回int类型,接受两个int类型参数的函数
int (*funcPtr)(int, int);
// 将add函数的地址赋值给函数指针
funcPtr = add;
// 通过函数指针调用函数
int result = funcPtr(3, 5);
cout << "3 + 5 = " << result << endl;
return 0;
}
引用
1. 引用的定义:
给已经存在的变量取别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
引用的定义方式:
数据类型 &引用变量名 = 变量
2. 引用的特性:
- 引用的指向不能修改(因为引用的底层是指针常量)
- 引用必须在定义时初始化,且不能初始化为空
3. 左值引用、右值引用与万能引用:
- 左值引用:只能接收左值
int a = 10;
int& ref_a = a;
- 右值引用:只能接收右值
int&& rref = 20;
- 万能引用:万能引用是一种特殊的引用,它既能接收左值又能接收右值
//接收左值
int a = 10;
const int ref_a = a;
//接收右值
const int rref = 20;
万能引用的优缺点:优点 既能接收左值又能接收右值;缺点 值不能被修改
4. 引用与指针的区别:
- 引用在定义时必须初始化,但指针没做要求
- 引用的指向不能修改,指针可以
- 引用不能为空,指针可以
- 引用比指针形式上更加简洁,代码的可读性更高
- 引用比指针更安全(指针有野指针、空指针等)
- 引用没有多级,指针有多级
- 访问实体的方式不同,指针需要显示解引用;引用则是编译器自行处理
- sizeof引用所得到的值是指引用对象所指对象的值,sizeof指针所得的是指针变量本身的值
- 引用做函数参数传递的是实参本身,指针做函数参数传递的是指针变量的值
END
本文讲解了引用与指针的定义方式、使用方式、使用的注意事项以及指针与引用的区别。希望可以对你有帮助