当前位置:首页 > 公众号精选 > 混说Linux
[导读]指针使得 C 语言能够更高效地实现对计算机底层硬件的操作,而计算机硬件的操作很大程度上依赖地址,指针便提供了一种对地址操作的方法,在一定意义上,指针是c语言的精髓,所以一定要耐心看完。指针对于很多c语言初学者来说可能难以理解,一不小心可能被指针的指向关系绕进去,在这里就对指针做一些总结,写一下自己的理解。

指针使得 C 语言能够更高效地实现对计算机底层硬件的操作,而计算机硬件的操作很大程度上依赖地址,指针便提供了一种对地址操作的方法,在一定意义上,指针是c语言的精髓,所以一定要耐心看完。指针对于很多c语言初学者来说可能难以理解,一不小心可能被指针的指向关系绕进去,在这里就对指针做一些总结,写一下自己的理解。

一. 指针的介绍


在程序中,我们声明一个变量(int a = 1),将数据1存到变量a中,计算机内部会将这个数据存到内存(RAM)中,那么,数据存到某个地方,就会涉及地址。就像你买的快递,快递到了就要存到某个驿站里面放着,你的快递就是一个数据,驿站就是一个变量,这个驿站就要有地址,不然全国这么多驿站你怎么知道你的快递在哪个驿站。


到这里,地址的概念应该有了吧。


现在想想地址(比如0x0000 0001)不也是一个数据吗,那么不也可以用一个变量存地址这个数据?是的,可以,这个变量就是指针,指针它就是存储另一个变量的内存地址的一种数据类型,即指针的内容就是另一个变量的内存地址。





指针本身也是一个变量,所以指针变量也有自己的地址,只是它有点特殊,它存放的是另一个变量的地址而已,理解这句话就行。




前面讲到过指针它是一种数据类型,为了方便,我们就规定在这种类型后面加*号表示该类型指针,有char型指针(char *)、double型指针(double *)和int型指针(int *)等等。


试着敲一下下面一段代码,可以加深对指针的认识:

int a = 1; // 定义一个int型变量int *p = &a; // 定义一个int型指针p,&a表示对a取地址,指针p的内容是a的地址// int  *p;   p = &a;    // 第二行也可以这样写,意思一样printf("%p\n", &a); // 打印a的地址printf("%p\n", p); // 打印指针p指向的地址// %p是打印地址(指针地址),是十六进制的形式


C/C++ 中规定了 * 操作符来从对应指针类型存放的地址中拿出相应数据,再定义一个变量int b = *p,指针p存了a的地址,*p就是拿出a的值,b的值就变成了1,*操作也被称为解引用。



二. 指针的相关操作(运算)


算数运算:+、-、++、--、

指针的运算是特别容易搞错的,千万不能以为和普通类型(比如int型数据)的运算一样。


指针的加减运算:


  1. 指针+1/指针-1,加/减的是整个指针类型的长度,与其说指针的加减法,我认为不如说成指针的偏移更合适,接下来看为什么是偏移,举个非常明显的例子:

char a[5] = {1, 2, 3, 4, 5}; // 定义一个char型数组,这里的a实质上是一个指针,指向这个数组的首元素a[0]的指针char *p = a;printf("%d\n", *p); // 输出1 --> a[0]printf("%d\n", *(p + 1)); // 输出2 --> a[1]......


看输出的结果就很容易看出规律,p指针指向a[0],特别注意p+1指针变成指向a[1],所以*(p+1)  = a[1] = 2,而不是*(p+1)  = a[0] + 1 = 2,当然这里两个答案凑巧一样,但是把数组的内容换一下就不会是一样了,如果是改成(*p) + 1,那么就是(*p) + 1 = a[0] + 1 = 2,同理可以改成p+2、p+3......


还有试着定义其它类型的数组(比如int型:int a[5] = {1, 2, 3, 4, 5};),看看是不是这个规律,就可以知道指针加减的是这个指针类型的长度,也就是指针的偏移,还可以尝试定义结构体数组,将会有更深的理解。


减法就不用多说了,理解了指针p+1/p-1,那么指针p++/p--其实是一样的,都是偏移。



三. 多级指针





说起多级指针这个东西,曾经大一学c语言的时候,学到二级指针都已经把我给绕晕了,如果当时你给我写个int ********p出来,我估计直接崩溃到放弃。




我们先来说说二级指针吧!前面有讲到,指针也是一种数据类型,是一种变量,也有自己的地址,所以既然有地址,而指针就是存放另一个变量的地址的呀,那为什么不能再用一个指针存放这个指针的地址呢,对吧!所以就有了二级指针,就是指向指针的指针


