IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 直接带你对指针进行一个门的入|指针初阶 -> 正文阅读

[C++知识库]直接带你对指针进行一个门的入|指针初阶

导语:昨晚问了老师几个关于指针的很简单的问题,两个老师都怀疑我根本没听课qwq(事实上我听了两遍T_T),还和小伙伴讨论了好久,但是昨晚因为老师的话心态很崩溃,自己一个人背着妈妈偷偷哭了好久::>_<::哭到大脑缺氧1点才睡觉(结果今天九点才起来啊啊啊),说这些的原因是,学了好久指针都会问出简单智障的问题混淆简单概念(甚至让老师怀疑我根本没听课),可以看出博主真的不聪明甚至可以说很笨,但是今天仍然爬起来弄明白了这些问题,说明你也可以!我这样的笨蛋都学会了你也一定可以,加油呀!相信自己!

一、首先,什么是指针?

? ? 如果我有事要找住在酒店中的某个人,那我得先知道他具体住在酒店的哪里,比如他住在xx层房间号为x0x,根据他的住址我们就可以找到他。

? ? 内存就相当于一个大的酒店,而内存中存储的数据就相当于住在酒店房间的人,每个人住在不同的房间,同样每个数据被存储在不同的格子中;我们在编写程序的时候经常会由于需要去调用内存中的某个数据,但是很多时候不知道数据在哪,换言之,不知道数据的“地址”从而无法找到他。那么这时……

天空一声巨响,指针闪亮登场(好土哈哈哈哈)

? ? 指针指针,那它不就是指引的那根针嘛;指针之中存放的就是这个数据在内存中的地址,根据这个地址我们很容易就可以在内存中找到我们想要的数据。

二、关于指针的一些常规操作

1、定义指针变量

???在指针前面写上指针指向的数据类型,同时*表示这是一个指针(如整型指针p写作int*p)

2、取地址

?? 既然指针是存放地址的,那么我们要使指针指向这个数据,就需要取出数据的地址,并且将地址赋给指针变量,这里需要用到取地址符&

#include<stdio.h>
int main()
{
	int i = 10;
	int* p = &i;
	return 0;
}

? ? 观察上面这个例子,定义i为整型变量,那么它在内存中占了4个字节(相当于4个格子,假设一个格子是一个字节),每个格子都有自己的地址,但是&i取出的是第一个格子的地址,因为我们已经定义了指针类型为int类型,那么它就会从第一个格子开始往后数四个。(好吧,其实我觉得电脑才是最懒的人)

? ?

? ? 与此同时,指针p同样需要在内存中占据空间,在32位中指针是4个字节,64位中指针是8个字节,我们假设这里的指针p是4个字节,那么指针p中就会存放上面 i 占据的四个格子中第一个格子的地址。

3、解引用

? ? ?*为解引用操作符,&为取地址符,二者互为逆运算;取地址符是指取出内存中数据的地址,那么解引用符就是指向这个地址的数据。

? ? 换句话说,解引用+指针 等价于 指针指向的数据

三、指针有哪些类型?

? ? 在介绍下面指针的这些不同类型之前,我们首先要搞明白一件这样的事:为什么要区分不同的指针类型?

1、操作的字节数不同

?在开始时可以看到a的地址为第一行,倒序存放的11 22 33 44

?当调试代码至执行了*pa = 0这行语句之后,可以看到右边原来存放的11 22 33 44这时都变成了00 00 00 00

在开始时a的地址为右侧的44,只有一个字节

调试代码执行了*pa这行代码之后,可以看到右侧存放的44这时变成了00

? ? 通过以上两个例子可以看出,指针的类型不同,操作范围也不相同,整型指针可以操作4个字节,而字符型指针只能操作1个字节;因此,指针类型决定了指针在被解引用时访问的权限。

2、指针每走一步跨过的距离不同

? ? 通过上图对比,不难发现,对于整型指针pa来说,指针每加一跨过的是一个整数即为4个字节;对于字符型指针pc来说,指针每加一跨过的是一个字符即为1个字节

