大白话解指针(一):初识指针
指针,pointer, * ,“C语言的精髓”,“C语言中最难的内容”,无需多言,这些头衔足矣引起我们对指针的重视。
大概了解指针
先把“指针是存放地址的变量”这种烂大街的结论先放在一边,不管它。
最首先应强调的是,”指针“(pointer) 是一种变量类型,没错,是一种独特的变量类型!
我们在程序中时常可以看到指针变量的定义如下:
int* a = NULL;
它表示,a是一个int类型指针,int类型指针和int类型完全是两码事
就像char,float,double都各属于一种变量类型一样,指针就是指针,它和int什么的完全是两码事,我们把它当做一个新类型的变量来理解。至于什么int*, char*都是属于指针这个大类下的分类。
指针的定义有两种风格,它们完全等价,只根据自己的需求进行选择,哪个顺眼用哪个。
1)int* a;
2) int *a;
即“*”是紧挨着变量名还是紧挨着int。
(我个人比较喜欢紧挨着int,可以提醒我们是指针类型。)
两种命名风格的优缺点:
1)由于*紧紧贴着int,可以提醒我们a是int指针类型,强调它是“指针",对单个变量比较友 好。
但对于多个变量赋值,如要在一行创建两个指针,你需要这样写:
int* a, *b; //先无视野指针的问题
感觉不太美观,而且容易漏掉星号。
如果写 int* a,b,就只有a是指针,b还是int常量。
2) 紧贴变量的命名可以强调他是 ”int"类型的指针,对多个指针变量的命名也非常友好,不会忘记加星号。但感觉会对于”指针“的强调就少了。
int *a, *b;
初步了解指针
好,现在回到那句烂大街的结论:“指针是存放地址的变量”。
指针是个变量,就说明它可以存东西。它存什么?它存地址。
指针的内容就是某个变量的地址
指针就是地址
什么是地址?我用比较通俗的话解释一下:
int a = 10;
//在我们编写代码时,我们的变量,如这里的a会存储在我们电脑存储空间,比如硬盘的某个位置
//上,这个位置是看作一块划给a的地皮,地皮上有一块独一无二的牌子,牌子内容说明这里是哪里
//这个牌子的内容就是这个变量的地址。就是a到底在哪里!
printf("%p",&a);//注意%p,不是%d
//用&符号可以找a到底放在哪里了,即会输出a的地址。我们把这个符号称为取地址符,
//每一次输出不一样是正常的,但输出的位数总是相同的,说明a只是换了位置罢了。
我们在定义指针时
定义int*,说明这个指针里面存的是一个int变量的地址。
定义float*,说明这个指针里面存的是一个float变量的地址。
。。。
我们发现,不论定义的指针是哪个类型,它都存的是地址,所以
指针的大小是固定的,int* 和float* 它们大小都是一样的,大小只取决你电脑性能怎么样。
一个指针在32位的计算机上,占4个字节;
一个指针在64位的计算机上,占8个字节。
所以,我们一定要把一个地址放到指针里。
所以一个基本的指针初始化就来了:
int a = 10;
int* pointer_to_a = &a;
printf("%p",pointer_to_a);
现在,pointer_to_a中就有a的地址了,输出的值就是a存放的位置。
初步使用指针
指针存地址,然后呢?有什么用?
我们有地址,我们就可以通过地址直接去影响指向的变量的值。
说通俗点,和开别人盒差不多。
我们开的是变量的盒。
有了这个变量的地址,变量就没有”隐私“了,我们可以影响这个变量的值,而且比一般的访问更快。(也更方便老师出题)
(先不考虑const)
好
这里就要提出疑问了,我们只有地址,怎么去看这个变量的值是多少以及如何去影响这个在地址的变量的值?
这里就要引出下一小节:
让人头大的*
“*”,这个符号在指针中有两个用途,请不要混淆,很容易混淆!
1)在定义指针时出场,说明他是一个指针变量。
int* pointer_to_a = &a;
2)作为取值符号出场!
int a = 10;
int* pointer_to_a = &a;
printf(“%d”,*pointer_to_a);//注意,变成%d了!
这里会输出10,就是a的值。说明在指针前加*,就可以得到放在该地址的变量的值
有了取值符,我们就可以操作地址所指的变量a了。
如果*pointer_to_a = *pointer_to_a + 1;的话,a会变成11。这就做到影响a的值了。
针对指针的加减法
*pointer_to_a = *pointer_to_a + 1;
和
pointer_to_a = pointer_to_a + 1;
对指针操作和对指针所指的值操作是不一样。
指针加1,指针的地址会加上它的指针类型的大小。
多说无益,上案例:
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <Windows.h>
#include <time.h>
#include <stdlib.h>
int main(void)
{
int a = 10;
int* pointer_to_a = &a;
printf("%p\n", pointer_to_a);
pointer_to_a = pointer_to_a + 1;
printf("%p\n", pointer_to_a);
printf("\n\n");
short a_short = 10;
short* pointer_to_a_short = &a_short;
printf("%p\n", pointer_to_a_short);
pointer_to_a_short = pointer_to_a_short + 1;
printf("%p\n", pointer_to_a_short);
}
推荐打开vs2022试一试,输出后我们可以发现,同样是指针加一,int型指针pointer_to_a的地址变化值是4,而short型指针pointer_to_a_short的地址变化值是2.
正好和int和short占用的字节数匹配。
这是为了能够和数组搭配使用所设置的。
野指针,空指针
野指针,是一种不正常使用指针类型所产生的一种错误的指针。
它一般出现在指针初始化而忘记为其赋予初始值时,如就写个int *a;后面就不管了。
而没有为其初始化地址,不代表它就在哪里不动了,无初始值的指针会随机指向未知的位置,甚至是比较关键比较脆弱的存储位置,野指针就是个不定时炸弹,请务必避免这种写法。
PS.最好尽快为定义的指针赋予初始值。免得夜长梦多。
空指针
如 int* a = NULL;
这是说明当前指针不指向任何东西,不会乱指,在还不能为指针赋予地址时,为了避免野指针的出现,可以先将指针置空,更安全。
基本的使用如上所示,下一章博客“大白话解数组和指针”会解析数组和指针这部分比较进阶内容。
非常感谢您可以耐心读到这里,博客内容写的很粗糙,只是分享自己在学习中的一些想法,有错误指正和改进欢迎提出!