使用C编程语言的指针的简单介绍

2020-06-17 18:52:50

指针是那些在您第一次了解它们时毫无意义的概念之一。通常,一个视角的改变就足以让你大脑中的某些东西发出咔哒声--呼!--一切都神奇地落到了它的位置上。

尽管它们名声不佳,但指针是极其强大的工具。此外,在某些语言(如C或GO)中,如果您想成为熟练的开发人员,理解它们是必须的。

让我们探索一下使用C编程语言的指针和几个非常简单的例子。

指针是保存对内存中某物的引用的变量。我知道这听起来令人困惑,但通过几个例子,它会更有意义。请看下面的代码以及运行它的结果。

#include";stdio.h";#include";string.h";void print_character_info(char*char_POINTER);int main(){char alphabet[10]={';a';,';b';,';c';,';d';,';e';};char*字母表指针;//Alphabet_POINTER指向字母表的开头,字符';a';Alphabet_POINTER=alphabet;print_character_info(Alphabet_POINTER);//现在。让&/让它指向字母表指针++;print_character_info(字母表指针);//再多一个字符,现在应该指向';c';字母表_指针++;print_character_info(字母表指针);//再多一个,现在应该指向';d';字母表_指针++;print_character_info(字母表指针);//让';print_character_info(字母表指针);return 0;}void print_character_info(char*char_Pointer){printf(";指针";指针的地址是:%p\n";,&;字符指针);printf(";它指向的地址:%p\n";,字符指针);printf(";它指向的地址包含值:%c\n\。

指针的地址是:0x7fff95b03d08它指向的地址是:0x7fff95b03d2e它指向的地址包含值:a指针的地址是:0x7fff95b03d08它指向的地址是:0x7fff95b03d2f它指向的地址包含值:b指针的地址是:0x7fff95b。

让我们逐行来看,以便更好地了解所发生的事情。首先,我们声明以下两个变量:

字母表是一个字符数组,包含英语字母表的前5个字母。

ALPARBET_POINTER是char类型的指针。在C中,我们通过在变量名前加上星号';*';来定义指针。声明正确的指针类型很重要:它必须与它所指向的数据类型相匹配,否则,事情可能会变得有点怪异(我们稍后会讨论这一点)。

根据运行代码的结果,我们可以在声明变量之后立即形成内存内容的图片:

指针的地址是:0x7fff95b03d08,它指向的地址是:0x7fff95b03d2e,它指向的地址包含值:a。

字母指针的地址保持不变,我们没有对指针本身的位置进行任何更改。有趣的部分是它的内容,现在设置为值0x7fff95b03d2e。查一下桌子,你能找到吗?是的,它是字母表的开始!更准确地说,是包含值';a';的地址。

您可以使用';*';运算符访问所指向的地址中包含的值。如果在执行的这一时刻运行,则下面的行会打印值';a';:

如你所见,我们的指针的内容是一个简单的地址。这意味着我们可以动态更改它所指向的内容。正如我们即将看到的那样,C语言通过为我们处理指针算法使这一点变得非常容易。

指针算术意味着您可以对指针执行基本算术运算,以操纵它们指向哪个地址。要实现这一点,可以相对于整数的当前位置加减整数。同样,通过示例可以更容易理解这一点。

第二行是我们值得信任的print_character_info函数,没有什么新东西。然而,第一行非常酷:我们抓取字母指针并将其值加1,结果,我们现在指向一行中的下一个地址(包含#39;b';的地址)。执行一次操作后,我们会得到以下结果:

指针的地址是:0x7fff95b03d08,它指向的地址是:0x7fff95b03d2f,它指向的地址包含值:b。

指针的地址是:0x7fff95b03d08,它指向的地址是:0x7fff95b03d30它指向的地址包含值:c。

我们继续这个过程,直到它最终指向数组的最后一个元素:字符。最后,内存看起来是这样的:

还记得我说过指针的类型很重要吗?原因之一是编译器使用该类型执行指针算术计算。

不同的变量类型在内存中使用不同的字节数量表示。在我的计算机上,字符仅使用一个字节(并且只有一个地址槽)表示。另一方面,整数需要4个字节。

这意味着当我为字符指针编写POINTER++时,我将移动到紧接在当前地址之后的地址。如果我在int指针上执行++,它将向前跳跃4个位置。通过不同的代码示例,我们可以看到这种效果:

//其余代码是相同的main(){char alphabet[10]={';a';,';b';,';c';,';d';,';e';};//请注意,现在字母表指针的类型是int*alphabet_POINTER;alphabet_POINTER=alphabet;print_character_info(ALPHBET_POINTER。}//其余代码相同。

打印完';a';之后-与我们的第一个示例相同-我们++指针。因为现在它的类型是int,它将跳到前面4个位置,指向--您猜对了--带有字符的地址。

指针的地址是:0x7fff95b03d08它指向的地址是:0x7fff95b03d2e它指向的地址包含值:a指针的地址是:0x7fff95b03d08它指向的地址是:0x7fff95b03d32它指向的地址包含值:E。

指定指针类型还有另一个重要原因。正如您刚刚读到的,不同的变量在内存中具有不同的大小。因此,当我们需要执行解引用来获得一个值时,编译器需要知道它应该获取多少字节,以及如何解释该数据。

最后一个主题,除了内存布局和变量/指针强制转换之外,还应该有自己的文章。我们可能晚些时候再来讨论他们。

我还需要澄清的是,指针本身占据了几个内存位置。在插图中,我将其简化为包含整个指针的单个地址。实际上,它们需要尽可能多的字节来表示CPU体系结构中的地址(通常是4个或8个)。

我希望阅读这篇文章能帮助您理解要点,或者至少能激发您对该主题的兴趣。您可能需要更多的时间和实验才能获得全面的理解,所以您可以随意获取代码样例并四处移动。调整它并阅读输出,这种方法在学习新的编程概念时总是对我有帮助。

很多其他重要的东西都建立在指针之上。即使您主要在高级编程语言上工作,了解事情是如何在幕后工作的也是很有用的。

与朋友和同事分享这篇文章。感谢您帮助我联系到可能会觉得此信息有用的人。

“黑客:剥削的艺术”第二章对指针和内存布局进行了令人惊叹的介绍。如果你想了解更多关于这个主题的知识,试一试。这本书和其他非常有用的书都可以在推荐书单中找到。

给我发一封有问题、评论或建议的电子邮件(它在关于我的页面上)。来吧,别害羞!