是什么,令无数C语言学子痛哭流涕。
是什么,令无数C语言学子抱头鼠窜。
没错,是指针!
什么是指针?
初识与内存
C语言中,指针=地址=内存单元的编号
换句话说,指针指向一个你定义的元素。
最简单的指针如下:
此时,a的地址被存储到了p中,而p即是指针,类型为int*。
说完类型,不得不提到的就是其占用内存空间
在x64环境下,int*的内存占用空间为8。
这是因为x64的地址是8个字节,而x86的地址是4个字节。
同样的,char*、short*、long*等类型
在x86环境下为4个字节,在x64环境下为8个字节。
怎么使用指针?
我们需要在这里引入解引用符号:
*
一个小小的星号。
按照上述内容,p存储了a的地址,而给*p赋值则可以直接改变a的值。
这就是最基本的使用指针的方式。
为什么要使用指针?
我们不难发现,如果我们只是在main函数里使用指针,倒不如直接更改赋值来的更快。
但是,我们似乎忘记了之前学习过的一个东西——函数。
函数的传值调用和传址调用
我们写出最简单的交换两个值的函数:
如果我们在main函数里使用以上代码,我们轻松地交换了两个数的值。
但是很抱歉的是,我们只能改变形参的值,而无法改变实参的值。
那么有没有办法改变实参的值呢?
答案是:指针。
将上述代码中的x和y都换为int*类型的指针后(同时传的值也是地址即&a,&b)
我们成功做到了a和b这两个实参的值的转换。
而第一种操作被称为传值调用,第二种被称为传址调用。
数组名亦是地址(指针)
除了一个值以外,我们知道函数也可以传数组。
通常情况下,数组名是首元素的地址。
那么&arr和arr有什么区别呢?
两者相差了16(地址是十六进制!!!)
这是因为arr代表了数组首元素的地址,而&arr里的arr代表了整个数组的地址。
当选择跳过1个的时候,arr跳到下一个元素,而&arr则会跳到整个数组之后。
再看这个代码,输出的数据将会是40,代表了整个数组的大小。
这就是arr不作为数组首元素地址的两个特例,sizeof(arr)和&arr。
再绕回指针,数组名既然是地址,那么可以作为指针调用吗?答案是可以的。
(当然,函数的返回类型不一定是void)
也就是说,我们可以通过指向数组的指针,来改变数组内的元素了。
如果说*p可以等价于a,那么大胆推出p[i]就可以等价于数组的元素。(因为arr是地址嘛)
经过实践,是可以的。
我们把这种指针,称为数组指针。
指针数组
既然指针内存储着相应变量的地址,那么指针是否也可以组成自己的数组呢?
其中,arr数组便是一个指针数组(数组名亦是地址)。
函数指针
那有指向各类变量的指针,指向数组的指针,有没有函数的指针呢?
试试就知道了。
可以看到,ptr完美的代替了ARR。
那么函数名和&函数名有区别吗?答案是无,这两者等价,所以在我们写代码的时候,直接写函数名即可。
再次回到这个问题,有什么用呢?直接使用函数难道不香吗?
我们不要忘记了,函数之间是可以互相调用的。
那么,如果我们有一个中转站,我们使用函数指针,是否就能够方便的多了呢?
我们就可以通过用户输入的值,来使用对应函数了。
这会使代码更加的简洁(就如同函数,分块写的目的便是使得逻辑更清晰)
而且,当我们使用上指针数组的时候,我们甚至可以将函数存入,并且按照数组的方式来使用这些函数,简洁更多。