07.指针

目录介绍
  • 7.1 指针基本概念
    • 7.1.1 什么是指针
    • 7.1.2 指针声明
    • 7.1.3 指针初始化
    • 7.1.4 指针占用空间
  • 7.2 指针基本操作
    • 7.2.1 取地址运算符
    • 7.2.2 解引用运算符
  • 7.3 指针和数组
  • 7.4 指针和函数
    • 7.4.1 指针作为函数参数
    • 7.4.2 指针作为函数返回值
  • 7.5 指针与常量
    • 7.5.1 指向常量的指针
    • 7.5.2 常量指针
    • 7.5.3 指向常量的常量指针
    • 7.5.4 综合案例
  • 7.6 指针高级用法
    • 7.6.1 指针的指针
    • 7.6.2 函数指针
  • 7.7 指针注意实现
    • 7.7.1 空指针
    • 7.7.2 野指针
  • 7.8 综合案例练习
    • 7.8.1 数组的升序
    • 7.8.2 遍历数组案例

7.1 指针基本概念

7.1.1 什么是指针

指针的作用: 可以通过指针间接访问内存

  • 内存编号是从0开始记录的,一般用十六进制数字表示
  • 可以利用指针变量保存地址

指针,它存储了一个内存地址。指针可以指向其他变量或对象的内存地址,通过指针,可以直接访问和操作内存中的数据。

7.1.2 指针声明

指针变量定义语法:

数据类型 *指针变量名;
  • 数据类型:指针指向的变量的类型(如 intdouble 等)。
  • *:表示这是一个指针变量。
  • 指针变量名:指针的名称。

7.1.3 指针初始化

指针在使用前必须初始化,否则会指向一个未知的内存地址,可能导致程序崩溃。

int *ptr = nullptr; // 初始化为空指针

看如下案例所示:

int main() {
    int a = 10; //定义整型变量a
    //1、指针的定义
    //指针定义语法: 数据类型 * 变量名 ;
    int * p;
    //初始化,指针变量赋值
    p = &a; //指针指向变量a的地址
    cout << &a << endl; //打印数据a的地址
    cout << p << endl;  //打印指针变量p

    //2、指针的使用
    //通过*操作指针变量指向的内存
    cout << "*p = " << *p << endl;
    return 0;
}

指针变量和普通变量的区别

  • 普通变量存放的是数据,指针变量存放的是地址
  • 指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用
  1. 总结1:我们可以通过 & 符号 获取变量的地址
  2. 总结2:利用指针可以记录地址
  3. 总结3:对指针变量解引用,可以操作指针指向的内存

7.1.3 指针占用空间

提问:指针也是种数据类型,那么这种数据类型占用多少内存空间?示例:

int main() {
    int a = 10;
    int * p;
    p = &a; //指针指向数据a的地址

    cout << *p << endl; //* 解引用
    cout << sizeof(p) << endl;
    cout << sizeof(char *) << endl;
    cout << sizeof(float *) << endl;
    cout << sizeof(double *) << endl;
    return 0;
}
//10
//8
//8
//8
//8

在 C++ 中,指针的大小取决于编译器和操作系统的位数。通常情况下,指针在 C++ 中也会占用一定的内存空间,这个空间大小与系统的位数相关。

在大多数现代计算机系统中,指针的大小通常如下:

32 位系统:在 32 位系统中,指针通常占用 4 个字节(32 位)的内存空间。

64 位系统:在 64 位系统中,指针通常占用 8 个字节(64 位)的内存空间。

7.2 指针基本操作

7.2.1 取地址运算符

& 用于获取变量的内存地址。

int num = 10;
int *ptr = &num; // ptr 指向 num 的地址

7.2.2 解引用运算符

* 用于访问指针指向的内存地址中的值。

int num = 10;
int *ptr = &num;
cout << *ptr; // 输出 10

7.3 指针使用场景

7.3.1 指针和数组

数组名本身就是一个指针,指向数组的第一个元素。示例

#include <iostream>
using namespace std;

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr; // ptr 指向数组的第一个元素

    for (int i = 0; i < 3; i++) {
        cout << "Element " << i << ": " << *(ptr + i) << endl;
    }

    return 0;
}

输出

Element 0: 10
Element 1: 20
Element 2: 30

7.4 指针和函数

指针可以作为函数的参数或返回值,用于传递或返回内存地址。

7.4.1 指针作为函数参数

#include <iostream>
using namespace std;

void increment(int *ptr) {
    (*ptr)++; // 修改指针指向的值
}

int main() {
    int num = 10;
    increment(&num); // 传递 num 的地址
    cout << "Incremented value: " << num << endl;
    return 0;
}

输出

Incremented value: 11

7.4.2 指针作为函数返回值

#include <iostream>
using namespace std;

int* getMax(int *a, int *b) {
    return (*a > *b) ? a : b;
}

int main() {
    int x = 10, y = 20;
    int *maxPtr = getMax(&x, &y);
    cout << "Max value: " << *maxPtr << endl;
    return 0;
}

输出

Max value: 20

7.5 指针与常量

