数组与指针

Posted wshl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组与指针相关的知识,希望对你有一定的参考价值。

序:天气逐渐转冷了,各位IT界的朋友,注意保暖,爱惜自己身体~~

 

最近在浏览某篇博文的时候,看到了大概两年前看到过的一个问题,是一个面试题,因为两年前那时候没有搞懂,所以当时也没有过多地纠结,最近再次看到这个问题,颇有感慨,因此,就结合自己最近两年左右的经验,简单总结一下。

 

面试题大概是这样:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        int numbers[4] = {10, 20, 30, 40};
        int *p = (int *)(&numbers + 1);
        NSLog(@"%d", *(p - 1));

}

// 请问打印结果。

 

换作在两年前,我看到这种问题,连吃午饭的胃口都没有了。。。。

但是现在再重新来看这个问题,虽然需要经过一点时间的思考,但还是可以得出正确结果为40。

 

下面咱们就一步一步来整理一下:

首先来看

// numbers数组装有4个int类型的元素,由于一个int类型占4个字节,因此,numbers数组总共占有16个字节。
int numbers[4] = {10, 20, 30, 40};

然后,咱们来打印一下内存地址

// 数组的内存地址、数组中第一个元素的内存地址,这二者其实是同一个值,如下:
NSLog(@"%p", numbers); // 这种写法是在获取 数组的内存地址,也叫做数组名
NSLog(@"%p", &numbers[0]); // 这种写法是在获取 数组中第一个元素的的内存地址

紧接着,咱们来定义一个指针

int *p; // 这种写法,代表p将要指向int类型的数据

然后给它赋值

p = &numbers[0]; // 这种写法,表示p指向了数组中第一个元素的内存地址。即指向第一个元素所占用的4个字节(因为int为4个字节)

这里,p只会存储4个字节中的第一个字节(下面的打印就可以验证),这就是int的意义所在,因为已经提前声明了p是指向int类型的数据,因此只要根据p存储的

那个字节,依次按序往下再算3个字节,那么这4个字节就是p所指向的这个数据所占用的内存。同理double、float、long。

NSLog(@"%p", p); 

咱们再来看p 和 p + 1的结果比较

NSLog(@"%p", p); // 0x7ffeefbff590
NSLog(@"%p", p + 1); // 0x7ffeefbff594

结果显示,p + 1增加了4。

其实,可以简单的推出一个结论:

// 指针数据 + 1,表示当前指针指向的地址值 + 指向类型所占用的字节数(如下打印验证)。
因此,可以推导出:
指针p + n 表示 p指向的地址值 + n * p指向的类型所占用的字节数。
同理,亦可得出:
指针p + n 表示 p指向的地址值 - n * p指向的类型所占用的字节数。

紧接着,再来看下面这种写法表达的意思

NSLog(@"%d", *p);

这种写法,结果为指针p指向的数据的值(结果为10,因为p指向的是第一个元素)。

 

上面提到,由于数组名(数组的内存地址)其实就是数组中第一个元素的内存地址,因此,数组名的另外一层含义即为:数组中第一个元素的内存指针。所以,下面

这种写法所得到的结果,就是数组中第一个元素的值。

NSLog(@"%d", *numbers); // 10

再来几句代码比较一下就会更加有理解

NSLog(@"%d", *(&numbers[0])); // 10
NSLog(@"%d", *(&numbers[0] + 1)); // 20
NSLog(@"%d", *(&numbers[0] + 2)); // 30
NSLog(@"%d", *(&numbers[0] + 3)); // 40

说到这里,其实可以得出一个常识:&a就代表一个指针。上面用到的&numbers[0]其实就是一个指针,只不过为了简单化,所以用p代替了。

 

刚才也说了,数组名的意义,其实就是&numbers[0],即指向数组中第一个元素的指针。那么顾名思义,&numbers的意义即为:指向这个数组的指针。看如下

印:

 

NSLog(@"%p", &numbers); // 0x7ffeefbff590
NSLog(@"%p", numbers); // 0x7ffeefbff590

 

不难看出,&numbers的打印结果同numbers,其实就是数组中第一个元素的内存地址,也为数组的内存地址。那么看一下&numbers + 1得到的结果是否遵循刚

才得出的结论:

NSLog(@"%p", &numbers);
NSLog(@"%p", &numbers + 1);

根据结果可以看出,&numbers + 1得到的地址也遵循之前的结论,因为&numbers指针指向的数据类型所占用的位数是16(numbers数组中存有4个int类型),因此&numbers + 1的结果就增加了16。

 

通过上面一连串的规整,那么再回到文章一开始列出的面试题,就不难得到正确答案是40了。

有兴趣的童鞋可以再尝试练习一下二维、甚至三维数组,可以进一步加深理解。

 

 









以上是关于数组与指针的主要内容,如果未能解决你的问题,请参考以下文章

在第6731次释放指针后双重免费或损坏

指针与数组

指针与数组

Go语言切片

指针与一维数组和二维数组以及字符串指针数组的学习笔记

c语言中如何通过二级指针来操作二维数组