C语言:详解各操作数组的含义 arr、arr[0]、&arr、&arr+1、&arr[0] + 1、*arr、*(arr+1)等,彻底摆脱被数组指针支配的恐惧!
*和& 可以看做同时抵消,只剩a,那么就是整个数组的大小(&a-->int(*)[4],&a拿到的是数组名的地址,类型是int(*)[4],是一种数组指针,数组指针解引用找到的是数组,*&a-->a)a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址,a表示首元素的地址,二维数组的首元素是它的第一行,a就是第一行的地址,+1跳过一行的数组,表示第二行的地址。&a取出是数组的地址
目录
char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'}
讨论数组名
数组名通常表示的都是数组首元素的地址
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
2. &数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址
sizeof & strlen
- sizeof只关注占用内存空间的大小,不在乎内存中放的是什么,所以\0也算一个字符(只针对字符串)
- strlen是求字符串长度的,关注的是字符串中\0,计算的是\0之前出现的字符的个数(strlen是操作符)
int a[] = {1, 2, 3, 4}
sizeof(a)
sizeof(数组名), 数组名表示整个数组,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(a)); // 16
sizeof(a + 0)
a不是单独放在sizeof内部,也没有取地址,所以a就是数组首元素的地址,指针地址的大小是4/8个字节,当前是64位,即8
printf("%d\n", sizeof(a + 0)); // 8
sizeof(*a)
a代表数组首元素地址,解引用得到第一个int值,int是 4 个字节
printf("%d\n", sizeof(*a)); // 4
sizeof(a + 1)
a代表数组首元素地址,a+1,是第二个元素的地址,sizeof(a+1)就是地址的大小,4/8,当前64位,即8
printf("%d\n", sizeof(a + 1)); // 8
sizeof(a[1])
a[1] ——> *(a+1),也就是第二个int值的大小,同样是 4 个字节
printf("%d\n", sizeof(a[1])); // 4
sizeof(&a)
&a 等同于 a+0,同样是指针地址的大小,即4/8个字节,当前是64位,即8,(如果去掉&,大小就是16)
printf("%d\n", sizeof(&a)); // 8
sizeof(*&a)
*和& 可以看做同时抵消,只剩a,那么就是整个数组的大小(&a-->int(*)[4],&a拿到的是数组名的地址,类型是int(*)[4],是一种数组指针,数组指针解引用找到的是数组,*&a-->a)
printf("%d\n", sizeof(*&a)); // 16
sizeof(&a + 1)
&a取出是数组的地址,&a+1 跳过了整个数组的字节(16)所指向的地址,但同样是指针的大小,即4/8个字节,当前是64位,即8
printf("%d\n", sizeof(&a + 1)); // 8
sizeof(&a[0])
第一个元素的地址大小.同样是指针地址的大小,即4/8个字节,当前是64位,即8
printf("%d\n", sizeof(&a[0])); // 8
sizeof(&a[0] + 1)
第二个元素的地址大小,同样是指针地址的大小,即4/8个字节,当前是64位,即8
sizeof(&a[0] + 1)
char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'}
sizeof(arr)
printf("%d\n", sizeof(arr)); // 6
sizeof(arr + 0)
printf("%d\n", sizeof(arr + 0)); // 8 首元素地址大小,4/8
sizeof(*arr)
printf("%d\n", sizeof(*arr)); // 1 首元素地址解引用,a的字节大小
sizeof(arr[1])
printf("%d\n", sizeof(arr[1])); // 1 第2个元素大小
sizeof(&arr)
printf("%d\n", sizeof(&arr)); // 8 取数组的地址,地址就是地址,4/8
sizeof(&arr + 1)
printf("%d\n", sizeof(&arr + 1)); // 8 跳过整个数组的地址,4/8
sizeof(&arr[0] + 1)
printf("%d\n", sizeof(&arr[0] + 1)); // 8 第2个元素的地址,4/8
♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥
strlen(arr)
printf("%d\n", strlen(arr)); // 随机值,找到 \0 才停止
strlen(arr + 0)
printf("%d\n", strlen(arr + 0)); // 随机值,arr首元素地址+0还是首元素地址,等同于上式
strlen(*arr)
报错, strlen接收字符指针作为参数,而 strlen(*arr) -- strlen('a') -- strlen(97),而97相当于是个野指针,并不属于a
printf("%d\n", strlen(*arr)); // error
strlen(arr[1])
报错,相当于 strlen('b') -- strlen(61) 同上也是野指针
printf("%d\n", strlen(arr[1])); // error
strlen(&arr)
printf("%d\n", strlen(&arr)); // 随机值,取数组地址,本质也是首元素地址
strlen(&arr + 1)
printf("%d\n", strlen(&arr + 1)); // 随机值 - 6,&arr跳过整个数组取地址
strlen(&arr[0] + 1)
rintf("%d\n", strlen(&arr[0] + 1)); // 随机值 - 1, &arr[0] 第一个元素地址
char arr[] = "abcdef"
sizeof(arr)
printf("%d\n", sizeof(arr)); // 7 这里默认补 \0
sizeof(arr + 0)
printf("%d\n", sizeof(arr + 0)); // 8 a的地址+0,还是a的地址,4/8
sizeof(*arr)
printf("%d\n", sizeof(*arr)); // 1 *arr就是元素a
sizeof(arr[1])
printf("%d\n", sizeof(arr[1])); // 1 元素b
sizeof(&arr)
printf("%d\n", sizeof(&arr)); // 8,数组地址,4/8
sizeof(&arr + 1)
printf("%d\n", sizeof(&arr + 1)); // 8 &arr + 1 移动一个数组的长度,即指向数组 arr 之后的一个内存位置,指向 arr 数组结束的位置之后的地址, 指针大小,即4/8
sizeof(&arr[0] + 1)
printf("%d\n", sizeof(&arr[0] + 1)); // 8 元素a的地址
♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥
strlen(arr)
/* 6 截取\0之前的字符个数 */
printf("%d\n", strlen(arr));
strlen(arr + 0)
/* 6 同上 */
printf("%d\n", strlen(arr + 0));
strlen(*arr)
/* 报错,同上上上上上 */
printf("%d\n", strlen(*arr));
strlen(arr[1])
/* 报错,同上上上上上 */
printf("%d\n", strlen(arr[1]));
strlen(&arr)
/* 6 */
printf("%d\n", strlen(&arr));
strlen(&arr + 1)
/* 随机值 跳过整个数组,\0也会跳过,它不知道所指向的下个字符数组的地址个数有几个元素 */
printf("%d\n", strlen(&arr + 1));
strlen(&arr[0] + 1)
/* 5 */
printf("%d\n", strlen(&arr[0] + 1));
char *p = "abcdef"
sizeof(p)
/* 8 这里是指针变量的大小 */
printf("%d\n", sizeof(p));
sizeof(p + 1)
/* 8 b的地址 */
printf("%d\n", sizeof(p + 1));
sizeof(*p)
/* 1 */
printf("%d\n", sizeof(*p));
sizeof(p[0])
/* 1 p[0] == *(p + 0) */
printf("%d\n", sizeof(p[0]));
sizeof(&p)
/* 8 指针变量大小 */
printf("%d\n", sizeof(&p));
sizeof(&p + 1)
/* 8 */
printf("%d\n", sizeof(&p + 1));
sizeof(&p[0] + 1)
/* 8 */
printf("%d\n", sizeof(&p[0] + 1));
♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥
strlen(p)
/* 6 */
printf("%d\n", strlen(p));
strlen(p + 1)
/* 5 */
printf("%d\n", strlen(p + 1));
strlen(*p)
/* 报错,*p == 96 */
printf("%d\n", strlen(*p));
strlen(p[0])
/* 6 */
printf("%d\n", strlen(p[0]));
strlen(&p)
/* 随机值,p本身就是地址,再取地址,相当于取指针变量p的地址,两个地址之间毫无关系 */
printf("%d\n", strlen(&p));
strlen(&p + 1)
/* 随机值 */
printf("%d\n", strlen(&p + 1));
strlen(&p[0] + 1)
/* 5 p[0] == 元素a,&a+1即5 */
printf("%d\n", strlen(&p[0] + 1));
int a[3][4] = {0}
sizeof(a)
/* 48 */
printf("%d\n", sizeof(a));
sizeof(a[0][0])
/* 4 */
printf("%d\n", sizeof(a[0][0]));
sizeof(a[0])
a[0]相当于第一个数组,只有一个数组名,计算当前数组的大小
printf("%d\n", sizeof(a[0])); // 16
sizeof(a[0] + 1)
arr[0]是表示首元素的地址,本质是数组名(又等于第一行数组首元素的地址),等同于第一个数组的arr+1。也就是第一行第二个元素的地址
printf("%d\n", sizeof(a[0] + 1)); // 8
sizeof(*(a[0] + 1))
第一行第二个元素的大小
printf("%d\n", sizeof(*(a[0] + 1))); // 4
sizeof(a + 1)
a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址,a表示首元素的地址,二维数组的首元素是它的第一行,a就是第一行的地址,+1跳过一行的数组,表示第二行的地址
printf("%d\n", sizeof(a + 1)); // 8
sizeof(*(a + 1))
第二行数组地址的解引用,拿到了整个第二行,sizeof内只有数组名,求整个第二行数组的大小
printf("%d\n", sizeof(*(a + 1))); // 16
sizeof(&a[0] + 1)
&a[0]对第一行的数组名取地址,拿出的是第一行的地址,&a[0]+1 得到的是第二行的地址
printf("%d\n", sizeof(&a[0] + 1)); // 8
sizeof(*(&a[0] + 1))
第二行的地址解引用,得到第二行的数组名arr,sizeof内部只有arr,即计算整个第二行数组的大小
printf("%d\n", sizeof(*(&a[0] + 1))); // 16
sizeof(*a)
解引用整个二维数组的地址,即解引用二维数组首元素第一行数组的地址,再解引用第一行的地址得到arr,只有arr,计算整个第一行数组大小
printf("%d\n", sizeof(*a)); // 16
sizeof(a[3])
超界不会真正访问第四行的,其会根据int类型,就可以推算到,等同于a[0]
printf("%d\n", sizeof(a[3])); // 16
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)