一维数组易混淆的点,各种数组名+-的各种坑,sizeof与strlen求的数值的坑

2024 - 10 - 05 - 笔记 - 22
作者(Author):郑龙浩 / 仟濹(网名)

一维数组易混淆的点,各种数组名±的含义,各种坑

1) 一维数组【int】int arr[] = {1, 2, 3, 4}

int arr[] = {1, 2, 3, 4};

//在大多数情况下,arr表示的是首元素地址,但是在sizeof里面代表的是整个数组,所以打印的是整个数组的值大小,一个元素为4字节,所以4个元素的大小为4 * 4 == 16字节
printf("%d\n", sizeof(arr));//16 byte

//虽然说arr + 0 与 arr没有什么区别,但实际上arr + 0就不能表示整个数组了,而是表示的首元素的地址,arr + 0相当于 &arr[0] + 0 == &arr[0] == arr
printf("%d\n", sizeof(arr + 0));//4 byte / 8 byte(32位4字节,64位8字节)

//大部分情况下,只要sizeof中不是只有单独的arr,那么arr就是首元素地址,在这里arr为首元素地址,解引用就是首元素的值,即arr[0]
printf("%d\n", sizeof(*arr));//1 byte

//同上,arr为首元素地址,首元素地址加1为第二个元素的地址,只要是地址,就是 4 / 8 (32位 / 64位)
printf("%d\n", sizeof(arr + 1));//4 byte / 8 byte

//arr[1]为第二个元素的值,而这个元素的值为int型,int型的数据就是4个字节
printf("%d\n", sizeof(arr[ 1 ]));//4 byte


//这个稍微复杂一点
//1.&arr表示的是整个数组的地址
//2.还有一种解释相对复杂,&arr拿到的是整个数组的地址,那么类型就是int(*)[4],这是一种数组指针,但是指针所占的大小依然是固定的
//只要是地址,就是4 byte Or 8 byte
printf("%d\n", sizeof(&arr));//4 byte / 8 byte (32位 / 64位)


//这个也稍微复杂一点
//1.&arr表示的是整个数组的地址, 然后再解引用,就是表示的整个数组.可以理解为*&相互抵消了
//2.还有一种解释相对复杂,&arr拿到的是整个数组的地址,那么类型就是int(*)[4],这是一种数组指针,对数组指针解引用,得出来的就是【数组】
printf("%d\n", sizeof(*&arr));//16 byte


//同上,地址 + 1照样还是地址,只要是地址,就是4 byte Or 8 byte
printf("%d\n", sizeof(&arr + 1));//4 byte / 8 byte(32位 / 64位)

//&arr[0] 首元素的地址,首元素地址也是地址(4 byte / 8 byte),+1后仍然还是地址,所以还是 4 byte / 8 byte
printf("%d\n", sizeof(&arr[ 0 ] + 1));//4 byte / 8 byte(32位 / 64位)

2) 一维数组【char】char arr[] = {'a', 'b', 'c', 'd'};

char arr[] = {'a', 'b', 'c', 'd'};

sizeof


//在sizeof中,单写一个数组名,该数组名表示的就是整个数组,那么该数组的大小就是4  * 1 byte
printf("%d\n", sizeof(arr));//4 byte

//arr表示的首元素地址,地址的大小就是 4 byte / 8 byte
printf("%d\n", sizeof(arr + 0));//4 byte / 8 byte(32位 / 64位)

//arr表示的是首元素地址,解引用首元素地址 -> 元素的值 -> char的元素,占 1 byte
printf("%d\n", sizeof(*arr));//1 byte

//arr[1]为第2个元素值,该值的元素为char类型,所以占 1 byte
printf("%d\n", sizeof(arr[ 1 ]));//1 byte

//1.&arr表示的是整个数组的地址
//2.还有一种解释相对复杂,&arr拿到的是整个数组的地址,那么类型就是int(*)[4],这是一种数组指针,但是指针所占的大小依然是固定的
//只要是地址,一般就是 4 byte / 8 byte
printf("%d\n", sizeof(&arr));// 4 byte / 8 byte

//整个数组的地址 + 1,直接跳过整个数组,至于地址是什么地方就不知道了,可能直接变为了野指针,但是指针的大小依然不变
printf("%d\n", sizeof(&arr + 1));// 4 byte / 8 byte 

//&arr[0]为首元素的地址,首元素的地址 + 1 就是 &arr[1],只要是地址,依然是4 byte / 8 byte
printf("%d\n", sizeof(&arr[ 0 ] + 1 ));// 4 byte / 8 byte(32位 / 64位)

strlen - strlen是一个函数,用于计算并返回给定字符串的长度

从提供的地址开始,计算直至遇到字符串终止符‘\0’所在地址,确定字符串的实际长度。

//给的是数组的首地址,而strlen是从给的地址计算到'\0'所在地址的,然而该数组中可能并没有'\0',因为后面的数据是随机的,所以不知道指向第几个地址时才会有'\0',那么求的该数组字符串的大小就是随机的了
printf( "%d\n", strlen( arr ) );//随机值

