说明
X64环境下,8个字节
X86环境下,4个字节
小编在运行代码,数据是在VS 2019 X86环境下打印的。
🚩数组笔试题
💻一维数组
📄练习:
code:
#include<stdio.h> int main() { int a[] = { 1,2,3,4 }; printf("%zd\n", sizeof(a)); printf("%zd\n", sizeof(a + 0)); printf("%zd\n", sizeof(*a)); printf("%zd\n", sizeof(a + 1)); printf("%zd\n", sizeof(a[1])); printf("%zd\n", sizeof(&a)); printf("%zd\n", sizeof(*&a)); printf("%zd\n", sizeof(&a + 1)); printf("%zd\n", sizeof(&a[0])); printf("%zd\n", sizeof(&a[0] + 1)); return 0; }
运行结果:
16 4 4 4 4 4 16 4 4 4
💡解析
printf("%zd\n", sizeof(a)); //16
➿➿数组名的理解:
数组名是数组首元素的地址
但是有2个例外:
- sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
- &数组名,数组名表示整个数组,取出的是数组的地址
⭕所以在此代码中,有四个整型,一个整型占4个字节,故总共占16个字节。
printf("%zd\n", sizeof(a + 0)); //4
数组名a没有单独放在sizeof()中,也没有进行单独取地址&,因此,(a+0)不是数组名,这里的a是数组首元素地址,加上0,相当于没有加
a+0<======>&a[ 0 ]
⭕故,是地址大小,4或者8个字节(X64环境下和X86环境下不一样)
printf("%zd\n", sizeof(*a)); //4
这里没有将单独的一个a放进sizeof()中,也没有取地址&,那么a就是除那两种情况之外,即a就是数组首元素地址,a==>&a[ 0 ]
⭕故,*a 其实就是第一个元素,也就是a[ 0 ] 的大小:4个字节
printf("%zd\n", sizeof(a + 1)); //4
和上面(a+0)一样,a是首元素地址
(a+0)–>&a[ 0 ]
(a+1)–>&a[ 1 ]
⭕故,(a+1)就是第2个元素的地址,大小是4或者8个字节
printf("%zd\n", sizeof(a[1])); //4
a[1]就是这个数组的第二个元素
⭕故,大小是4个字节
printf("%zd\n", sizeof(&a));
&a➡️取出的是数组的地址,但是数组的地址也是一个地址呀😏,数组的地址可没有高人一等。是地址大小就是4或者8个字节
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(*&a)); //16
两种解读方式:
1️⃣抵消:
·这里取地址,然后再解引用,抵消掉了,相当于就是a
2️⃣数组指针类型:
· &a类型是一个数组指针,&a<==>int(*p)[ 4 ]
· 我们知道,指针在进行加一或者解引用的时候,跳过多少个字节是取决于指针类型:
*p访问一个数组的大小
p+1是跳过一个数组的大小
·
那么现在p指向一个大小为4,类型为整型的一个数组
取出整个数组的地址,再进行解引用,访问的就是整个数组
因此:
printf("%zd\n", sizeof(*&a)); <==> printf("%zd\n", sizeof(a));
⭕故,大小是16个字节
printf("%zd\n", sizeof(&a + 1)); //4
&a+1是跳过整个数组后的地址,是地址大小就是4或者8个字节。
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(&a[0])); //4
没什么好说的,就是首元素地址🤨,是地址大小就是4或者8个字节。
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(&a[0] + 1)); //4
&a[0] + 1表示第二个元素的地址(&a[ 1 ])
⭕故,大小是4或者8个字节
💻字符数组
📄练习1:
code:
#include<stdio.h> int main() { 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)); return 0; }
运行结果:
6 4 1 1 4 4 4
💡解析
printf("%d\n", sizeof(arr)); //6
arr表示整个数组,计算的是整个数组的大小
此数组有6个字符,一个字符1个字节
⭕故,一共有6个字节
printf("%d\n", sizeof(arr + 0)); //4
arr是数组首元素的地址,arr+0还是首元素的地址
⭕故,是地址,大小就是4或者8个字节
printf("%d\n", sizeof(*arr)); //1
arr就是首元素地址,*arr解引用,就是首元素,就站一个字符,即1个字节
⭕故,大小就是1个字节
printf("%d\n", sizeof(arr[1])); //1
arr[ 1 ]表示数组第2个元素,即占一个字节
⭕故,大小就是1个字节
printf("%d\n", sizeof(&arr)); //4
&arr是数组的地址,数组的地址也是地址
⭕故,是地址,大小就是4或者8个字节
printf("%d\n", sizeof(&arr + 1));
&arr+1跳过整个数组,指向的是f后面,
⭕故,是地址,大小就是4或者8个字节
printf("%d\n", sizeof(&arr[0] + 1)); //4
&arr[0]是首元素地址,+1后变成第二个元素地址
⭕故,是地址,大小就是4或者8个字节
📄练习2:
code:
#include<stdio.h> #include<string.h> int main() { char arr[] = { 'a','b','c','d','e','f' }; printf("%zd\n", strlen(arr)); printf("%zd\n", strlen(arr + 0)); printf("%zd\n", strlen(*arr)); printf("%zd\n", strlen(arr[1])); printf("%zd\n", strlen(&arr)); printf("%zd\n", strlen(&arr + 1)); printf("%zd\n", strlen(&arr[0] + 1)); return 0; }
💡解析
printf("%zd\n", strlen(arr)); //随机值
数组中没有明确给出\0
⭕故,计算出的结果是随机值
printf("%zd\n", strlen(arr + 0)); //随机值
arr+0:首元素地址+0,和没加一样,依然表示arr,数组中也是没有明确给出\0
⭕故,计算出的结果是随机值
printf("%zd\n", strlen(*arr)); //非法访问-err
strlen()函数参数是指针类型
size_t strlen ( const char * str );
而*arr得到是首元素‘a’
这样就意味着将’a’(97)传递给strlen,将97当作地址传递给strlen
⭕故,形成非法访问
printf("%zd\n", strlen(arr[1])); //非法访问-err
arr[1]表示数组第二个元素,‘b’(98)
将98当作地址传递给strlen,依然是非法访问,和上面一样
⭕故,形成非法访问
printf("%zd\n", strlen(&arr)); //随机值
&arr是一个字符数组指针类型–>char (*p)[ 6 ]
对于strlen依然是找到首元素地址,往后读取,但是没有\0
⭕故,计算出的结果是随机值
printf("%zd\n", strlen(&arr + 1)); //随机值
加一后,跳过整个数组
跳过一个数组后再去往后找,不知道找什么
和上面的随机值是不一样的
差6个字节
⭕故,计算出的结果是随机值
printf("%zd\n", strlen(&arr[0] + 1)); //随机值
&arr[0] + 1表示数组第二个元素,即’b’,从‘b’开始往后数,没有明确给出\0
⭕故,计算出的结果是随机值
📄练习3:
code:
#include<stdio.h> int main() { char arr[] = "abcdef"; //[ a b c d e f \0 ] printf("%zd\n", sizeof(arr)); printf("%zd\n", sizeof(arr + 0)); printf("%zd\n", sizeof(*arr)); printf("%zd\n", sizeof(arr[1])); printf("%zd\n", sizeof(&arr)); printf("%zd\n", sizeof(&arr + 1)); printf("%zd\n", sizeof(&arr[0] + 1)); return 0; }
运行结果:
7 4 1 1 4 4 4
💡解析
printf("%zd\n", sizeof(arr)); //7
不管有没有\0,只管占了多少字节
有7个元素
⭕故,占7个字节
printf("%zd\n", sizeof(arr + 0)); //4
arr表示首元素地址,即arr+0也表示数组首元素地址,是地址,大小就是4或者8个字节
⭕故,占4或者8个字节
printf("%zd\n", sizeof(*arr)); //1
arr表示首元素地址,*arr就是首元素,大小就是1个字节
⭕故,占1个字节
printf("%zd\n", sizeof(arr[1])); //1
arr[1]表示数组第二个元素,大小1个字节
⭕故,占1个字节
printf("%zd\n", sizeof(&arr)); //4
&arr是数组的地址,是地址,大小就是4或者8个字节
⭕故,占4或者8个字节
printf("%zd\n", sizeof(&arr + 1));
&arr是数组地址
&arr+1是跳过整个数组的那个地址
是地址,大小就是4或者8个字节
⭕故,占4或者8个字节
printf("%zd\n", sizeof(&arr[0] + 1)); //4
&arr[0] + 1表示第二个元素地址
是地址,大小就是4或者8个字节
⭕故,占4或者8个字节
📄练习4:
code:
#include<stdio.h> #include <string.h> int main() { char arr[] = "abcdef"; printf("%zd\n", strlen(arr)); printf("%zd\n", strlen(arr + 0)); //printf("%lld\n", strlen(*arr)); //printf("%lld\n", strlen(arr[1])); printf("%zd\n", strlen(&arr)); printf("%zd\n", strlen(&arr + 1)); printf("%zd\n", strlen(&arr[0] + 1)); return 0; }
运行结果:
6 6 6 12 5
💡解析
printf("%zd\n", strlen(arr)); //6
arr是数组首元素地址,顺着往后读取,读到\0结束
strlen统计的是\0之前的字符串个数
⭕故,计算结果是6
printf("%zd\n", strlen(arr + 0)); //6
arr是数组名,首元素地址
arr+0 还是首元素地址,顺着往后读取,读到\0结束
⭕故,计算结果是6
//printf("%lld\n", strlen(*arr)); //err - 非法访问
*arr表示’a’(97)
将97当作地址传递给strlen
非法访问
⭕故,非法访问
//printf("%lld\n", strlen(arr[1])); //err - 非法访问
arr[1]表示数组第二个元素,即‘b’(98)
将987当作地址传递给strlen
非法访问
⭕故,非法访问
printf("%zd\n", strlen(&arr)); //6
&arr取的是整个数组的地址
但这个地址依然指的是数组的起始位置
传递给strlen后,依然从起始位置往后读取,直到\0停止
⭕故,计算结果是6
printf("%zd\n", strlen(&arr + 1)); //随机值
&arr取的是整个数组的地址
&arr+1跳过整个数组后的地址
从跳过后的地址开始找\0,就是随机值
⭕故,随机值
printf("%zd\n", strlen(&arr[0] + 1)); //5
&arr[0] 表示第一个元素地址
&arr[0] + 1第二个元素地址,即b的地址
从b的地址开始找\0,找到\0后停止
⭕故,计算结果是5
📄练习5:
code:
#include<stdio.h> int main() { char* p = "abcdef"; printf("%zd\n", sizeof(p)); printf("%zd\n", sizeof(p + 1)); printf("%zd\n", sizeof(*p)); printf("%zd\n", sizeof(p[0])); printf("%zd\n", sizeof(&p)); printf("%zd\n", sizeof(&p + 1)); printf("%zd\n", sizeof(&p[0] + 1)); return 0; }
运行结果:
4 4 1 1 4 4 4
💡解析
思路:这里是常量字符串,将常量字符串首字符放在p中。
图示:
printf("%zd\n", sizeof(p));
p是一个指针变量
sizeof(p)求的就是指针变量的大小
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(p + 1)); //4
p放的是‘a’的地址
p+1则放的是’b’的地址
依然是地址
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(*p)); //1
p指向’a’
*p解引用,是首字符
⭕故,大小是1个字节
printf("%zd\n", sizeof(p[0])); //1
两种解读方式:
1️⃣类似数组:
这里,可以把字符串“abcdef”也当作有个数组
p是数组名
那么,p[0]访问的就是‘a’
2️⃣计算:
p[0]===>*(p+0)
⭕故,大小是1个字节
printf("%zd\n", sizeof(&p)); //4
&p是取出p所占的地址
也是个地址
是地址,大小就是4或者8个字节
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(&p + 1));
&p + 1也是地址
跳过p变量的地址,指向的是p后面的地址
是地址,大小就是4或者8个字节
⭕故,大小是4或者8个字节
printf("%zd\n", sizeof(&p[0] + 1));
&p[0]是’a’的地址
&p[0] + 1是“b’的地址
是地址,大小就是4或者8个字节
⭕故,大小是4或者8个字节