下面可以来康康应用:

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	char* p = (char*)arr;
	int i = 0;
	for (i = 0; i < 40; i++)
	{
		*p = 'w';
		p++;
	}
	return 0;
}

? ? 定义整型arr数组,数组中有10个元素,说明在内存中开辟了40个字节的空间。这里的arr数组元素原本为int类型,因此指针类型也应该是int*,但是整型指针每向前一步跨过一个整数即为4个字节,如果我们想要一个字节一个字节地进行访问,那么这时我们只能使用字符型指针。无论是4个字节4个字节的访问,还是1个字节1个字节的访问,我们都需要将第一个字节的地址存放在指针中,因为数组名代表数组首元素地址,因此char*p等于数组名arr,但是数组本身是整型数组,因此数组首元素地址是int*类型的,要放到字符型指针里面就要进行强制类型转换。其中w放在4个字节里,结果却不是它的4倍,是把这4个字节当作一个int看的(如果在监视中观察a[i]中存储的ASCII码值的话)

? ? 那么,如果4个字节4个字节地访问呢?

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p = 'w';
		p++;
	}
	return 0;
}

? ? 我们还是获取了数组arr的数组名即为首元素地址,因为数组本身存放的即为整型,因此不需要强制类型转换,地址类型本身即为int*类型,因为int类型是4个字节,所以p++,地址每+1访问的应该是跨过sizeof(int)即为4个字节,同时*p=‘w’将数组的每个元素都改为了w

? ? 酒店肯定不会因为你是歪果仁,或者是男/女就拒绝你入住吧,那么内存也是同样,每个房间里存放的数据也并非单一类型,由于指针指向的数据类型不同,指针也因此分为不同类型

? ? 因为这篇文章算是指针入门介绍,所以在这里只列举了几种基本的指针类型:

四、野指针

什么是野指针?

顾名思义,野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

导致野指针的原因有以下三种:

1、未对指针进行初始化

#include<stdio.h>
int main()
{
	int* p;
	*p = 10;
	return 0;
}

? ? 我们声明了p这个指针变量,但从未对它进行初始化,里面放的是一个随机值,所以没有办法预测10这个地方存储在什么地方。如果变量是静态的,它会被初始化为0,但如果变量是自动的,它根本不会被初始化。

? ? 如果想要不出现野指针,这里第一行可以写做int*p=NULL,NULL指针是一个特殊的指针变量,它表示不指向任何东西,所以同样不能对这个指针进行解引用操作。

2、指针进行越界访问

?

? ? 数组中只有5个元素,定义整型指针p存放数组首元素地址,也就是从数组第一个元素开始访问,每次访问数组中的一个元素,但是后面的for循环却循环了10次,在访问完数组的5个元素之后接着对后面的元素进行访问就属于越界访问了。

3、指针指向的空间释放

#include<stdio.h>
int* test()
{
	int a = 10;
	printf("%d\n", a);
	return &a;
}
int main()
{
	int* p = test();
	*p = 100;
	return 0;
}

? ? 上面test函数的变量a是进入函数创建,但是一旦出了这个函数a就会被销毁,内存空间就会还给操作系统不属于当前程序了,那么这个时候p里面存储的地址就无法使用了,指针p也会变成野指针。

? ? 就好比我今天在酒店102订了房间并且电话叫好盆友过来住,但是他今天却没有时间,第二天我退了房间后,他来了,那他现在就没办法住了鸭😊

如何规避野指针?

1、指针初始化

#include<stdio.h>
int main()
{
	int* p = NULL;
	if (p != NULL)
	{
		//使用指针
	}
	return 0;
}

? ? 在我们还没想好对指针p初始化什么值的时候,我们可以先让它等于空指针NULL,当指针不是空指针时,我们再去用它

2、小心指针越界

3、指针指向空间释放之后及时将指针置为空指针

