C++阶段01笔记07【指针(基本概念、变量定义和使用、内存空间、空指针和野指针、const修饰指针、指针和数组、指针和函数)】

C++| 匠心之作 从0到1入门学编程【视频+课件+笔记+源码】

目录

7 指针

7.1 指针的基本概念

7.2 指针变量的定义和使用

示例

7.3 指针所占内存空间

示例

7.4 空指针和野指针

示例1:空指针

示例2:野指针

总结

7.5 const修饰指针

1、const修饰指针——常量指针

2、const修饰常量——指针常量

3、const既修饰指针,又修饰常量

示例

7.6 指针和数组

示例

7.7 指针和函数

示例

7.8 指针、数组、函数

示例


7 指针

7.1 指针的基本概念

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

  • 内存编号是从0开始记录的,一般用十六进制数字表示。

  • 可以利用指针变量保存地址。

内存都是有地址编号的,从0开始记录,一般用十六进制数字来表示编号,可以利用指针来记录地址编号。

int a = 10; // 4字节空间大小

每创建一个变量,都要去记录地址编号,不太方便去使用这个数据,所以才会有这个变量。

知道地址编号,也可以拿到数据。指针就是一个地址,记录地址编号!

7.2 指针变量的定义和使用

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

示例

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

  • 普通变量存放的是数据,指针变量存放的是地址。

  • 指针变量可以通过 “ * ” 操作符,操作指针变量指向的内存空间,这个过程称为解引用

 通过p可以找到内存,通过*p可以修改内存。

指针的作用(用途):可以间接地访问内存,并且对其进行读和写的操作(修改、访问)!

  

#include <iostream>
using namespace std;

int main()
{
	//1、指针的定义
	int a = 10; //定义整型变量a

	//指针定义的语法:数据类型 * 指针变量名 ;
	int *p; // point代表指针

	//指针变量赋值 让指针记录变量a的地址
	p = &a;	//指针p指向(等于)变量a的地址【取地址符号& 取变量a的地址】建立变量与指针之间的关系
	cout << "a的地址为:" << &a << endl; //打印数据a的地址:0x61fe14
	// cout << "a的地址为:" << (int)&a << endl; //十六进制转整型
	cout << "指针p为:" << p << endl; //打印指针变量p:0x61fe14【指针就是一个地址,记录地址编号!】

	//2、指针的使用
	//可以通过“解引用”的方式来找到指针指向的内存
	//指针前加一个* 代表 解引用,找到指针指向的内存中的数据
	//通过*操作指针变量指向的内存
	cout << "*p = " << *p << endl; // 10

	*p = 1000; //解引用 通过指针间接地找到了a的内存 通过解引用拿到p指向的内存中的数据(进行 修改、读取)
	cout << "a = " << a << endl;
	cout << "*p = " << *p << endl;

	system("pause");
	return 0;
}

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

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

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

7.3 指针所占内存空间

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

总结:所有指针类型在32位操作系统下是4个字节,在64位操作系统下是8字节。

示例

 

#include <iostream>
using namespace std;

int main() //指针所占内存空间
{
	int a = 10;

	// int *p;
	// p = &a; //指针指向数据a的数据地址
	int *p = &a; //建立关系

	//在32位操作系统下,指针是占4个字节空间大小(不管是什么数据类型)
	//在64位操作系统下,指针是占4个字节空间大小(不管是什么数据类型)
	cout << *p << endl;										   //10 * 解引用
	cout << "sizeof(p) = " << sizeof(p) << endl;			   //8 查看变量(数据类型)占用的内存空间
	cout << "sizeof(int *) = " << sizeof(int *) << endl;	   //8
	cout << "sizeof(float *) = " << sizeof(float *) << endl;   //8
	cout << "sizeof(double *) = " << sizeof(double *) << endl; //8
	cout << "sizeof(char *) = " << sizeof(char *) << endl;	   //8
	system("pause");
	return 0;
}

7.4 空指针和野指针

空指针:指针变量指向内存中编号为0的空间。内存条,都有自己的编号,从0开始递增。指向编号为0的指针,称为“空指针”!

用途:初始化指针变量。指针一开始不知道指向哪里好,就指向内存中编号为0的空间。

注意:空指针指向的内存是不可以访问的。无权利访问空指针指向的内存。0~255之间的这块内存,是系统占用的,一旦访问,就会出错!

示例1:空指针

#include <iostream>
using namespace std;

int main() //空指针
{
	//1、空指针用于给指针变量进行初始化
	// int * p;//指针指向哪?未知!所以,一般会让指针指向NULL(空)
	int *p = NULL; //指针变量p指向内存地址编号为0的空间

	//2、空指针是不可以进行访问的
	//0~255之间的内存编号是系统占用的,因此不可以访问
	*p = 100; //直接引用 操作内存
	//访问空指针报错
	//内存编号0 ~255为系统占用内存,不允许用户访问
	cout << *p << endl;

	//system("pause");
	return 0;
}

示例2:野指针

野指针:指针变量指向非法的内存空间。非法的内存空间:不是使用者申请的内存空间。

#include <iostream>
using namespace std;

