目录
指针
指针的定义和使用
指针所占用的内存空间
空指针与野指针
const修饰指针
指针和数组
指针和函数
指针
指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
指针的定义和使用
作用:
内存管理:通过指针,可以直接访问和操作内存中的数据。通过动态分配内存,使用
new
操作符创建对象并返回其地址,然后将地址存储在指针中,可以动态地管理内存,创建和销毁对象。传递参数:指针可用于通过引用传递参数。通过将变量的地址传递给函数,函数可以直接访问并修改变量的值,而不是传递变量的副本。这种传递方式可以避免复制大量数据,提高性能,并允许函数对原始变量进行更改。
数据结构:指针在实现数据结构(如链表、树和图等)时起着重要作用。通过使用指针,可以链接不同的节点或对象,以构建复杂的数据结构,并在结构内进行遍历、插入、删除等操作。
动态多态性:通过指向基类的指针,可以实现多态性。指针的多态性使得可以在运行时确定具体指向的对象类型,并调用相应的方法。这在面向对象编程中非常有用,允许以统一的方式操作和处理不同类型的对象。
优化和效率:指针的使用可以提高程序的性能和效率。通过使用指针,可以减少内存和数据的复制,节省存储空间,提高数据访问速度,并允许在需要时动态分配和释放内存。
语法:
定义:数据类型 * 变量名;
取值:* 变量名
#include <iostream>
#include "maxValue.h"
using namespace std;
// 指针
// 定义和使用
int main()
{
int a = 10; // 定义变量a
cout << "address a : " << &a << endl; // 0x63fe14
// 指针的定义 数据类型 * 变量名;
int *p;
p = &a; // 使用取址符号,取到a的地址赋值给指针p
cout << "address p : " << p << endl; // 0x63fe14
// 指针的使用 *p解除引用 找到内存中的数据
*p = 5; // *p表示的是内存地址中的数据,这行代码相当于将数值5赋值给指针p指向的内存地址中的值
cout << " a = " << a << endl; // a = 5 指针p指向a所在的内存地址,取到指针p对应的值并赋值为5,所以a为5
cout << " *p = " << *p << endl; // *p = 5
system("pause");
return 0;
}
指针所占用的内存空间
指针是一种变量类型。
在32位操作系统中占用4个字节。
在34位操作系统中占用8个字节。
指针占用内存空间与操作系统相关,与指针的数据类型无关
#include <iostream>
#include "maxValue.h"
using namespace std;
// 指针
// 指针所占用的内存空间
int main()
{
int a = 10;
int *p = &a;
cout << "sizeof (int *) = " << sizeof(p) << endl; // sizeof (int *) = 8 我的操作系统是64位 如果你输出的是4可以检查一下你是否是32位操作系统
cout << "sizeof (int *) = " << sizeof(int *) << endl; // sizeof (int *) = 8 验证指针占用内存空间与操作系统相关,与指针的数据类型无关
cout << "sizeof (float *) = " << sizeof(float *) << endl; // sizeof (float *) = 8
system("pause");
return 0;
}
空指针与野指针
空指针(Null Pointer):空指针是指未指向任何有效对象或内存地址的指针。在C++中,可以使用字面值
nullptr
或宏NULL
(通常定义为0)来表示空指针。空指针在以下情况下有应用:
初始化指针:在声明指针变量时,可以将其初始化为空指针,表示该指针当前不指向任何有效对象。
检查指针有效性:在使用指针之前,可以通过与空指针进行比较,检查指针是否有效。如果指针等于空指针,则表示指针未指向有效对象,可以进行相应的错误处理或逻辑判断。
终止链表或递归:在链表或递归结构中,空指针可以用作终止条件。当指针为NULL时,表示已到达链表的末尾或递归的边界条件。
野指针(Dangling Pointer):野指针是指指针变量指向已释放或无效的内存地址。这种指针可能会导致未定义的行为和问题。野指针的应用通常是一种错误或编程失误,应该尽量避免出现。
释放内存后未置空指针:如果在释放内存后没有将 指针置为空指针或重新指向其他有效的对象,那么该指针将成为野指针。
悬空指针引用:在某些情况下,可能会发生指针在使用之前就失去了有效性的情况,比如函数返回栈上局部变量的指针,或者指向已经释放的内存的指针。
#include <iostream>
using namespace std;
// 指针
// 空指针
int main()
{
// 空指针给指针变量进行初始化
int *p = NULL;
// *p = 1000; 出现异常。Segmentation fault
system("pause");
return 0;
}
#include <iostream>
using namespace std;
// 指针
// 野指针
int main()
{
int *p = (int *)0x1100;
cout << *p << endl; //出现异常。Segmentation fault 没有申请0x1100地址的访问权限直接访问 尽量避免
system("pause");
return 0;
}
const修饰指针
const修饰指针的三种情况:
- const修饰指针:常量指针(可以修改指针指向,不可以修改指针指向的值)
- const修饰常量:指针常量(可以修改指针指向的值,不可以修改指针指向)
- const既修饰指针又修饰常量(不可以修改指针指向的值,不可以修改指针指向)
#include <iostream>
using namespace std;
// const指针
int main()
{
// ① 常量指针(可以修改指针指向,不可以修改指针指向的值)
int a = 10;
int b = 20;
const int *p = &a;
cout << *p << endl; // 10
p = &b;
cout << *p << endl; // 20
// *p = a; 报错
// ② 指针常量(可以修改指针指向的值,不可以修改指针指向)
int *const p2 = &a;
*p2 = 100;
cout << *p2 << endl; // 100
// p2 = &b; 报错
// ③ const既修饰指针又修饰常量(不可以修改指针指向的值,不可以修改指针指向)
const int *const p3 = &a;
// *p3 = 100; 报错
// *p3 = &b; 报错
return 0;
}
指针和数组
作用:使用指针访问数组中元素。
#include <iostream>
using namespace std;
// 指针和数组
// 使用指针访问数组
int main()
{
int arr[5] = {1, 4, 7, 2, 5};
int *p = arr; // 数组名arr就是第数组元素的首地址
int size = sizeof(arr) / sizeof(arr[0]); // 数组长度计算
for (int i = 0; i < size; i++)
{
cout << *p; // 14725 13与14行代码可以一起写,写成这个样子cout << *p++;
p++;
}
return 0;
}
指针和函数
作用:
利用指针作函数参数,可以修改实参的值。
#include <iostream>
using namespace std;
// 指针和函数
// 背景:我们知道值传递时是可以修改形参的值,实参是不受影响的 那么地址传递呢?
void swap01(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main()
{
int a = 10, b = 20;
swap01(&a, &b);
cout << "a = " << a << endl; // a = 20
cout << "b = " << b << endl; // b = 10
return 0;
}