今天,在我们的一个小群里,一个同学发了一道题目给我看,这道题目应该是C语言面试的一股清流了,各种招聘笔试上都可以看到,我试着发到我的大群里去,发现有人对这个理解不是很深刻,所以再发出来,知识总是在不断的碰撞中提高的,同理,球技也是一样。
大家可以先猜测一下这两个程序的输出是什么?
什么是指针?
书籍看得比较多了,这个指针那个指针,但是我认为如果说到指针,不说变量,就有点耍流氓,所以我认为理解指针的基础就要理解它是一个变量,所以指针,可以理解为指针变量,再延伸出来,就是地址变量,可以存地址的一个变量,而且存的这个地址指向的类型也是有要求的。
#include "stdio.h" int main()
{ int i = 12; int *p = &i; printf("%d\n",sizeof(int *)); printf("%d\n",sizeof(p)); printf("%p\n",&p);
}
看上面的代码,p是一个指针变量,p存的是一个地址,p存的这个地址存的类型是 int 类型。有点拗口,我们画个图。
上图中 我们定义了一个变量 p ,所以编译器就必须要给这个p分配内存,如上图所示,这个p的内存是 0x1000,p是什么类型呢?从定义可以看,p的类型是 int *,所以说p只可以存 int * 类型的值,也就是一级指针,就是一级地址,也就是 i 的地址。
i 也是一个变量,这个变量的地址是 0x1001, 这个地址上存的值是 12。
地址本来是没有名字的,因为定义了变量,所以地址就对应有了一个别名,这个名字就代表了这个内存地址。
弱弱问一句,声明有没有分配内存呢?
什么是数组?
我觉得指针和数组是不用比较的,我们比较的是指针变量和数组名,这两个东西才有比较的意义,数组是一类数据的集合,指针变量只能是一个地址变量,没必要折腾自己的大脑了。
#include "stdio.h" int main()
{ int array[5] = {1,2,3,4,5}; return (0);
}
我们定义了一个 array的数组,这个数组是个什么鬼东西,我们知道,内存可以起一个别名,数组是连续几个同类型内存块的别名。
好了,我们再说下一个问题 ,array 是数组的名字,&array 获取的是这个数组的地址,而且这个地址的值等于 &array[0] 「首元素的地址」。
虽然数值相等,但是他们的含义是不一样的。
如果 &array +1 这个时候,地址偏移的是 &array + sizeof(array)
如果 &array[0] +1 这个地址偏移是 &array[0] + sizeof(array[0]) ,也就是偏移到地址 &array[1]上。
再看看上面的两个题目
我们再看看上面的题目
int *p = (int*)(&a +1);
这句代码执行后,p的值应该是 &a +sizeof(a)了。
但是下面这句代码就不一样了。
#include "stdio.h" int main()
{ int a[5] = {1,2,3,4,5}; int *p = &a; int *q = a; printf("%d %d\n",*(q+1),*(p+1)); return (0);
}
&a 赋值给 p 后,这个意义就不一样了,这时候,它的类型是 int* ,p+1 就是 p + sizeof(int *) 。只能偏移到数组的下一个位置。
所以这样说之后,大家都知道上面的输出结果了吗?
2,5
2,2
扫码或长按关注
回复「 加群 」进入技术群聊