C语言&的一些思考
1. C语言里&的一般作用
C语言里有了指针的概念后,当我们需要为指针赋值时,常用的有以下两种方式
void main(){ // 方法一 char a = 'A'; char* p = &a; // 方法二 char* q = (char*)malloc(sizeof(char)); }
总而言之,&可以放在一个变量前面,以取得这个变量对应的内存地址。
2. &放在指针前面
现在来考虑一下下列的两种情况
void main(){ // 情况一,考虑p1, p2, p3, arr, &arr, arr + 1的关系 int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int* p1 = arr; int* p2 = arr + 1; int* p3 = &arr; // 情况二,考虑&number, q, &q, p5, p4的关系 int number = 10; int* q = &number; int* p5 = &q; int** p4 = &q; }
实际上这两种情况是:
对数组指针取&
对int指针取&
首先,我们知道arr是长度为10的整数数组的起始地址,所以有*arr == arr[0]; *(arr + n) = a[n]
。所以对于情况一,p1 == arr;p2 == p1 + 1(因为是整数指针,指针加一内存地址加4)
。上面这几点只是想点出下面的问题,究竟p3、&arr、arr有着什么关系。当我们用C语言开发工具去运行这段代码打印指针的值,会发现这三者相等,意思是他们指向的都是同一个地址。为什么呢?arr是一个指针,我对一个指针使用&他应该会获取这个指针的指针啊。这里需要注意的是,当&操作的对象是一个非数组类型的指针时,我们如愿以偿获取到了这个指针的指针。但是当我们对数组指针使用&,我们实际上是获取的这个数组的指针,上述的情况是我们获取到了arr这个数组对象的指针,那么这个数组对象的指针就是arr的值。所以,p3 == arr == &arr
。不止如此,我们通过&arr获取到的指针的步长是这个数组的元素类型的步长 * 数组长度
。而arr这个指针的步长只是元素类型的步长
。如下所示void main(){ int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int* p1 = arr; int* p2 = &arr; printf("&arr + 1 is %p", (&arr + 1)); // 内存地址:arr + 4(整数的步长为4) * 10(数组的长度为10) printf("arr + 1 is %p", (arr + 1)); // 内存地址: arr + 4(整数的步长为4) // 综上,(&arr + 1) - (arr + 1) == 36 // 此处的第一反应(p2 + 1) == (&arr + 1)。但是注意我们在赋值给p2的时候,指定了p2的类型为整数指针,所以实际上内存地址:p2 + 1(整数指针) == arr + 4 printf("p2 + 1 is %p", (p2 + 1)); }
再来考虑情况二,我们此时不再对数组指针取&,所以p5, p4, &q, q是什么关系呢?实际上,&q此时不在像情况一那样等于q,它返回的是q这个指针的指针。所以p5 == p4。他们都取到了q这个指针的指针。但是,问题又来了,p5是整数指针的指针,p4只是一个整数指针。所以会带来步长的不一致,p5的步长是一个指针的步长,p4的步长是一个整数的步长。指针的步长是4或者8,这个看系统环境而定。
3. 总结
C语言中&的作用是返回一个地址(指针)。但是具体是返回什么样的值、值等于多少还是&操作的对象有所去别的。
- 对数组指针取&,返回的是数组的首地址,即&arr == arr,只不过指针的步长不一样
- 对非指针变量取&,返回这个变量的地址
- 对非数组类型的指针取&,返回这个指针的指针