//与上方的情况一样,依然是个随机值
printf( "%d\n", strlen( arr + 0 ) );//随机值

//这个就好玩了,arr是收元素的地址,*arr就是首元素的值,而在该数组中,首元素的值为'a',那么strlen(*arr) <==> strlen('a') <==> strlen( 97 );
//strlen中的参数是个地址,所以计算机会把97当做地址,而这种地址是未定义或者不可预知的,也就是平时所熟知的野指针了,对于这种野指针,在编译的时候,一般不会报错,但是在调试的时候,会有弹窗来报错提示的
printf( "%d\n", strlen( *arr ) );//程序错误 - 野指针

//与上方的情况是类似的,依然是报错
printf( "%d\n", strlen( arr[ 1 ] ) );//程序错误 - 野指针

//依然是随机值,和strlen(arr)情况相似,在strlen(arr)中,arr表示的是数组首元素的地址( 类型 - char* ),&arr表示的是整个数组的地址( 类型 - (char*)[4] ),这俩虽然类型不一样,但是strlen的参数类型设置的是 const char*,在传参过去的时候,也会强行将地址类型转换为char*,所以这俩所表示的地址还是一样的,都是首元素的地址,所以依然是随机值
//其实首元素的地址和整个数组的地址虽然类型不一样,但是在打印的时候,数值确还是一样的,所以不要太纠结
printf( "%d\n", strlen( &arr ) );//随机值

//&arr表示整个数组的地址,对&arr加1会跳过整个数组的内存区域,指向数组之后的内存,但这并不提供关于原数组长度的任何信息。对&arr加1后得到的地址与原数组无直接关联,它指向的是数组之后的内存区域。如果试图从这个地址开始“计算长度”,实际上依然是没有意义的。结果也就是随机值了。计算的时候不是从数组首地址开始计算的,而是从数组首地址开始算,第5个位置开始计算的,所以计算出来的大小就是原来的基础之上再减去4个(数组宽度)。
printf( "%d\n", strlen( &arr + 1 ) );//随机值 - 4

//首元素的地址 + 1 得出的是arr[1]的地址,即&arr[1],从这开始计算,比原来少计算了1个
printf( "%d\n", strlen( &arr[0] + 1 ) );//随机值 - 1

3) 指针指向常量字符串,int* p = “abcdef” - 数组有’\0’`

//在sizeof中,单写一个数组名,该数组名表示的就是整个数组,但是要注意p可不是数组名,他是一个char*类型的指针变量,指向的是字符串的第一个元素的地址,就是'a'的地址,那么打印出来肯定就是地址的大小了,即 4 byte / 8 byte (32位 / 64 位)
printf("%d\n", sizeof(p));//4 byte / 8 byte

//p指向常量字符串"abcdef"的首元素地址,地址的大小就是 4 byte / 8 byte
printf("%d\n", sizeof(p + 0));//4 byte / 8 byte(32位 / 64位)

//p指向常量字符串"abcdef"的首元素地址,解引用首元素地址 -> 元素的值 -> char的元素,占 1 byte
printf("%d\n", sizeof(*p));//1 byte

//p可以当数组名来用,p[1]为第2个元素值,该值的元素为char类型,所以占 1 byte
printf("%d\n", sizeof(arr[ 1 ]));//1 byte

//&p是指针变量的地址,只要是地址,大小就是 4 byte Or 8 byte
printf("%d\n", sizeof(&p));// 4 byte / 8 byte

//从p的地址跳过1个偏移量,依然还是地址
printf("%d\n", sizeof(&p + 1));// 4 byte / 8 byte 

//&p[0]为首元素的地址,首元素的地址 + 1 就是 &p[1],就相当于是'b'的地址,只要是地址,就是 4 byte / 8 byte
printf("%d\n", sizeof(&p[ 0 ] + 1 ));// 4 byte / 8 byte(32位 / 64位)

这次计算字符串长度就和上次不一样了,因为上次是没有‘\0’结尾,这次是有‘\0’结尾

//从'a'的地址开始计算到'f',宽度为6个
printf("%d\n", strlen(p));//6

//这里与上面一样的
printf("%d\n", strlen(p + 0));//6

//*p取出来是'a',也就是给了strlen一个地址为97
printf("%d\n", strlen(*p));//程序错误 - 野指针

//p[1]取出来是'b',也就是给了strlen一个地址为98,这不是一个有定义的自己或是可预知的地址
printf("%d\n", strlen(p[ 1 ]));//程序错误 - 野指针

//给strlen的是p的地址,而p是一个指针变量,这个定义的或者是可预知的,往后计算的时候,不知道何时会遇到'\0',那么计算出来就是随机值
printf("%d\n", strlen(&p));// 随机值

//给strlen的是p的地址 + 1 偏移量,而p是一个指针变量,这个定义的或者是可预知的,往后计算的时候,不知道何时会遇到'\0',那么计算出来就是随机值
printf("%d\n", strlen(&p + 1));//

//&p[ 0 ] + 1 等于是 &p[1],相当于'b'开始计算,计算到'f',得出5个
printf("%d\n", strlen(&p[ 0 ] + 1 ));// 5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值