? ? 就是它存放的地址没用了之后赶紧放上NULL

4、避免返回局部变量地址

? ? 就是尽量不返回在一个函数里面的变量哦~

5、指针使用之前检查有效性

? ? 如果指针为空指针我就不使用它了,当它是空指针的时候我再去使用它

五、指针运算

1、指针加减整数/关系运算

指针可以进行加一减一的操作,并且指针每行动一步跨过sizeof(指针指向的变量类型)个字节

? ? 可以来看一下这段代码,首先定义了一个含有5个元素的数组arr,定义整型指针p,接着运用for循环,使得指针p指向的为数组首元素地址,同时p小于arr第五个元素的地址,p++,即对p进行+1的操作,同时打印出*p。因为指针也是有大小的,所以指针可以比较大小,比如p<&arr[5],就是进行指针的关系运算。

? ? 这段代码其实还有可优化之处,我们可以把p++与*p合在一起,即为*p++,对p进行解引用之后再++,最终打印出来的效果也还是一样的

#include<stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int* p;
	for (p = arr; p < &arr[5];)
	{
		printf("%d ", *p++);
	}
	return 0;
}

2、指针减指针运算

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%d", &arr[9] - &arr[0]);
	return 0;
}

? ? 这里打印的两个地址相减的结果,其实就是在算两个指针相减,最终运行结果为9,代表两个指针之间有9个元素。因此,当两个指针指向同一块空间时,指针减去指针所得结果的绝对值为指针之间元素的个数

? ? 那么这个东西有什么用呢?我们来看下面的代码,不调用库函数strlen来实现我们自己求字符串长度的一个函数

#include<stdio.h>
int my_strlen(char* str)
{
	char* start = str;
	while (*str)
	{
		str++;
	}
	return str - start;
}
int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

? ? 运行结果为6,首先我们在arr数组中存放了一个字符串,注意在f后面还有一个\0,要计算这个字符串中有几个字符,可以用\0的地址,减去a的地址,通过指针减指针,来计算出有多少个字符

??因为从数组首元素地址开始,所以我们将arr数组名传给my_strlen函数并用char*str指针接收这个char类型变量的地址,同时指针减指针得到的是指针之间元素的个数,因此函数的返回类型为int类型。将第一个元素的地址赋给新的指针char*start代表第一个字符,而后用while循环,*str表示str指针指向的元素,从第一个元素开始,只要指向的元素不是\0(因为\0的ASCII码值就是0)str就++继续往后走,直到\0,最终返回str-start,指针减指针,算出字符串中字符的个数并进行打印。

六、下面我想来说一说我之前学习指针混淆的一些地方

易错点1:指针 等价于 指针指向变量的地址

? ? ?我也不理解为什么我之前总是认为这二者之间存在某种神秘的隔阂╮(╯-╰)╭明明定义中说的清清楚楚,指针就是用来存放地址的,这两者完全可以画上等号鸭,这就相当于,我用袋子装着写着你地址的小纸条 跟 我直接拿着写着你地址的小纸条 去找你,效果是完全一样滴,都可以找到你鸭? ψ(`?′)ψ

? ? 因此,指针有不同类型的区别,同样地址也有;指针的类型有int*,char*等等,那地址当然也一样喽

易错点2:指针的类型 不等于 指针指向的变量类型

?就拿最简单的这个int*p指针来举例叭,我们都知道这里定义了一个指针变量,指针的名字叫做p,删去指针的名字p,剩下的内容是指针的类型int*,指针的类型就表明这是一个指向整型的指针变量;同样,删去指针名字p和它前面的*表示的就是指针指向的类型int

易错点3:指针类型不同不代表指针大小不同

? ? 虽然p1指针和p2指针类型不同,但是两个指针都是用来存放地址的,无论是整型地址还是字符型地址,地址都是64个比特位,要把这个地址存起来所需要的空间自然也是一样的。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-24 15:05:50  更:2022-02-24 15:07:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:16:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码