int main() //野指针 在程序中,尽量避免出现野指针
{
	// int *p = NULL;
	//指针变量p指向内存地址编号为0x1100的空间【0x1100:十六进制数字】
	int *p = (int *)0x1100; //变为地址:(int *)强转为指针类型
	//0x1100随便在内存中指向了这样一个编号,这个编号中的数 无权利操作!没有申请,无权利操作!
	//举例:花钱买房间A(int a = 10; int *p = &a;),没有权利去房间B(房间B->野指针)

	cout << *p << endl; //访问野指针报错

	system("pause");
	return 0;
}

总结

总结:空指针和野指针都不是我们申请的空间,因此不要访问。

7.5 const修饰指针

const修饰指针有3种情况:

  1. const 修饰指针 —— 常量指针        const int *p1 = &a;

  2. const 修饰常量 —— 指针常量        int *const p2 = &a;

  3. const 既修饰指针,又修饰常量

1、const修饰指针——常量指针

红框:被限定,不可以修改;黑线:可以修改。

2、const修饰常量——指针常量

红线:被限定,不可以修改;黑框:可以修改。

3、const既修饰指针,又修饰常量

示例

 

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	int b = 10;
	//int *p0 = &a; //普通写法

	//1、常量指针(记法:const在前 先常量 后指针)
	//const修饰的是指针,指针的指向可以更改,指针指向的值不可以更改(可以理解为const 修饰的是解引用 int*,所以指针指向的值不可以更改)
	const int *p1 = &a;
	p1 = &b; //正确
	// *p1 = 20; //错误

	//2、指针常量(记法:int* 在前 先指针 后常量)
	//const修饰的是常量,指针的指向不可以更改,指针指向的值可以更改(可以理解为const修饰的是指针本身,所以指针指向的值不可以修改)
	int *const p2 = &a;
	*p2 = 100; //正确
	//p2 = &b; //错误,指针常量 指针的指向不可以更改

	//3、const既修饰指针又修饰常量
	const int *const p3 = &a;
	//指针的指向和指针指向的值都不可以改
	//*p3 = 100; //错误
	//p3 = &b; //错误

	system("pause");
	return 0;
}

技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量

7.6 指针和数组

作用:利用指针访问数组中元素。数组:一段连续的空间中,存放了相同类型的数据元素。

示例

  

#include <iostream>
using namespace std;

int main()
{
	//指针和数组
	//让(利用)指针也能访问数组中的每一个元素
	int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	cout << "第一个元素为:" << arr[0] << endl;

	int *p = arr; //指向数组的指针 数组是整型的,所以创建整型指针,指向数组的地址 arr数组名就是数组的首地址
	//指针指向数组首地址,对指针进行解引用的操作,就可以解出数组中的第一个元素
	cout << "利用指针访问第一个元素:" << *p << endl; //*p解引用

	p++; //指向数组中的第二个元素,让指针向后偏移(移动)4个字节(整型指针)
	cout << "利用指针访问第二个元素:" << *p << endl; //*p解引用

	cout << "利用指针遍历数组:" << endl;
	int *p2 = arr;
	for (int i = 0; i < 10; i++) //利用指针遍历数组
	{
		// cout << arr[i] << endl;
		cout << *p2 << endl;
		p2++;
	}

	system("pause");
	return 0;
}

7.7 指针和函数

作用:利用指针作函数参数,可以修改实参的值。

示例

 

指针保存的是地址。传递地址,可以间接地改变实参数据。

#include <iostream>
using namespace std;

//1、值传递:实现两个数字进行交换
void swap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "swap01中 a = " << a << endl;
	cout << "swap01中 b = " << b << endl;
}

//2、地址传递
void swap02(int *p1, int *p2)
{
	int temp = *p1; //解出内存 解引用
	*p1 = *p2;
	*p2 = temp;
	cout << "swap02中 *p1 = " << *p1 << endl;
	cout << "swap02中 *p2 = " << *p2 << endl;
}

int main() //指针和函数
{
	int a = 10;
	int b = 20;

	//1、值传递不会改变实参
	swap01(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//2、地址传递会改变实参
	//将a、b变量地址传入函数体中,用指针接受地址【如果是地址传递,可以修饰实参】
	swap02(&a, &b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	system("pause");
	return 0;
}

总结:如果不想修改实参,就用值传递,如果想修改实参,就用地址传递。

7.8 指针、数组、函数

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

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

示例

#include <iostream>
using namespace std;

//冒泡排序函数【参数1:数组首地址;参数2:数组长度】
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]) //如果j > j + 1的值,交换数字
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

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

int main()
{
	//1、创建一个数组
	int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5};
	//数组长度
	int len = sizeof(arr) / sizeof(int);

	//2、创建一个函数实现冒泡排序
	bubbleSort(arr, len); //传递数组地址arr:数组名就是数组的首地址

	//3、打印排序后的数组
	printArray(arr, len); //传递数组地址arr

	system("pause");

	return 0;
}

总结:当数组名传入到函数作为参数时,被退化为指向首元素的指针。

猜你喜欢

转载自blog.csdn.net/weixin_44949135/article/details/115187829