8、指针

指针的基本概念

指针的作用: 可以通过指针间接访问内存,指针也是一种数据类型

指针变量的定义和使用

指针变量定义语法: 数据类型 * 变量名;

指针的数据类型:取决于指针指向的内存空间,该内存空间存放的是什么类型数据,如果是数组,那么变量指向的是第一个元素,所以还是取决于数组的数据类型是什么

例子

#include<iostream>
using namespace std;

int main() {
	//创建一个变量
	int a = 10;
	//定义指针,语法:数据类型 * 指针名
	int * p;
	//让指针p记录a的地址
	p = &a;

	cout << &a << endl; //0113F8F0
	cout << p << endl; //0113F8F0

	//解引用,在指针变量前加*,获取指向的内存空间,进行重新赋值
	*p = 100;
	cout << a << endl; // 100

	system("pause");
	return 0;
}

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

总结1: 我们可以通过 & 符号 获取变量的地址

总结2:利用指针可以记录地址

总结3:对指针变量解引用,可以操作指针指向的内存

指针所占内存空间

#include<iostream>
using namespace std;

int main() {
	int * p;
	int size = sizeof(p);
	cout << size << endl;
	system("pause");
	return 0;
}

所有指针类型在32位操作系统下是4个字节

所有指针类型在64位操作系统下是8个字节

空指针

空指针:指针变量指向内存中编号为0的空间

用途:初始化指针变量

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

#include<iostream>
using namespace std;

int main() {
	//用于给指针变量初始化
	int * p = NULL;
    cout << p << endl; //00000000
	//空指针是不可以进行解引用使用的
	*p = 100; //报错

	system("pause");
	return 0;
}

野指针

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

#include<iostream>
using namespace std;

int main() {
	//用于给指针变量初始化
	int * p = (int *)0x1100;

	//野指针不可以进行读写,非法
	*p = 100; //报错,写入访问权限冲突

	system("pause");
	return 0;
}

const修饰指针

const修饰指针有三种情况

  1. const修饰指针 --- 常量指针
  2. const修饰常量 --- 指针常量
  3. const即修饰指针,又修饰常量

常量指针

const修饰指针:指针的指向可以进行修改,不可以对指向内存空间的值进行修改

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 20;
	const int * p = &a;

	p = &b; // 指针的指向可以进行修改

	*p = 20; // 不可以对指向内存空间的值进行修改

	system("pause");
	return 0;
}

指针常量

const修饰常量:指针的指向不可以进行修改,可以对指向内存空间的值进行修改

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 20;
	int * const p = &a;

	p = &b; // 指针的指向不可以进行修改

	*p = 20; // 可以对指向内存空间的值进行修改

	system("pause");
	return 0;
}

const同时修饰指针和常量

指针的指向和指向内存空间的值都不可以进行修改

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 20;
	const int * const p = &a;

	p = &b; // 指针的指向不可以进行修改

	*p = 20; // 不可以对指向内存空间的值进行修改

	system("pause");
	return 0;
}

指针和数组

作用:利用指针访问数组中元素

示例

#include<iostream>
using namespace std;
#include<string>

int main() {
	//定义一个数组
	string a[] = { "lucy","tom","lily","james" };
	//a其实保存的就是数组的第一个元素的地址
	string * p = a;
	//解引用,可以获取数组的第一个元素
	cout << *p << endl; //lucy
	//由于数组是连续的内存空间,而一个指针占用的内存空间是4个字节,所以只需要将p后移四个字节,就指向了下一个元素
	p++;
	cout << *p << endl; //tom
	
	system("pause");
	return 0;
}

利用指针遍历数组

#include<iostream>
using namespace std;
#include<string>

int main() {
	//定义一个数组
	string a[] = { "lucy","tom","lily","james" };
	//定义指针
	string * p = a;
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
		cout << *p << endl;
		p++;
	}
	
	system("pause");
	return 0;
}

指针和函数

由于cpp的函数是值传递,所以如果需要引用传递(类似java),那么需要使用指针作为参数

例子,如果不使用地址传递,那么函数是无法改变a和b的值:

#include<iostream>
using namespace std;

void change(int * a,int * b) {
	int temp = *b;
	*b = *a;
	*a = temp;
}

int main() {
	int a = 10;
	int b = 20;
	change(&a, &b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	
	system("pause");
	return 0;
}

案例1

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

int arr[10] = { 4,3,6,9,1,2,10,8,7,5 }

#include<iostream>
using namespace std;
//冒泡升序排序
void mopoSort(int * arr,int length) {
	for (int i = 0; i < length - 1; i++) {
		for (int j = 0; j < length - 1 - i; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
//遍历数组
void toStringArr(int * arr,int length) {
	for (int i = 0; i < length; i++) {
		cout << arr[i] << endl;
	}
}

int main() {
	int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
    //数组的长度
	int length = sizeof(arr) / sizeof(arr[0]);
	mopoSort(arr, length);
	toStringArr(arr, length);
	system("pause");
	return 0;
}