指针可以与 const 关键字结合,表示指针指向的值或指针本身不可修改。

const修饰指针有三种情况

  1. const修饰指针 --- 常量指针。常量指针(Constant Pointer):在这种情况下,const 修饰指针本身,表示指针本身是常量,不能通过该指针修改指向的地址。
  2. const修饰常量 --- 指针常量。指向常量的指针(Pointer to Constant):在这种情况下,const 修饰指针所指向的值,表示指针指向的值是常量,不能通过该指针修改所指向的值。
  3. const即修饰指针,又修饰常量。指向常量的常量指针(Constant Pointer to Constant):结合上述两种情况,指针本身和指针所指向的值都是常量,既不能通过指针修改所指向的值,也不能修改指针本身指向的地址。

7.5.1 指向常量的指针

const int *ptr; // ptr 指向的值不可修改

7.5.2 常量指针

int *const ptr = &num; // ptr 本身不可修改

7.5.3 指向常量的常量指针

const int *const ptr = &num; // ptr 和 ptr 指向的值都不可修改

7.5.4 综合案例

示例:

int main() {
    int a = 10;
    int b = 10;
    //const修饰的是指针,指针指向可以改,指针指向的值不可以更改
    const int * p1 = &a;
    p1 = &b; //正确
    //*p1 = 100;  报错
    //const修饰的是常量,指针指向不可以改,指针指向的值可以更改
    int * const p2 = &a;
    //p2 = &b; //错误
    *p2 = 100; //正确
    //const既修饰指针又修饰常量
    const int * const p3 = &a;
    //p3 = &b; //错误
    //*p3 = 100; //错误
    return 0;
}

7.6 指针高级用法

7.6.1 指针的指针

指针可以指向另一个指针。

int num = 10;
int *ptr = &num;
int **ptr2 = &ptr; // ptr2 指向 ptr

7.6.2 函数指针

函数指针是指向函数的指针变量,可以用于动态调用函数。

#include <iostream>
using namespace std;

// 函数
int add(int a, int b) {
    return a + b;
}

int main() {
    // 声明函数指针
    int (*funcPtr)(int, int) = add;

    // 使用函数指针调用函数
    int result = funcPtr(3, 5);
    cout << "Sum: " << result << endl;

    return 0;
}

输出

Sum: 8

7.7 指针注意实现

7.7.1 空指针

空指针:空指针是指不指向任何有效内存地址的指针。空指针通常用来表示指针没有被初始化或者指向了无效的内存地址。在 C++ 中,空指针的值通常是 0 或者使用 nullptr 关键字表示。

用途:初始化指针变量

注意:空指针指向的内存是不可以访问的

示例1:空指针

int main() {
	//指针变量p指向内存地址编号为0的空间
	int * p = NULL;
	//访问空指针报错 
	//内存编号0 ~255为系统占用内存,不允许用户访问
	cout << *p << endl;
	return 0;
}

7.7.2 野指针

野指针:指针变量指向非法的内存空间。

野指针是指指向未知内存地址或已释放的内存地址的指针。野指针通常是由于指针未正确初始化、指向已释放的内存或者超出作用域而导致的。

int main() {
	//指针变量p指向内存地址编号为0x1100的空间
	int * p = (int *)0x1100;
	//访问野指针报错 
	cout << *p << endl;
	return 0;
}

使用野指针可能会导致程序崩溃、内存泄漏或产生不可预测的行为。如何避免野指针:避免野指针的最佳方法是谨慎管理指针的生命周期,确保正确初始化、释放内存后置空指针,并避免超出指针的作用域。

7.8 综合案例练习

7.8.1 数组的升序

案例描述: 封装一个函数,利用冒泡排序,实现对整型数组的升序排序

例如数组:int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };

示例:

//冒泡排序函数
void bubbleSort(int * arr, int len)  //int * arr 也可以写为int arr[]
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

//打印数组函数
void printArray(int arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}

int main() {
	int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
	int len = sizeof(arr) / sizeof(int);
	bubbleSort(arr, len);
	printArray(arr, len);
	return 0;
}

7.8.2 遍历数组案例

作用:利用指针访问数组中元素。数组名本身是一个指针,指向数组的第一个元素。

示例:

int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p = arr;  //指向数组的指针。看解释1
    cout << "第一个元素: " << arr[0] << endl;
    cout << "指针访问第一个元素: " << *p << endl;  //指向数组第一个元素的指针。看解释2
    for (int i = 0; i < 10; i++) {
        //利用指针遍历数组。看解释3
        cout << *p << endl;
        p++;
    }
    return 0;
}
  1. 解释1,数组名是指针:在 C++ 中,数组名可以被隐式转换为指向数组第一个元素的指针。这意味着p可以将数组名视为指向数组的第一个元素的指针。
  2. 解释2,指针和数组的关系:指针可以用来访问数组中的元素。通过指针算术运算,可以遍历数组中的元素。
  3. 解释3,指针和数组的传递:当传递数组给函数时,实际上传递的是数组的地址,即数组名被隐式转换为指向数组第一个元素的指针。
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]