复习一下对数组名的理解
数组名的理解
数组名是数组首元素的地址
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
一维数组
int a[] = { 1,2,3,4 }; printf("%d\n", sizeof(a)); printf("%d\n", sizeof(a + 0)); printf("%d\n", sizeof(*a)); printf("%d\n", sizeof(a + 1)); printf("%d\n", sizeof(a[1])); printf("%d\n", sizeof(&a)); printf("%d\n", sizeof(*&a)); printf("%d\n", sizeof(&a + 1)); printf("%d\n", sizeof(&a[0])); printf("%d\n", sizeof(&a[0] + 1));
在32位下的结果是4 4 4/8
讲解:
printf("%d\n", sizeof(a));
sizeof(数组名),数组名单独放在sizeof中,所以计算的是整个数组的大小,4*4=16。
printf("%d\n", sizeof(a + 0));
a是数组名是首元素地址,a+0(不是单独放在sizeof中)还是首元素地址,地址的大小是4/8。
printf("%d\n", sizeof(*a));
数组名a是数组首元素的地址,*a就是首元素,大小就是4个字节
printf("%d\n",sizeof(a + 1));
数组名a是数组首元素的地址,a+1是第二个元素的地址,地址的大小4/8
printf("%d\n".sizeof(a[1]));
第二个元素的大小就是4个字节(int类型大小)
printf("%d\n", sizeof(&a));
&a是数组的地址,数组的地址也是地址,是地址4/8个字节
printf("%d\n", sizeof(*&a));
计算整个数组的大小所以是16个字节。
sizeof(*&a)-->sizeof(a)两者等价
printf("%d\n", sizeof(&a + 1));
&a+1相当于&a是跳过整个数组,但是即使是跳过整个数组,&a+1依然是地址,是地址就是4/8个字节
printf("%d\n",sizeof(&a[0]));
在C语言中,
[]
(数组下标运算符)的优先级高于&
(取地址运算符)。所以是先a[0]就是第一个元素,之后&,得到第一个元素的地址就是4/8.也就是第一个元素的地址。printf("%d\n", sizeof(&a[0] + 1));
&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,大小4。
字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
(32位下)【答案】:6 4 1 1 4 4 4
【解析】
printf("%d\n", sizeof(arr));
数组名arr单独放在sizeof内部,计算的是整个数组的大小6。
printf("%d\n", sizeof(arr + 0));
arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));
arr表示数组首元素的地址,*arr就是首元素,大小1个字节
printf("%d\n", sizeof(arr[1]));
arr[1]就是第二个元素,大小是1个字节
printf("%d\n", sizeof(&arr));
&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8
printf("%d\n", sizeof(&arr + 1));
&arr+1 是跳过数组后的地址, 是地址就是4。
printf("%d\n", sizeof(&arr[0] + 1));
第二个元素的地址,是地址就是4。
看看strlen的结果,注意strlen统计的是\0之前的字符个数,现在这个数组中是没有\0的
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
【答案】32位环境下运行的结果
1、随机值
2、随机值
3、err
4、err
5、随机值
6、随机值-6
7、随机值-1
【解析】
printf("%d\n", strlen(arr));
因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值
printf("%d\n", strlen(arr + 0));
arr + 0是首元素的地址,和第一个一样,也是随机值。strlen函数是接收一个地址然后往后面找\0。也是随机值
printf("%d\n", strlen(*arr));
arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97
strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参
strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
printf("%d\n", strlen(arr[1]));
同上
printf("%d\n", strlen(&arr + 1));
&arr表示整个数组的地址,&arr + 1表示跳过整个数组(6个字节)向后查找\0,因此是随机值
printf("%d\n", strlen(&arr[0] + 1));
第二个函数的地址。也是随机值。 &arr[0]表示首元素地址,&arr[0] + 1跳过一个元素,向后查找\0,因此是随机值
下面换成char arr[] = "abcdef";再来看看也就是末尾有\0了
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
【答案】32位环境下运行的结果
7
4
1
1
4
4
4
1、6
2、6
3、err
4、err
5、6
6、随机值
7、5
【解析】
printf("%d\n", sizeof(arr));
sizeof(数组名)表示整个数组,sizeof是会把\0也计入在内的,因此是7。
printf("%d\n", sizeof(arr + 0));
arr+0表示首元素地址,是地址就是4/8
printf("%d\n", sizeof(*arr));
*arr表示首元素,首元素是char类型,所以就是1。
printf("%d\n", sizeof(arr[1]));
第二个元素,所以就是1。
printf("%d\n", sizeof(&arr));
&arr表示整个数组的地址, 是地址就是4/8
printf("%d\n", sizeof(&arr + 1));
&arr表示整个数组的地址, &arr + 1表示跳过整个数组,是地址就是4。
printf("%d\n", strlen(arr));
统计\0前有多少个元素,就是6。
printf("%d\n", strlen(arr + 0));
arr+0等于首元素地址,统计\0前有多少个元素,就是6。
printf("%d\n", strlen(*arr));
*arr表示首元素,把元素作为地址直接进行访问,就是非法访问,因此程序会报错。
printf("%d\n", strlen(arr[1]));
同上
printf("%d\n", strlen(&arr));
&arr是数组的地址这里其实数值和首元素地址一样,所以是6
printf("%d\n", strlen(&arr + 1));
跳过这个数组向后找|0,随机值。
printf("%d\n", strlen(&arr[0] + 1));
&arr[0] + 1 表示第二个元素的地址,向后找\0等于5。
char* p = "abcdef";
// 012345
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
【答案】
6
5
err
err
随机值
随机值
5
【解析】
printf("%d\n", strlen(p));//6
前面说了strlen接收的是指针,p就是这个字符串的指针也就是首元素的地址。所以是6
printf("%d\n", strlen(p + 1));
p+1是第二个元素的地址,向后找\0所以是5
printf("%d\n", strlen(*p))
*p是这个字符串,非法访问。
printf("%d\n", strlen(p[0]))
同理,这也是非法访问,p[0]是第一个元素。strlen要的是一个指针(地址)
printf("%d\n", strlen(&p));//随机值
这是这个指针的地址。
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//5
第二个元素开始向后找\0所以是5
char* p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
//&p -- char**
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
【答案】
4
4
1
1
4
4
4
解析
printf("%d\n", sizeof(p));
p是一个指针变量大小就是4/8
printf("%d\n", sizeof(p + 1));
p+1是'b'的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(*p));
*p 就是'a',就是1个字节
printf("%d\n", sizeof(p[0]));
p[0]--> *(p+0) --> *p 1个字节
printf("%d\n", sizeof(&p));//4/8
&p 的类型是 char**是二级指针,是指针就是4/8
printf("%d\n", sizeof(&p + 1));
&p + 1
表示指向&p
之后位置的指针。如果指针p
在内存中占用4个字节,那么&p + 1
将指向p
之后的4个字节。是地址就是4/8
printf("%d\n", sizeof(&p[0] + 1));//4/8
&p[0] + 1得到是'b'的地址.是地址就是4/8
二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
【答案】
48
4
16
4
4
4
16
4
16
16
16
【解析】
printf("%d\n", sizeof(a));//3*4*4 = 48
计算整个数组的大小是3*4个元素,每个元素是4字节所以是48字节
printf("%d\n", sizeof(a[0][0]));//4
第一个元素
printf("%d\n", sizeof(a[0]));//a[0]是第一行这个一维数组的数组名
a[0]是第一行这个一位数组的数组名。数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
printf("%d\n", sizeof(a[0] + 1));
a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&
a[0]表示数组首元素的地址,也就是a[0][0]的地址
所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));//4
计算的是就是第一行第2个元素的大小。
注意这个printf("%d\n", sizeof(a + 1));//4 / 8
a是数组首元素的地址,是第一行的地址 类型就是int(*)[4]。a+1 就是第二行的地址
加减整数的操作移动多少是看自己的类型的,第一行的地址的类型是int(*)[4]是数组指针
printf("%d\n", sizeof(*(a + 1)));//16
a+1就是第二行的地址,*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小
a+1 --> 是第二行的地址,int(*)[4]
*(a+1) 访问的第二行的数组
printf("%d\n", sizeof(&a[0] + 1));//4/8
&a[0]是第一行的地址,加一之后就是第二行的地址
&a[0]是第一行的地址 int(*)[4]
&a[0]+1 是第二行的地址 int(*)[4]
printf("%d\n", sizeof(*(&a[0] + 1)));//16 计算的是第二行的大小
看了上一个就知道这里相当数是把第二行的数组名直接放在sizeof
里面所以是第二行的大小16
printf("%d\n", sizeof(*a));//计算的是第一行的大小-16
a,int[*][4],解引用之后就是第一行这个一维数组
a是数组首元素的地址,就是第一行的地址
*a 就是第一行
*a --> *(a+0) --> a[0]
printf("%d\n", sizeof(a[3]));//16
a[3]--> int [4]