Linux系统中指针的详细分析与操作
创始人
2024-05-30 04:41:59
0

 

文章目录

一、指针

二、指针的初始化

三、指针的运算

四、指针与数组

五、指针与字符串

六、函数指针

七、NULL 指针

八、对复杂指针的解释

C 语言指针真正精髓的地方在于指针可以进行加减法,这一点极大的提升了程序的对指针使用的灵活性,同时也带来了不小的学习负担。正是因为 C 语言指针可运算,才奠定了如今 C 语言的地位。

一、指针

对于内存,我们可以简单地认为它就是大小相同、连续排布的格子,每一个格子的大小为一字节。为了更方便地找到某一个格子,我们通过对内存进行编号,通过编号来找到某一个具体的内存格子。


这样的编号通常称之为内存地址,如果程序想要获取某一块内存存放的数据,必须通过内存地址定位,再取出对应内存的数据。

 

一个指针变量存储着另一块内存的起始地址,相较于直接寻址的方式,如果想要通过一个指针获取指向的内存变量的话,首先需要获取到指针变量存储的内存地址,再通过这个地址来获取变量,所以这种方式又称为间接寻址。

在 C 函数实现中,所传入的参数均为原有变量的一个拷贝,在函数中对参数进行修改是无法影响到原有变量的值的,若需要对参数进行修改,可向函数传递该变量的内存地址。如此一来,即使对参数(地址)进行了拷贝,也可以通过地址对其进行修改,而变量的地址就保存在指针当中。


二、指针的初始化

操作符 &表示取一个变量的地址,并将该地址赋给变量 pointer,由此一来指针中的地址就是正确且合法的。

void main() {int number = 100;int *pointer;pointer = &number;
}

三、指针的运算

C 语言中的指针支持运算,不过仅支持加减法,并不支持乘除法。在前面我们已经提到过了,一元运算符 * 表示间接寻址,即取出指针的地址,根据该地址找到指针指向的变量。而对于指针的加减法而言,与指针指向的类型密切相关。


可以看到,对一个指向 int 的指针加 1,其地址增加了 4,正好是一个整型的大小。其原因在于如果仅仅是增加 1 的话,那么指针将会指向该整型的第二个字节,那么此时指针所指向的“整型”值将会变得非常奇怪,因为最后一个字节是其它数据的。


 

四、指针与数组

我们经常听到数组名称其实就是一个指针,数组名表示数组的首地址。但是这并不正确,数组名称和指针绝不等价,我们可以认为数组名称具有指针的特性,但不能说数组和指针等价。一个最为典型的例子就是使用 sizeof 求数组的长度。

#include void main() {int number[] = {1, 2, 3};int *pointer = number;printf("number's size: %ld \n", sizeof(number));printf("pointer's size: %ld \n", sizeof(pointer));
}// number's size: 12 
// pointer's size: 4 

在上述代码中我们明确地表示了 number 是一个整型数组,表示整型的集合,所以 sizeof 的结果为数组占用内存的总大小。而 pointer 仅仅只是一个整型指针,编译器并不知道它到底是指向一个整型,还是一坨整型,那么 sizeof 的结果自然而然的是指针占用内存空间的大小。

所以,数组名称所代表的含义要高于指针,但是这并不改变数组名是一个指针的事实。数组在内存中连续分布,再结合前面所提到的指针的运算,使得我们可以通过指针的方式访问数组中的元素。


五、指针与字符串

C 语言中字符串并非像其它语言一样,将其设置为基本数据类型,而是构建于数组之上,并在数组末尾添加 \0 表示结尾,这也是为什么数组和字符串经常成对出现的原因。

int main() {char *hello = {"Hello"};char world[] = {"World"};printf("hello: %s \n", hello);printf("world: %s \n", world);
}

如上述代码所示,我们既可以使用数组初始化一个字符串,也可以使用字符指针来初始化一个字符串,只不过使用字符指针初始化的字符串具有只读特性,使用数组初始化的字符串具有读写特性。


六、函数指针

在函数式编程中我们经常需要将一个函数作为参数传递给另外一个函数,其中比较经典的例子线程的创建与执行。不同于 fork 或者 vfork 调用,pthread_create 调用以一个函数指针作为参数,创建的线程转而执行该函数。

int filterArray(int *array, int size);

上述代码是一个简单的函数原型,接收一个整型数组和其长度,并返回一个整型。一个函数总是占用一段连续的内存区域,函数名称在某些情况下会被转换成该函数所在内存区域的首地址,这一点和数组非常的相似。也就是说,函数名称 filterArray 可以被替换成 (*pointerName),这样一来就得到了一个指向函数入口的指针:

int (*pointerName)(int *array, int size);

所以,函数指针其实就是对函数原型的稍加修改而已。


七、NULL 指针

标准定义了 NULL 指针,它作为一个特殊的指针变量,表示不指向任何东西,当我们在定义一个指针变量,并且不知道该指针指向何处时,就应该将其初始化为 NULL。其次,当我们使用 free 函数释放堆内存时,也应该将指针指向为NULL,防止出现内存访问错误。

#include int main() {char *s = NULL;s = (char *)malloc(sizeof(char) * 5);strcpy(s, "hello");free(s);s = NULL;return 0;
}

NULL 指针进行解引用是非法的,因为 NULL指针从定义上来看不指向任何东西。因此,当我们对指针进行解引用时应该对其进行检查,能显著减少 DEBUG 的时间。


