一、sizeof与strlen对比
1.1 sizeof
sizeof是一个操作符,绝对不是函数,如果操作数是变量,则计算变量所占内存空间的大小,如果操作数是类型,则计算使用该类型创建变量所占内存空间的大小
sizeof只关注占内存空间的大小,不在乎内存中存放的是什么数据

sizeof里的表达式不会运算
表达式是在产生.exe可执行程序时双击运行时才会运行表达式,而sizeof运算是在编译时就计算好了,编译完以后表达式就没在代码里面了,自然就不会算表达式
1.2 strlen
是一个库函数,只针对字符串,求字符串的长度,把首地址的地址传给函数,统计\0之前的个数
三种写法:

错误写法:

1.3 sizeof与strlen对比

二、sizeof练习
2.1 整形数组
已知:int arr[]={1,2,3,4}
sizeof(arr+0)的结果
计算机假设计算arr+0运行,算出结果的类型,但是实际并不会进行真正的运算,arr没有单独与sizeof结合,arr就是首元素的地址,arr+0还是首元素的地址,sizeof(arr+0)的结果就是4/8
sizeof(&arr)的结果
&arr也是数组的地址,数组的地址也是地址,sizeof计算出来为4/8
sieof(*&a)的结果
- 方法1:*与&相抵消,就是
sizeof(arr)也就是整个数组的大小 - 方法2:&arr取出的是数组的地址,类型是int(*)[4],对数组指针解引用,而旁边直接有sizeof,所以访问的是一个数组,也就是一个数组的大小

sizeof(&arr+1)
&arr+1没有访问内存空间,是跳过这个数组后那个位置的地址,是地址就是4/8
2.2 字符数组
已知: char arr[] = { 'a','b','c','d','e','f' };
sizeof(arr)的结果
arr与sizeof()结合求整个数组的大小
sizeof(arr+0)的结果
arr就是首元素的地址,arr+0还是首元素的地址,sizeof(arr+0)的结果就是4/8
sizeof(&arr)的结果
&arr为整个数组的地址,类型是int (*)[6]
sizeof(&arr[0]+1)的结果
&arr[0]为第一个元素的地址,&arr[0]+1为第二个元素的地址
2.3 存字符串数组
- 存到数组中
已知:char arr[] = "abcdef";
sizeof(arr)的结果
arr是数组名,单独放在sizeof()内部,计算的是数组总大小,加上\0有7个

sizeof(arr+0)的结果
arr表示数组首元素的地址,arr+0还是首元素的地址,是地址就是4/8
- 还有一种也是字符串,但是放到指针类型
const char *p="abcdef"

printf("%d",sizeof(p))的结果
p是指针变量,我们计算的是指针变量的大小,4/8个字节
printf("%d",sizeof(p+1))的结果
p+1是b的地址,是地址大小就是4/8个字节
printf("%d",sizeof(*p))的结果
*p的类型是const char*,*p就是char类型了,1个字节
printf("%d",sizeof(p[0]))的结果
理解方式:
- p[0]-->*(p+0)-->'a',大小是一个字节
- 把常量字符串想象成数组,p可以理解为数组名,p[0],就是首元素
printf("%d",sizeof(&p))的结果
p是个指针变量,&p去的是p空间的地址,与"abcdef"没关系,结果为4/8
printf("%d",sizeof(&p+1))的结果
跳过char*类型的地址,也是地址
2.4 二维数组
已知:int arr[3][4] = { 0 };
printf("%d", sizeof(arr))的结果
arr单独与sizeof结合,计算的是整个数组的大小,结果为3* 4 *4等于48
printf("%d", sizeof(arr[0]))的结果
a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小16个
理解方式:

