C 语言指针 5 分钟教程

网友投稿 235 2022-09-15

C 语言指针 5 分钟教程

C 语言指针 5 分钟教程

指针、引用和取值

什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量。在这份教程里“引用”表示计算机内存地址。从指针指向的内存读取数据称作指针的取值。指针可以指向某些具体类型的变量地址,例如int、long和double。指针也可以是void类型、NULL指针和未初始化指针。本文会对上述所有指针类型进行探讨。

&是地址操作符,用来引用一个内存地址。通过在变量名字前使用&操作符,我们可以得到该变量的内存地址。

这里可以把指针、引用和值的关系类比为信封、邮箱地址和房子。一个指针就好像是一个信封,我们可以在上面填写邮寄地址。一个引用(地址)就像是一个邮件地址,它是实际的地址。取值就像是地址对应的房子。我们可以把信封上的地址擦掉,写上另外一个我们想要的地址,但这个行为对房子没有任何影响。

void指针、NULL指针和未初始化指针

int *uninit; // int指针未初始化int *nullptr = NULL; // 初始化为NULLvoid *vptr; // void指针未初始化int val = 1;int *iptr;int *castptr; // void类型可以存储任意类型的指针或引用iptr = &val;vptr = iptr;printf("iptr=%p, vptr=%p\n", iptr, vptr); // 通过显示转换,我们可以把一个void指针转成// int指针并进行取值castptr = (int *)vptr;printf("*castptr=%d\n", *castptr); // 打印null和未初始化指针printf("uninit=%p, nullptr=%p\n", uninit, nullptr);// 不知道你会得到怎样的返回值,会是随机的垃圾地址吗?// printf("*nullptr=%d\n", nullptr);// 这里会产生一个段错误// printf("*nullptr=%d\n", nullptr);

执行上面的代码,你会得到类似下面对应不同内存地址的输出。

iptr=0x7fff94b89c6c, vptr=0x7fff94b89c6c*castptr=1uninit=0x7fff94b89d50, nullptr=(nil)

第9行到11行,我们为int指针赋值为一个引用并把int指针赋值为void指针。void指针可以保存各种其它指针类型。大多数时候它们被用来存储数据结构。可以注意到,第11行我们打印了int和void指针的地址。它们现在指向了同样的内存地址。所有的指针都存储了内存地址。它们的类型只在取值时起作用。

第15到16行,我们把void指针转换为int指针castptr。请注意这里需要显示转换。虽然C语言并不要求显示地转换,但这样会增加代码的可读性。接着我们对castptr指针取值,值为1。

第19行非常有意思,在这里打印未初始化指针和NULL指针。值得注意的是,未初始化指针是有内存地址的,而且是一个垃圾地址。不知道这个内存地址指向的值是什么。这就是为什么不要对未初始化指针取值的原因。最好的情况是你取到的是垃圾地址接下来你需要对程序进行调试,最坏的情况则会导致程序崩溃。

NULL指针被初始化为o。NULL是一个特殊的地址,用NULL赋值的指针指向的地址为0而不是随机的地址。只有当你准备使用这个地址时有效。不要对NULL地址取值,否则会产生段错误。

指针和数组

C语言的数组表示一段连续的内存空间,用来存储多个特定类型的对象。与之相反,指针用来存储单个内存地址。数组和指针不是同一种结构因此不可以互相转换。而数组变量指向了数组的第一个元素的内存地址。

一个数组变量是一个常量。即使指针变量指向同样的地址或者一个不同的数组,也不能把指针赋值给数组变量。也不可以将一个数组变量赋值给另一个数组。然而,可以把一个数组变量赋值给指针,这一点似乎让人感到费解。把数组变量赋值给指针时,实际上是把指向数组第一个元素的地址赋给指针。

int myarray[4] = {1,2,3,0};int *ptr = myarray;printf("*ptr=%d\n", *ptr); // 数组变量是常量,不能做下面的赋值// myarray = ptr// myarray = myarray2// myarray = &myarray2[0]

第1行初始化了一个int数组,第2行用数组变量初始化了一个int指针。由于数组变量实际上是第一个元素的地址,因此我们可以把这个地址赋值给指针。这个赋值与int *ptr = &myarray[0]效果相同,显示地把数组的第一个元素地址赋值到了ptr引用。这里需要注意的是,这里指针需要和数组的元素类型保持一致,除非指针类型为void。

指针与结构体

struct person { int age; char *name;};struct person first;struct person *ptr; first.age = 21;char *fullname = "full name";first.name = fullname;ptr = &first; printf("age=%d, name=%s\n", first.age, ptr->name);

第13行我们打印了结构体实例的age和name。这里需要注意两个不同的符号,’.’ 和 ‘->’ 。结构体实例可以通过使用 ‘.’ 符号访问age变量。对于结构体实例的指针,我们可以通过 ‘->’ 符号访问name变量。也可以同样通过(*ptr).name来访问name变量。

总结

希望这份简短的概述能够有助于了解不同的指针类型。在后续的博文中我们会探讨其它类型的指针和高级用法,比如函数指针。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:告别11年军旅生涯,北控新内线邹雨宸感谢八一队!
下一篇:Google 2016 面试题5 | 岛屿计数2
相关文章

 发表评论

暂时没有评论,来抢沙发吧~