ok!来点生活上的东西,快递柜大家都用过吧,快递小哥给你发一个取件码你就能拿到快递。



这里的每一个柜子就是一块内存,取件码就是地址,柜子里的快递就是存储在内存的内容/数据。


假如快递小哥把你的快递放到"058柜子",给你发取件码,那么你输入取件码就可以取到快递。

如果快递小哥逗你一下,故意给你发"057柜子"的取件码,然后在"057柜子"放一张纸条,上面写:快递在058柜子,这时候你肯定是按照纸条从"058柜子"里就可以拿到快递。


这里的"057柜子"就是指针,指针里面存放另一个变量(058柜子)的地址。

如果快递小哥给你发"056柜子"的取件码,在"056柜子"里放一张纸条写:快递在"057柜子"里,又在"057柜子"里放一张纸条写:快递在"058柜子"里。


这里的"056柜子"就是二级指针,"057柜子"就是指针,"058柜子"就是指针存放的另一个变量。

现在明白了二级指针吧,那么,N级指针也就那样,也就是指向指针的指针的指针的指针的指针........,是不是非常简单!

int a = 1;int *p = &a;int **pp = &p; // 二级指针pp存放指针p的地址,即二级指针pp指向指针pint ***ppp = &pp; // 三级指针ppp存放二级指针pp的地址,即三级指针ppp指向二级指针pp......


总之,如果一个内存如果存放的是另一个变量的地址,那么就叫指针。一块内存要么存放实际内容/数据,要么存放的是另一个变量的地址,确实是刚刚所说的非常简单。





【总结两点】:

1. 指针本身也是一个变量,也有自己的地址,需要内存存储。

2. 指针存放的是所指向的变量的地址,这个所指向的变量也可以是一个指针。


特别注意】:面试可能被问到指针的大小

1. 指针的大小跟指针是什么类型的没有任何关系。

 2. 在32为系统系统中,所有的指针大小都是4个字节,原因是32系统上所有变量的地址都是32位的,而指针用来存地址的。




最后,大家要明白一个概念,其实并没有什么多级指针这种东西,多级指针就是个指针,称为多级指针是为了我们方便表达而取的逻辑名称。



四. 多维数组





二维数组其实和二级指针有着相似的理解方法:

比如a[3][2],把它理解成一个一维数组来看待,这个一维数组里面有三个元素,只是这个一维数组有点特殊,它的每个元素又是一个一维数组而已。




懂了上面这段话,二维数组就很好理解。

前面我们已经知道一维数组a[3]中,a实质上是一个指针,指向这个数组首元素a[0]:
int a[3] = {1, 2, 3};// a[0]  -->  *aprintf("%d\n", *a); // 打印 1  -->  a[0] 的值// a[1]  -->  *(a + 1)printf("%d\n", *(a + 1)); // 打印 2  -->  a[1] 的值// a[2]  -->  *(a + 2)printf("%d\n", *(a + 2)); // 打印 3  -->  a[2] 的值

那么,二维数组a[3][2]当成一维数组看是不是可以得出:
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};// a[0][0]  -->  (*a)[0]printf("%d\n", (*a)[0]); // 打印 1  -->  a[0][0] 的值// a[1][0]  -->  (*(a + 1))[0]printf("%d\n", (*(a + 1))[0]); // 打印 3  -->  a[1][0] 的值// a[2][0]  -->  (*(a + 2))[0]printf("%d\n", (*(a + 2))[0]); // 打印 5  -->  a[2][0] 的值// a[2][1]  -->  (*(a + 2))[1]printf("%d\n", (*(a + 2))[1]); // 打印 6  -->  a[2][1] 的值// ..... 二维数组其它元素类似都可以输出

结论一:a[m][n]  等价于 (*(a + m)[n]  -->就是一个数组指针(后面会提到)

基于前面两种指针和数组的变换,可以继续得出:
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};// a[0][0]  -->  (*a)[0]  -->  *(*a + 0)  -->  把 *a 当成整体printf("%d\n", *(*a)); // 打印 1  -->  a[0][0] 的值// a[1][0]  -->  (*(a + 1))[0]  -->  *(*(a + 1) + 0)printf("%d\n", *(*(a + 1))); // 打印 3  -->  a[1][0] 的值// a[2][0]  -->  (*(a + 2))[0]  -->  *(*(a + 2) + 0)printf("%d\n", *(*(a + 2))); // 打印 5  -->  a[2][0] 的值// a[2][1]  -->  (*(a + 2))[1]  -->  *(*(a + 2) + 1)printf("%d\n", *(*(a + 2) + 1)); // 打印 6  -->  a[2][1] 的值// ..... 二维数组其它元素类似都可以输出