八、对复杂指针的解释

有时候我们会看到诸如 char *(*name[124])(int **p) 这种看起来非常复杂的指针,对于此类复杂指针,我们只需要牢记两个关键点即可。

  • 对于一个符号定义而言,找到其名称,然后再按照优先级顺序进行解析。

  • 牢记 C 语言中操作符的优先级。

操作符描述
()聚组,例如5 / (2 + 3),和数学中的()语义相同
()函数调用,例如 3 + foo(),首先调用函数,而后执行加法操作
[]下标引用,例如 foo()[2],首先调用函数,根据函数返回的结果进行下标引用
.访问结构体成员,如 student[1].name 首先获取数组索引为1的元素,而后访问name成员
->访问结构指针成员,和 . 作用相同
++后缀自增,如 struct.name++,首先获取结构体成员再对其进行自增
后缀自减,同后缀自增
!逻辑反
~按位取反
++前缀自增
前缀自减
*间接访问,如 *p++ 首先对指针 p 进行自增,然后对自增后的指针进行间接访问
&取变量地址

可以看到,* 间接访问操作的优先级要远远低于()[]++ 以及 . 等常用操作符,也就是说,* 在复杂指针中就是个弟弟。

接下来就对 char *(*name[124])(int **p) 这个指针做一个具体的分析。首先得找到变量名称,上面有两个: name 以及 p,结合外面两对括号可知这是个函数指针,p 为函数参数。再来看 *name[124][]的优先级高于 *,所以 name 是一个数组,数组中保存了某种类型的指针。将所有的信息整合起来,就可以得到:name 是一个指针数组,保存了原型为 char *funcName(int **p) 的函数指针。

相关内容

热门资讯

定制系统数据安卓转苹果,体验跨... 你有没有想过,手机从安卓转到苹果,这中间的数据迁移,是不是就像搬家一样,既繁琐又让人头疼?别急,今天...
iphone怎么刷安卓双系统 你有没有想过,你的iPhone也能变身成为安卓双系统的小能手呢?没错,就是那个我们平时用来打电话、刷...
安卓系统网络拦截怎么设置,轻松... 你有没有遇到过这种情况:在使用安卓手机时,突然弹出一个广告,让你忍不住想关掉它?或者有时候,一些不安...
苹果系统和安卓系统的区别ppt... 你有没有想过,为什么你的手机里装的是苹果系统而不是安卓系统呢?是不是好奇它们之间有什么不一样的地方?...
安卓系统隐藏运行程序 你知道吗?手机里那些看似安静的小程序,其实可能正在偷偷地运行着呢!是不是觉得有点不可思议?别急,让我...
安卓设置系统简体与繁体,探索安... 亲爱的手机控们,你是否在某个瞬间,突然对手机上的文字产生了好奇,想要知道如何轻松切换安卓系统中的简体...
平凉综合办公系统安卓,便捷高效... 你有没有听说过那个超级方便的平凉综合办公系统安卓版?没错,就是那个能让你的工作生活变得更加轻松的神奇...
安卓系统的实验报告,深入剖析与... 你知道吗?最近我在手机上做了一场有趣的实验,就是测试安卓系统的性能。这可不是随便玩玩,而是真的深入研...
oppo安卓9系统如何,功能亮... 你有没有发现,你的OPPO手机最近是不是有点儿不一样了?是不是觉得它变得更加聪明、更加流畅了呢?哈哈...
苹果装安卓系统卡吗 你有没有想过,把苹果手机换成安卓系统,是不是就像换了个新世界?不过,听说有人担心,苹果装上安卓系统会...
rog安卓10系统键盘下面,键... 亲爱的读者,你是否曾在使用安卓手机时,对那小小的键盘下面隐藏的神秘世界感到好奇?今天,就让我带你一探...
618推荐手机安卓系统 618购物节又要来了!是不是已经迫不及待想要换一部新手机了呢?别急,今天我就要给你推荐几款在安卓系统...
4寸手机安卓系统吗 你有没有想过,为什么现在的手机屏幕越来越小,却依然能塞进那么多的功能呢?今天,我们就来聊聊这个话题:...
安卓系统开启后台程序,高效管理... 你有没有发现,手机里的安卓系统越来越智能了?它就像一个贴心的管家,默默地在后台为你打理着各种事务。但...
战地1内存和安卓系统,战地1内... 你有没有发现,最近玩《战地1》的小伙伴们都在抱怨内存不够用?别急,让我来给你详细解析一下这个问题,顺...
电脑连接安卓系统手机,探索跨平... 你有没有想过,你的电脑和安卓手机之间也能来个亲密接触呢?没错,就是那种无缝连接的感觉,让你的手机屏幕...
安卓系统和ios系统玩吃鸡 你有没有发现,最近不管是大街小巷,还是线上线下的聚会,提到最多的游戏就是“吃鸡”啦!这款游戏可谓是风...
阻止安卓系统杀程序,如何有效阻... 你有没有遇到过这种情况?手机里装了好多喜欢的应用,可是一不小心,某个程序就被安卓系统无情地杀掉了。别...
国内安卓系统大小对比图,国内安... 你有没有想过,我们每天使用的安卓系统,其实就像是一个庞大的“城市”,里面住着各种各样的“居民”,而这...
苹果和安卓系统大小,系统规模对... 你有没有想过,为什么你的手机里装了那么多应用,可内存还是不够用呢?今天,就让我带你一探究竟,揭秘苹果...