printf("%d", sizeof(arr[0]+1))的结果
arr[0]没有单独放在sizeof()内部,所以arr[0]就是首元素的地址,就是arr[0][0],+1后变成arr[0][1]的地址,结果为4/8
printf("%d", sizeof(*(arr[0] + 1)))的结果
(arr[0] + 1)代表的是第二个元素的地址,*(arr[0] + 1)指的是第二个元素
printf("%d", sizeof(arr + 1))的结果
arr没有放在sizeof内部,arr表示二维数组的首地址,也就是一维数组的地址(第一行的地址),+1就是第二行的地址,a+1是数组指针,结果是4/8
printf("%d", sizeof(*(arr + 1)))的结果
理解方式:
- (arr+1)是第二行的地址,数组指针解引用,访问的是第二行,*(arr+1)计算的是第二行的大小
- *(arr+1)==arr[1],arr[1]是第二行的数组名,相当于把第二行的数组名放在
sizeof()里面,计算的是第二行的大小
printf("%d", sizeof(&arr[0] + 1))的结果
arr[0]是第一行的数组名,与sizeof结合,就是第一行的地址,arr[0]+1就是第二行的地址,是地址结果就是4/8
printf("%d", sizeof(*(&arr[0] + 1)))的结果
(&arr[0]+1)是第二行的地址,数组指针,解引用访问的是第二行,大小是16
printf("%d", sizeof(*arr))
arr是二维数组的首元素的地址,也就是第一行的地址,*arr就是第一行,计算的是第一行的大小
*a == *(a+0) == a[0]
sizeof(arr[3]), 会越界访问吗?
arr[3]无需存在,仅仅通过类型的推断就能算出长度,arr[3]是第四行的数组名,与sizeof()单独结合,计算的是第四行的大小,16个字节
注:sizeof不会真实访问空间,可以自己推断类型

总结:

三、strlen练习
3.1 字符数组
已知: char arr[] = { 'a','b','c','d','e','f' };
strlen(arr)的结果
首先分析arr既没与sizeof结合,也没与&结合,所以也是数组名表示首元素的地址,把首元素的地址传给strlen,从这个位置向后数,数到 \0就停下来统计个数,数组没有\0就会越界访问,结果为随机值
strlen(*arr)的结果
是首元素的地址,*arr是首元素,就是'a',strlen这个函数接受的是地址,a的Ascill码值为97,拿到一个野指针97,97这个地址不允许我们访问,运行到这里程序会崩溃
sizeof(&arr)的结果
arr是数组的地址,起始位置是数组的第一个元素的位置,strlen也是从这开始的,结果为随机值
3.2 存字符串数组
- 存到数组中
已知:char arr[] = "abcdef";
strlen(*arr)
*arr为首元素,为'a',Ascill码值为97,出错
strlen(&arr)
补充:strlen函数是char*类型的,而取地址数组是char * arr[6]的类型,会发生强制类型转换

&arr是数组的地址,也是从数组第一个元素开始向后找,结果是6
strlen(&arr+1)
跳过整个数组,结果为随机值
strlen(&arr[0]+1)
从第二个地址开始,结果为5
- 还有一种也是字符串,但是放到指针类型
已知:char* p = "abcdef";
printf("%d", strlen(p));
p存放的是a的地址,从前往后数,到\0为止,结果为6
printf("%d", strlen(p+1));
p+1是b的地址,从前往后数,到\0为止,结果是5
printf("%d", strlen(*p));
*p是'a',Ascill码值是97,程序会报错
printf("%d", strlen(&p));

&p是指针变量p的地址,和字符串"abcdef"关系就不大了,/从p这个指针变量的起始位置开始向后数的,变量存放的地址是什么,不知道,所以答案是随机值
printf("%d", strlen(&p[0]+1));
从第二个地址向后数,结果为5
四、巩固指针
易错题分析
- 指针加减

- 逗号表达式与指针

- 指针类型转换区别

- 二维数组的理解

- 字符串与指针

- 指针综合:优先级、多级指针

++、--会把值改掉,
[](下标运算符不会改)
*得到里面的空间,会把里面的值改掉