在C语言编程学习过程中,不少老铁会特别头大这个数组和指针之间的关系。例如arr[],这个arr一会又是代表数组首元素地址,一会又是代表数组地址,甚至有的老铁还会疑惑,啥是数组地址呀!??那么这篇文章将会带你彻底搞懂这二者之间的关系。
1.数组地址和数组首元素地址
首先,我们介绍一下什么叫做数组地址。从名词上直接理解就是,这个数组的地址,但不禁会疑惑,啥叫数组的地址呀?数组储存了同种类型的很多数据,占用了不止一个内存单元,我们怎么可能单一的确定某个地址就是这个数组的地址呢?其实,我们通常说数组地址,从打印结果看,他就是数组首元素的地址,而从实际意义上看它代表的是这个数组的地址。假设p为arr[]数组的地址,那定义代码为:int(*p)[数组元素个数]=&arr。相信大家也注意到了,我在定义*p时右端用&arr,而不是arr,二者的区别是什么呢?其实,&arr就是获取arr[]的地址,而arr则获取arr[]首元素的地址,我们前面讲到过,尽管二者从打印结果上一样,但代表的含义却是不同的。那有什么特殊情况吗?答案是有的,对于操作符sizeof()来说,如果代码为sizeof(arr),此时求的就是arr[]所占内存的大小,所以,此时的arr代表的就是整个数组。而不是求地址所占空间的大小了(注意()内部只能单独出现数组名,不能有其他操作)。所以,总而言之,除了&arr(数组地址),sizeof(arr)(整个数组),外其他时候arr就代表的是数组首元素的地址。
#include <stdio.h>
int main()
{
int arr[] = { 0,1,2,3,4,5 };
int(*p)[6] = &arr;
printf("%p\n", arr);
printf("%p\n", p);
printf("%d", sizeof(arr));
return 0;
}
2.sizeof和strlen()
为了对后面的练习题有更好的理解,我们现在简单的介绍一下sizeof()和strlne()两个函数。
2.1sizeof
sizeof是操作符,作用是求后接数据类型所占空间的大小,如sizeof(int)=4等,所以我们要分清楚括号内的类型,注意是类型,类型,类型!!!
2.2strlen()
strlen()是函数,作用是求字符串的长度:
size_t strlen ( const char * str );
返回类型是size_t,参数为const char* str,即我们要找到参数的地址,根据地址向后找'\0'来判断字符的长度。
3.练习
#include <stdio.h>
#include <string.h>
int main()
{ //使用该代码时一段一段使用,否则编译无法成功
//一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//sizeof(数组名)=整个数组所占空间大小=4*4=16
printf("%d\n", sizeof(a + 0));//注意,此时语句不是特殊情况,因为()内不只有+0,所以就是数组首元素地址的大小=4(32位)/8(64位)
printf("%d\n", sizeof(*a));//对首地址解引用-》a[0],大小为4个字节
printf("%d\n", sizeof(a + 1));//首地址+1还是地址,地址占4/8
printf("%d\n", sizeof(a[1]));//a[1]=2,int类型4字节
printf("%d\n", sizeof(&a));//数组地址还是地址4/8
printf("%d\n", sizeof(*&a));//解引用数组地址就是整个数组,与第一题相同
printf("%d\n", sizeof(&a + 1));//数组地址+1还是地址,4/8
printf("%d\n", sizeof(&a[0]));//依旧是地址
printf("%d\n", sizeof(&a[0] + 1));//还是地址
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//整个数组的大小=6
printf("%d\n", sizeof(arr + 0));//地址大小4/8
printf("%d\n", sizeof(*arr));//首地址解引用1
printf("%d\n", sizeof(arr[1]));//’b'的大小1
printf("%d\n", sizeof(&arr));//数组地址也是地址4/8
printf("%d\n", sizeof(&arr + 1));//数组地址+1也是地址4/8
printf("%d\n", sizeof(&arr[0] + 1));//首地址+1还是地址4/8
printf("%d\n", strlen(arr));//从数组首地址开始向后找‘0’,由于该数组未设置‘0’,故为随机值
printf("%d\n", strlen(arr + 0));//随机值
//printf("%d\n", strlen(*arr));//error,所给参数不是地址
//printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr + 1));//上述随机值-6,数组取地址+1要横跨整个数组所占字节
printf("%d\n", strlen(&arr[0] + 1));//上述随机值-1
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//数组所占字节的大小7*1=7(这种写法会自动在末尾补充’\0‘,所以实际上是有7个元素)
printf("%d\n", sizeof(arr + 0));//地址大小4/8
printf("%d\n", sizeof(*arr));//对首地址解引用,首元素所占空间大小1
printf("%d\n", sizeof(arr[1]));//‘b’所占空间大小1
printf("%d\n", sizeof(&arr));//地址大小4/8
printf("%d\n", sizeof(&arr + 1));//地址大小4/8
printf("%d\n", sizeof(&arr[0] + 1));//地址大小4/8
printf("%d\n", strlen(arr));//从首地址开始向后找’\0'一共找了6次所以是6
printf("%d\n", strlen(arr + 0));//6
printf("%d\n", strlen(*arr));//error参数不是地址
printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//数组地址从表现形式上来看是首元素地址,所以是6
printf("%d\n", strlen(&arr + 1));//随机值,&arr+1,此时会跳过七个字节的地址,后面什么时候遇到'\0'未知
printf("%d\n", strlen(&arr[0] + 1));//6-1=5
char* p = "abcdef";//表示p=&a,也就是说p中储存了a的地址
printf("%d\n", sizeof(p));//p是地址4/8
printf("%d\n", sizeof(p + 1));//p+1是地址4/8
printf("%d\n", sizeof(*p));//*p=a,占1字节
printf("%d\n", sizeof(p[0]));//1
printf("%d\n", sizeof(&p));//地址4/8
printf("%d\n", sizeof(&p + 1));//地址4/8
printf("%d\n", sizeof(&p[0] + 1));//地址4/8
printf("%d\n", strlen(p));//这种书写方式跟数组一样,都会自动补‘\0’,所以是6
printf("%d\n", strlen(p + 1));//5
printf("%d\n", strlen(*p));//error
printf("%d\n", strlen(p[0]));//error
printf("%d\n", strlen(&p));//随机值,char** pp=&p
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//=strlen(p+1) 5
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//3*4*4=48
printf("%d\n", sizeof(a[0][0]));//4
printf("%d\n", sizeof(a[0]));//此时表示为二维数组的第一行所有元素的大小4*4=16
printf("%d\n", sizeof(a[0] + 1));//地址4/8
printf("%d\n", sizeof(*(a[0] + 1)));//=a[1][0]因为对a[1]解引用可以看作对数组名解引用,那么就是首元素 4
printf("%d\n", sizeof(a + 1));//地址4/8
printf("%d\n", sizeof(*(a + 1)));//a[1] 16
printf("%d\n", sizeof(&a[0] + 1));//地址4/8
printf("%d\n", sizeof(*(&a[0] + 1)));//a[1] 16
printf("%d\n", sizeof(*a));//二维数组的首元素为a[0](第一行) 4*4=16
printf("%d\n", sizeof(a[3]));//即使越界了,但sizeof()只看类型,所以还是16
return 0;
}