结论二:a[m][n] 等价于   *(*(a + m) + n)


五. 数组指针与指针数组


1. 数组指针:指针在后,说明它就是个指针,所以数组指针指向的是数组,相当于一次声明了一个指针。从前面就已经知道,二维数组a[3][2]中,a实质上就是一个数组指针




公式:

指向的那个数组的元素类型  (*指针名字)[指向的数组的元素个数]




2. 指针数组:数组在后,说明它就是个数组。字符数组是什么?就是存放字符的数组,那么指针数组就是存放指针类型的数组,相当于一次声明了多个指针。




公式:

数组元素的类型  数组名字[数组元素个数]




char *a[3] = {"red", "green", "blue"};char **pp = a; //定义二级指针pp, a本质上相当于二级指针printf("%s\n", pp[0]); // 打印 redprintf("%s\n", pp[1]); // 打印 greenprintf("%s\n", pp[2]); // 打印 blue

直观上区分数组指针和指针数组的方法:
由于数组指针的 [] 比 * 的优先级,所以数组指针的指针加括号,所以看看指针有没有用圆括号括起来,就可以区分开。


六. 其它


关于指针想写的内容还有很多,其实这只是开了个头,比如:野指针、函数指针、函数参数传递方式、const 修饰指针、动态内存分配: malloc 和 free、堆, 栈、内存泄露......,以后慢慢补齐。

指针在链表使用的比较多,多写一些链表的操作会对指针理解很有帮助,链表节点的增加、删除、修改、查找,单向链表、双向链表、双向循环链表、内核链表等等。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

随着信息技术的迅猛发展和大数据时代的到来,机器学习成为了人工智能领域中的核心技术之一。机器学习是通过模拟人类学习行为,使计算机系统能够从数据中自动发现规律、提取特征并进行预测和决策的过程。它在诸多领域取得了广泛的应用,包...

关键字: 计算机 人工智能 机器学习

随着大数据时代的到来,数据处理成为了一项至关重要的任务。传统的数据处理方法往往面临着效率低下、准确性不高等问题,而机器学习技术的兴起为数据处理带来了全新的解决方案。本文将深入探讨机器学习在数据处理中的应用,并分析其优势和...

关键字: 数据处理 计算机 机器学习

机器学习是人工智能领域的一个重要分支,它使用各种算法来使计算机系统能够从数据中学习和改进,而无需进行明确的编程。在机器学习的广阔领域中,有多种算法被广泛应用,每种算法都有其独特的适用场景和优势。本文将详细介绍机器学习中的...

关键字: 机器学习 人工智能 计算机

随着信息技术的飞速发展,机器学习(Machine Learning)作为人工智能领域的重要分支,正在逐步改变我们生活的方方面面。那么,什么叫做机器学习呢?简单来说,机器学习是一门研究如何让计算机从数据中自动获取知识和技能...

关键字: 机器学习 人工智能 计算机

随着信息技术的飞速发展,数据已经成为现代社会的重要资源。数据挖掘和机器学习作为处理和分析数据的两大关键技术,在多个领域得到了广泛应用。尽管它们在某些方面存在重叠,但数据挖掘和机器学习在定义、目标、方法以及应用场景等方面存...

关键字: 数据挖掘 机器学习 计算机

计算机的历史可以追溯到公元前的古代算盘和查尔斯·巴贝奇的“分析机”构想。然而,现代意义上的计算机起源于二战时期对复杂军事计算需求的响应。1941年,美国宾夕法尼亚大学开发出了ENIAC(Electronic Numeri...

关键字: 计算机 云服务

自二十世纪以来,计算机技术经历了从机械计算装置到如今高度智能化、微型化的巨大飞跃,成为人类科技进步的重要推动力。电脑的发展史是一段充满创新与突破的历史,以下将按照时间顺序概述这一发展历程。

关键字: 电脑 计算机

计算机网络是当今信息化社会中不可或缺的基础设施,它将世界各地的计算机系统及其附属设备紧密联系在一起,实现了信息的高速传输与共享资源的有效利用。计算机网络的定义可以归纳为:计算机网络是一系列分布在不同地理位置、具备独立功能...

关键字: 计算机 信息交互

随着科技的不断进步,人工智能(AI)已成为当今世界的热门话题。它以其强大的计算能力和深度学习能力,在多个领域展现出巨大的应用潜力。本文将对人工智能技术进行详细的探究,包括其定义、发展历程、主要技术、应用领域以及面临的挑战...

关键字: 人工智能 深度学习 计算机

4月1日消息,戴尔在中国的PC销量持续下滑(份额已被华为超越),这迫使他们不得不采取更多的裁员措施。

关键字: 戴尔 PC 计算机
关闭