C语言——深入理解指针(四)
C语言——深入理解指针(四)
数组名的意义
- sizeof(数组名),且数组名单独放在sizeof内部,则这里的数组名表示整个数组,计算的是整个数组的大小
- &数组名,这里的数组名表示的是整个数组,取出的是整个数组的地址
- 除此之外所有的数组名都表示首元素的地址
sizeof和strlen的比较
1.sizeof是操作符,用于计算变量所占内存大小(不关注内存中存放什么数据),单位是字节
2.strlen是库函数(需要包含头文件<string.h>),求字符串长度。其统计的是从strlen函数的参数str中这个地址开始向后,\0之前字符串中字符的个数。函数原型:
size_t strlen (const char* str)//返回类型注意为size_t
但若没有\0,就可能会存在越界查找,结果就是一个随机数,如下图所示:
3.比较
实例:
(一)一维数组
这里千万要注意前面提到的数组名的意义
#include<stdio.h>
int main()
{int a[] = { 1,2,3,4 };
printf("%zu\n", sizeof(a));//16
//a单独在sizeof里面代表整个数组,即四个元素乘以它们的类型所占字节
printf("%zu\n", sizeof(a+0));//4/8
//a没有单独在里面,所以代表首元素的地址,那么a+0还是首元素的地址,这里计算的是一个地址的大小不同环境有差别
printf("%zu\n", sizeof(*a));//4
//这里a没有单独放在sizeof内,a就是首元素地址,*a就是首元素1
printf("%zu\n", sizeof(a+1));//4/8
//a是首元素的地址,a+1就是第二个元素的地址
printf("%zu\n", sizeof(a[1]));//4
//第二个元素
printf("%zu\n", sizeof(&a));//4/8
//&a取出的是数组的地址,数组的地址也是地址
printf("%zu\n", sizeof(*&a));//16
//&a取出的是数组的地址,它的类型为int(*)[4]
//对于数组指针解引用,访问的则是这个数组
printf("%zu\n", sizeof(&a+1));//4/8
//&a是数组的地址,&a+1是跳过数组后的地址
printf("%zu\n", sizeof(&a[0]));//4/8
//第一个元素的地址
printf("%zu\n", sizeof(&a[0]+1));//4/8
//跳过第一个元素的地址,到达第二个元素的地址
return 0;
}
运行结果:
(二)字符数组
(1)操作符sizeof
#include<stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f'};printf("%zu\n", sizeof(arr));//6,计算整个数组printf("%zu\n", sizeof(arr + 0));//4/8,首元素的地址printf("%zu\n", sizeof(*arr));//1,*arr就是首元素printf("%zu\n", sizeof(arr[1]));//1,第二个元素printf("%zu\n", sizeof(&arr));//4/8,数组的地址printf("%zu\n", sizeof(&arr + 1));//4/8,依旧是地址printf("%zu\n", sizeof(&arr[0] + 1));//4/8,第二个元素的地址return 0;
}
运行结果:
#include<stdio.h>
int main()
{char* p = "abcdef";printf("%zu\n", sizeof(p));//4/8//p是一个指针变量,我们假设地址0x0012ff30printf("%zu\n", sizeof(p + 0));//4/8//p+1就是b的地址printf("%zu\n", sizeof(*p));//1//char*类型指针解引用只能访问一个字符printf("%zu\n", sizeof(p[0]));//1//p[0]->*(p+0)->*p,就是第一个元素printf("%zu\n", sizeof(&p));//4/8//&p是指针变量p的地址,是二级指针printf("%zu\n", sizeof(&p+ 1));//4/8printf("%zu\n", sizeof(&p[0] + 1));//4/8//&p[0]+1就是b的地址return 0;
}
(2)库函数strlen():
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", strlen(arr));//随机值//arr是数组首元素地址,strlen算的是整个数组,由于字符串中找不到\0,所以为随机值printf("%zu\n", strlen(arr + 0));//随机值//(arr+0)也是首元素地址printf("%zu\n", strlen(*arr));//程序崩溃//arr是首元素地址,*arr就是首元素即‘a’——97//这里就会出现非法访问内存printf("%zu\n", strlen(arr[1]));//程序崩溃//同上printf("%zu\n", strlen(&arr));//随机值//整个数组的地址,从数组的起始位置数字符串的长度,但是没有\0printf("%zu\n", strlen(&arr + 1));//随机值//跳过这个数组的地址,向后找\0printf("%zu\n", strlen(&arr[0] + 1));//随机值//从第二个元素的地址,向后找\0return 0;
}
int main()
{char* p = "abcdef";printf("%zu\n", strlen(p));//6//p就是a的地址,直至遇到\0向后数有6个字符printf("%zu\n", strlen(p+1));//5//p+1指向b,向后数直到遇到\0有五个字符printf("%zu\n", strlen(*p));//error//*p就是第一个字符printf("%zu\n", strlen(p[0]));//error//同上printf("%zu\n", strlen(&p));//随机值//p变量在内存中后续的空间内容不确定printf("%zu\n", strlen(&p+1));//随机值//同上printf("%zu\n", strlen(&p[0]+1));//5//&p[0]就是a的地址,&p[0]+1就是b的地址,从b的位置向后数return 0;
}
(三)二维数组
- 这里还是要特别注意:数组名单独放在sizeof内,表示整个数组
- 还要注意的一个点:sizeof在计算变量,数组的大小时,是通过类型来推导的,不会真实去访问内存,举个栗子:
在下图中,括号内s=a+2,其中a和2都是int类型,算出来s=12,但sizeof并不会去计算,而是看s本身是什么类型,short类型占两个字节,所以打印出来的仍是2而不是4;而打印s的值时,也不会因为在sizeof里面的算式而改变。
- 实例
#include<stdio.h>
int main()
{int a[3][4] = { 0 };printf("%zu\n", sizeof(a));//48printf("%zu\n", sizeof(a[0][0]));//4printf("%zu\n", sizeof(a[0]));//16//a[0]是第一行一维数组名,单独放在sizeof内部// 表示第一行这个数组printf("%zu\n", sizeof(a[0]+1));//4/8//a[0]没有单独放在sizeof中// 则a[0]是第一行第一个元素的地址,a[0]+1是第一行第二个元素的地址printf("%zu\n", sizeof(*(a[0] + 1)));//4//*(a[0] + 1)是第一行第二个元素printf("%zu\n", sizeof(a+1));//4/8//a未单独放在sizeof中,表示数组首元素的地址,就是第一行的地址// a+1就是第二行的地址printf("%zu\n", sizeof(*(a+1)));//16//a+1是第二行的地址,解引用就是a[1]这行数组,计算的是整个数组的大小printf("%zu\n", sizeof(&a[0]+1));//4/8//表示第二行的地址printf("%zu\n", sizeof(*( & a[0] + 1)));//16//第二行的地址解引用就是这一行printf("%zu\n", sizeof(*a));//16//a没有单独放在里面,是第一行的地址,解引用就是a[0]printf("%zu\n", sizeof(a[3]));//16//sizeof在计算变量,数组的大小时,是通过类型来推导的,不会真实去访问内存//所以这里不会有越界访问return 0;
}
我们来测试一下运行结果:
本次内容到这里就结束了,谢谢观看,如有不对欢迎在评论区留言指正。
心向往之行必能至!