? ? ? 以下内容含金~
? ? ? ?带你掌握数组名与地址的各种关系,克服畏惧数组的心理?!??
目录
一维数组
解析
字符数组
解析
二维数组
解析
一维数组
? ? ? ? 你能做出几道?证明一下自己的实力?
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));
解析
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
数组名一定是首元素地址吗?
提示一点,只有以下两种情况出现数组名才表示整个数组,其他情况一律表示首元素地址
1.sizeof(数组名);
2.&数组名;
所以这里表示整个数组,因而求的是整个数组的大小,也就是4个整形的大小,答案是16
printf("%d\n",sizeof(a+0));
注意这里,sizeof()内部数组名没有单独出现,故这里表示首元素的地址,地址的大小是多少呢?
答案是4/8(32位平台/64位平台)
printf("%d\n",sizeof(*a));
首元素地址解引用也就是首元素,是一个整形,所以
答案是4
printf("%d\n",sizeof(a+1));
首元素地址+1 = 下一个地址 因为数组中地址是连续的,故指向下一个元素的地址
但他的本质依然是地址哩~ 所以
答案是4/8
printf("%d\n",sizeof(a[1]));
a[1] == *(a + 1);也就是数组的第二个元素,所以
答案是4
printf("%d\n",sizeof(&a));
注意,这里是取出整个数组的地址,但他终究还是是地址阿~ 所以
答案是4/8
printf("%d\n",sizeof(*&a));
打开你的思维
两种理解方式:
1.取出整个数组的地址,再解引用,相当于找到了整个数组,也就是计算整个数组的大小
2.*与&抵消,相当单独将数组名放入sizeof内部
答案是16
printf("%d\n",sizeof(&a+1));
取出整个数组的地址,+1跳过整个数组,但依然是地址,所以
答案是4/8
printf("%d\n",sizeof(&a[0]));
打开你的思维
两种理解方式:
1.a[0]是数组的第一个元素,取出他的地址
2.&a[0] == &*(a + 0); 这里&*抵消,剩下a + 0,也就是首元素的地址
答案是4/8
printf("%d\n",sizeof(&a[0]+1));
取出数组第一个元素的地址,+1跳过一个元素的地址,指向数组第二个元素的地址,终究还是地址~
答案是4/8
值得注意的是
printf("%d\n",sizeof(&a+1));
跳过整个数组指的是 由
?到+1后的操作
?
字符数组
????????你能做出几道?证明一下自己的实力?
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));
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));
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));
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));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
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));
解析
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
数组名单独放在sizeof内部,求的是整个数组的大小 所以
答案是6
printf("%d\n", sizeof(arr+0));
数组名没有单独放在sizeof内部,表示首元素地址,首元素地址+0还是首元素地址 所以
答案是4/8
printf("%d\n", sizeof(*arr));
首元素地址解引用,得到首元素,是一个字符'a' 所以
答案是1
printf("%d\n", sizeof(arr[1]));
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
------------------------以下是strlen------------------------------
printf("%d\n", strlen(arr));
将首元素的地址给strlen求字符串长度,到'\0'停止
但是数组中真的有放'\0'吗?
实际上,数组里只存放了abcdef这六个字符
所以strlen会一直找啊找,找啊找,直到找到内存中随机初始化的\0截至
答案是 随机数
printf("%d\n", strlen(arr+0));
首元素地址+0还是首元素地址,数组中没有'\0' 所以
答案是 随机数
printf("%d\n", strlen(*arr));
将首元素放进strlen这算什么呀?
什么都不算,这时一种错误的写法
为什么呢?看一下strlen函数的要求:
size_t strlen( const char *string );
他需要的是一个const的指针
想象一下,将字符'a'强行塞入,经ASCII转换后是97,访问的是97处的地址啊
这是一个位置极低的地址,已经造成了非法访问,如果你有兴趣,编译这段代码
程序走到这里就会挂掉
答案是 error
printf("%d\n", strlen(arr[1]));
这个也是同样的道理,只不过是第二个元素
答案是 error
printf("%d\n", strlen(&arr));
取出整个数组的地址,这可怎么办呢?
大家是否还记得取出首元素的地址和取出整个数组的地址是一样的,因为就算你要一次访问
整个数组,起始位置也一定是首元素地址不是吗?
但闹了半天,却因数组里没有'\0' 所以
答案是 随机数
printf("%d\n", strlen(&arr+1));
取出整个数组的地址,+1跳过整个数组,但内存中未初始化的位置内容都是随机的 所以
答案是 随机数-6
printf("%d\n", strlen(&arr[0]+1));
取出首元素的地址,+1指向第二个元素 所以
答案是 随机数-1
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
这里arr单独出现在sizeof内部,表示计算整个数组的大小,但要注意哦
这里的字符串里隐藏了一个'\0' 所以
答案是7
printf("%d\n", sizeof(arr+0));
arr没有单独出现在sizeof内部,表示首元素地址 所以
答案是4/8
printf("%d\n", sizeof(*arr));
首元素地址解引用得到数组第一个元素,是字符'a' 所以
答案是1
printf("%d\n", sizeof(arr[1]));
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
--------------------以下是strlen----------------------------
printf("%d\n", strlen(arr));
strlen读到'\0'停止,这里arr表示首元素的地址,表示从首元素开始读取 所以
答案是6
printf("%d\n", strlen(arr+0));
首元素地址+0还是首元素地址 所以
答案是6
printf("%d\n", strlen(*arr));
首元素地址解引用放入strlen,上面的题解释过,造成了非法访问,这是一种错误写法,所以
答案是error
printf("%d\n", strlen(arr[1]));
arr[1]是首元素和上一题同理 所以
答案是error
printf("%d\n", strlen(&arr));
取出整个数组的地址,整个数组的地址也是从首元素地址开始访问 所以
答案是6
printf("%d\n", strlen(&arr+1));
取出整个数组的地址,+1跳过整个数组,相当与也跳过了数组结尾的'\0' 所以
答案是 随机数
printf("%d\n", strlen(&arr[0]+1));
取出首元素的地址,+1指向数组第二个元素 所以
答案是5
char *p = "abcdef";
printf("%d\n", sizeof(p));
char*类型的p能存放的了这个字符串吗?
当然不行(具体在指针进阶文章里有讲)
这里存放的首元素a的地址 所以
答案是4/8
printf("%d\n", sizeof(p+1));
p是首元素的地址,首元素地址+1指向下一个元素的地址,但还是地址~ 所以
答案是4/8
printf("%d\n", sizeof(*p));
首元素地址解引用找到字符'a' 所以
答案是1
printf("%d\n", sizeof(p[0]));
p[0] == *(p + 0);表示第一个元素 所以
答案是1
printf("%d\n", sizeof(&p));
p表示首元素地址,&p表示取出首元素地址的地址,相当于一个二级指针,但还是地址~ 所以
答案是4/8
printf("%d\n", sizeof(&p+1));
取出首元素地址的地址,+1跳过p这块空间的地址(此处一会画图解释),但还是地址~ 所以
答案是4/8
printf("%d\n", sizeof(&p[0]+1));
取出首元素的地址,+1跳过第一个元素的地址,指向第二个元素地址,但还是地址~ 所以
答案是4/8
---------------------------以下是strlen-----------------------------------
printf("%d\n", strlen(p));
p是首元素地址,strlen计算字符串长度到'\0'停止 所以
答案是6
printf("%d\n", strlen(p+1));
首元素地址+1,指向下一个元素的地址 所以
答案是5
printf("%d\n", strlen(*p));
首元素地址解引用,得到的是首元素,是一个字符'a',和之前的一道题一样,非法访问内存空间 所以
答案是error
printf("%d\n", strlen(p[0]));
和上一题同理 所以
答案是error
printf("%d\n", strlen(&p));
p表示首元素地址,&p表示取出首元素地址的地址,但后面内容是随机初始化(一会画图解释) 所以
答案是 随机值
printf("%d\n", strlen(&p+1));
和上一道题同理,&p+1只是跳过了这个p的地址,后面内容随机初始化 所以
答案是 随机数
printf("%d\n", strlen(&p[0]+1));
取出首元素的地址,+1指向第二个元素的地址,所以
答案是5
对于
printf("%d\n", sizeof(&p+1));
printf("%d\n", strlen(&p+1))
p这个指针变量与"abcdef"的存储位置是不一样的
p是一个局部变量,在栈区上开辟空间,而常量字符串"abcdef"是在静态区开辟的空间
如图:
?+1跳过的是什么呢
如图
?想必这时大家心里因该很清楚啦。
二维数组
????????你能做出几道?证明一下自己的实力?
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]));
解析
int a[3][4] = {0};
printf("%d\n",sizeof(a));
数组名单独放在sizeof内部,表示计算整个数组大小,也就是12个整形大小 所以
答案是48
printf("%d\n",sizeof(a[0][0]));
a[0][0] == *(*(a + 0) + 0); 就是第一行第一个元素 所以
答案是4
printf("%d\n",sizeof(a[0]));
a[0] == *(a + 0);这里a表示数组第一行的地址,+0还是第一行,解引用相当于拿到
第一行的数组名,将第一行的数组名单独放入sizeof内部,相当于计算第一行的大小,
(这里这一类比一维数组) 所以
答案是4
printf("%d\n",sizeof(a[0]+1));
与上一道题同理,a[0]拿到第一行的数组名,数组名没有单独放在sizeof内部表示
第一行的首元素地址,第一行首元素的地址+1,指向第一行第二个元素的地址,但还是地址 所以
答案是4/8
printf("%d\n",sizeof(*(a[0]+1)));
与上一道题同理a[0]+1表示第一行第二个元素的地址,解引用相当于找到了第一行第二个元素,是个整形
答案是4
printf("%d\n",sizeof(a+1));
a表示首元素地址,+1跳过第一行的地址,指向第二行的地址,但还是地址~
答案是4/8
printf("%d\n",sizeof(*(a+1)));
与上一题同理,a+1表示第二行地址,第二行的地址解引用相当于找到了第二行的数组名,第二行
数组名单独放入sizeof内部表示计算第二行的数组大小 所以
答案是16
printf("%d\n",sizeof(&a[0]+1));
a[0]表示一行的数组名,&a[0]表示取出第一行数组名的地址,+1指向第二行的数组名的地址 所以
答案是4/8
printf("%d\n",sizeof(*(&a[0]+1)));
与上一题同理,&a[0]+1表示第二行的地址,解引用相当于找到了第二行的数组名,数组名单独放入sizeof
内部,表示计算第二行的大小
答案是16
printf("%d\n",sizeof(*a));
a没有单独放入sizeof内部表示第一行的地址,第一行的地址解引用拿到第一行的数组名,第一行的
数组名单独放入sizeof计算数组第一行的大小 所以
答案是16
printf("%d\n",sizeof(a[3]));
这道题很有意思
可能有的就要说了,这一看就是错的呀,越界访问了~
但其实你可能忘了一点
sizeof只关心的是类型,而非内容
你是否有见过这种写法sizeof(int)
起始就是在计算int的大小,包括平时写int a = 5; sizeof(a);
这也是在计算a这个类型的大小
这道题a[3]就是拿到第四行的数组名,数组名单独放入sizeof内部表示计算数组第四行的大小 所以
答案是16
? ? ? ?
不断揭示数组名的意义和本质:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
码字不易~
|