一、sizeof和strlen的对比
(一)sizeof
在学习操作符的时候,我们学习了sizeof,说明sizeof是一个操作符,绝对不是函数。
sizeof是用来计算变量所占内存空间大小的,单位是字节;如果操作数是类型的话,计算的是适用类型创建的变量所占空间的大小。
sizeof只关注占用内存的大小,不在乎内存中存放什么数据。
而且,sizeof括号中的表达式是不会参与计算的。
cpp
int main()
{
int a = 10;
short c = 8;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a);
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(c = a - 2));
printf("%d\n", c);
return 0;
}

(二)strlen
strlen是C语言的库函数,功能是求字符串长度:
cpp
size_t strlen(const char* str);
统计的是从strlen函数的参数str中这个地址开始向后,\0之前字符串中字符的个数。
strlen函数会一直向后找**\0**字符,直到找到为止,所以可能存在越界查找。
由于字符串的后面会自动跟一个\0,所以strlen计算的长度是准确的;但是,如果是由单个字符组成的话,那就有可能出现越界查找了。
cpp
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
printf("%zd\n", sizeof(arr1));
printf("%zd\n", sizeof(arr2));
return 0;
}

(三)sizeof和strlen的对比

二、数组和指针笔试题解析(1)
在做题目之前,我们再次对数组名的有关知识进行复习:
数组名的理解:
数组名是数组首元素(第一个元素)的地址
但是有2个例外:
-
sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
-
&数组名 - 数组名表示整个数组,取出的是整个数组的地址
除此之外,所以的数组名是数组首元素(第一个元素)的地址。
(一)一维数组
cpp
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//16 sizeof()中的数组名代表整个数组
printf("%d\n", sizeof(a + 0));
//4 or 8 这里的a是首元素地址,类型是int*,a+0还是首元素地址,只要是地址,大小就是4 or 8
printf("%d\n", sizeof(*a));
//4 这里的a是首元素地址,解引用后是整形,整形占4个字节
printf("%d\n", sizeof(a + 1));
//4 or 8 这里的a是首元素地址,+1就是跳过一个整型,a+1也就是第二个元素的地址
printf("%d\n", sizeof(a[1]));
//4 a[1]就是第二个元素,为整型
printf("%d\n", sizeof(&a));
//4 or 8 &a是整个数组的地址,整个数组的地址也是地址,所以是4 or 8
printf("%d\n", sizeof(*&a));
//16 1.*&相互抵消,计算的是整个数组的大小;2.&a是数组指针类型,解引用后访问的是数组
printf("%d\n", sizeof(&a+1));
//4 or 8 &a是整个数组的地址,+1就是跳过整个数组的地址后那个位置的地址,是地址就是4 or 8
printf("%d\n", sizeof(&a[0]));
//4 or 8 首元素地址,大小4 or 8
printf("%d\n", sizeof(&a[0] + 1));
//4 or 8 数组第二个元素的地址,大小4 or 8
return 0;
//这里要强调一下:arr与&arr的地址数值是一样的,差别就在于二者类型不同,
//arr是int*,&arr则是(int)(*)[4]
}
16 sizeof()中的数组名代表整个数组
4 or 8 这里的a是首元素地址,类型是int*,a+0还是首元素地址,只要是地址,大小就是4 or 8
4 这里的a是首元素地址,解引用后是整形,整形占4个字节
4 or 8 这里的a是首元素地址,+1就是跳过一个整型,a+1也就是第二个元素的地址
4 a[1]就是第二个元素,为整型
4 or 8 &a是整个数组的地址,整个数组的地址也是地址,所以是4 or 8
16 1.*&相互抵消,计算的是整个数组的大小;2.&a是数组指针类型,解引用后访问的是数组
4 or 8 &a是整个数组的地址,+1就是跳过整个数组的地址后那个位置的地址,是地址就是4 or 8
4 or 8 首元素地址,大小4 or 8
4 or 8 数组第二个元素的地址,大小4 or 8
这里要强调一下:
arr与&arr的地址数值是一样的,差别就在于二者类型不同,
arr是int*,&arr则是(int)(*)[4]
(二)字符数组
1.代码1
cpp
//代码一
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
//6 sizeof()中的arr代表整个数组,大小就是整个数组的大小
printf("%d\n", sizeof(arr + 0));
//4 or 8 arr是首元素地址,arr+0还是首元素地址,是地址就是4 or 8
printf("%d\n", sizeof(*arr));
//1 *arr是首元素,char类型就是1个字节
printf("%d\n", sizeof(arr[1]));
//1 第二个元素
printf("%d\n", sizeof(&arr));
//4 or 8 整个数组的地址,是地址就是4 or 8
printf("%d\n", sizeof(&arr + 1));
//4 or 8 跳过了整个数组,指向了后面的空间,是地址就是4 or 8
printf("%d\n", sizeof(&arr[0] + 1));
//4 or 8 第二个元素的地址值 是地址就是4 or 8
return 0;
}
2.代码2
cpp
//代码二
#include<string.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
//随机 arr是首元素地址,按理说会计算整个字符串长度,但是因为单个字符,
// 所以无\0,就会导致越界访问,结果是随机的
printf("%d\n", strlen(arr + 0));
//随机 arr+0是首元素地址,按理说会计算整个字符串长度,但是因为单个字符,
// 所以无\0,就会导致越界访问,结果是随机的
printf("%d\n", strlen(*arr));
//有问题 *arr就是首元素,'a'的Ascll码值是97,就相当于把97作为地址传递给了strlen
//函数,strlen得到的是野指针,此代码就是有问题的
printf("%d\n", strlen(arr[1]));
//有问题 arr[1]是第二个元素,Ascall码值就是98,就相当于把98作为地址传递给了strlen
//函数,strlen得到的是野指针,此代码就是有问题的
printf("%d\n", strlen(&arr));
//随机值x &arr是整个数组的地址,起始位置是数组的第一个元素的位置,所以会得到随机值x
printf("%d\n", strlen(&arr + 1));
//随机值x-6
printf("%d\n", strlen(&arr[0] + 1));
//从第二个元素开始向后统计的,得到的也就是随机值x-1
return 0;
}
随机 arr是首元素地址,按理说会计算整个字符串长度,但是因为单个字符,所以无\0,就会导致越界访问,结果是随机的;
随机 arr+0是首元素地址,按理说会计算整个字符串长度,但是因为单个字符,所以无\0,就会导致越界访问,结果是随机的;
有问题 *arr就是首元素,'a'的Ascll码值是97,就相当于把97作为地址传递给了strlen函数,strlen得到的是野指针,此代码就是有问题的;
有问题 arr[1]是第二个元素,Ascall码值就是98,就相当于把98作为地址传递给了strlen函数,strlen得到的是野指针,此代码就是有问题的;
随机值x &arr是整个数组的地址,起始位置是数组的第一个元素的位置,所以会得到随机值x;
随机值x-6;
从第二个元素开始向后统计的,得到的也就是随机值x-1
3.代码3
cpp
//代码三
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
//7 arr在sizeof()里面,代表整个数组,sizeof计算时,会计算上字符串最后的\0
printf("%d\n", sizeof(arr + 0));
//4 or 8 arr代表首元素地址,arr+0还是首元素地址,是地址就是4 or 8
printf("%d\n", sizeof(*arr));
//1 arr是数组首元素地址,*arr就是首元素,char类型是1字节
printf("%d\n", sizeof(arr[1]));
//1 arr[1]是数组的第二个元素
printf("%d\n", sizeof(&arr));
//4 or 8 &arr是整个数组的地址,是地址就是4 or 8
printf("%d\n", sizeof(&arr + 1));
//4 or 8 +1是跳过整个数组,还是地址,是地址就是4 or 8
printf("%d\n", sizeof(&arr[0] + 1));
//4 or 8 +1是跳过一个元素的地址,所以现在是该数组第二个元素的地址,是地址就是4 or 8
return 0;
}
7 arr在sizeof()里面,代表整个数组,sizeof计算时,会计算上字符串最后的\0;
4 or 8 arr代表首元素地址,arr+0还是首元素地址,是地址就是4 or 8
1 arr是数组首元素地址,*arr就是首元素,char类型是1字节
1 arr[1]是数组的第二个元素
4 or 8 &arr是整个数组的地址,是地址就是4 or 8
4 or 8 +1是跳过整个数组,还是地址,是地址就是4 or 8
4 or 8 +1是跳过一个元素的地址,所以现在是该数组第二个元素的地址,是地址就是4 or 8
4.代码4
cpp
//代码四
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
//6 arr代表首元素地址,从首元素一直计算到\0为止
printf("%d\n", strlen(arr + 0));
//6 arr+0还是首元素地址
printf("%d\n", strlen(*arr));
//报错 'a'的Ascll码是97,无意义
printf("%d\n", strlen(arr[1]));
//报错 'b'的Ascll码是98,无意义
printf("%d\n", strlen(&arr));
//6 &arr是整个数组的地址,也就是从该数组第一个元素开始计算到\0为止
//这里说明一下,&arr的类型是char(*)[7] 但是strlen()中的类型是
//const char* str 说明发生了强制类型转换
printf("%d\n", strlen(&arr + 1));
//随机值 因为+1跳过的是整个数组,那么何时遇到\0是不确定的
printf("%d\n", strlen(&arr[0] + 1));
//5 从该数组第二个元素开始计算
return 0;
}
6 arr代表首元素地址,从首元素一直计算到\0为止
6 arr+0还是首元素地址
报错 'a'的Ascll码是97,无意义
报错 'b'的Ascll码是98,无意义
6 &arr是整个数组的地址,也就是从该数组第一个元素开始计算到\0为止,这里说明一下,&arr的类型是char(*)[7] 但是strlen()中的类型是,const char* str 说明发生了强制类型转换
随机值 因为+1跳过的是整个数组,那么何时遇到\0是不确定的
5 从该数组第二个元素开始计算
5.代码5
cpp
//代码五
#include <string.h>
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));
//4 or 8 p是指针变量
printf("%d\n", sizeof(p + 1));
//4 or 8 p代表的是首元素,也就是a的地址,所以p+1是b的地址
printf("%d\n", sizeof(*p));
//1 p的类型是char*,解引用完就是char类型
printf("%d\n", sizeof(p[0]));
//1 ------1------ p[0]可以转换为*(p+0),所以代表第一个元素a
// ------2------ 把字符串想象成数组,p可以理解为数组名,p[0]就是首元素
printf("%d\n", sizeof(&p));
//4 or 8 取出的是p的地址,为二级指针类型,是地址就是4 or 8
printf("%d\n", sizeof(&p + 1));
//+1是跳过p指针变量后的地址,是地址就是4 or 8
printf("%d\n", sizeof(&p[0] + 1));
//代表第二个字符的地址,是地址就是4 or 8
return 0;
}
4 or 8 p是指针变量
4 or 8 p代表的是首元素,也就是a的地址,所以p+1是b的地址
1 p的类型是char*,解引用完就是char类型
1 ------1------ p[0]可以转换为*(p+0),所以代表第一个元素a
------2------ 把字符串想象成数组,p可以理解为数组名,p[0]就是首元素
4 or 8 取出的是p的地址,为二级指针类型,是地址就是4 or 8
+1是跳过p指针变量后的地址,是地址就是4 or 8
代表第二个字符的地址,是地址就是4 or 8
6.代码6
cpp
int main()
{
char* p = "abcdef";
printf("%d\n", strlen(p));
//6
printf("%d\n", strlen(p + 1));
//5
printf("%d\n", strlen(*p));
//报错 'a'的Ascll码是97,无意义
printf("%d\n", strlen(p[0]));
//报错 p[0]-->*(p+0)-->*p
printf("%d\n", strlen(&p));
//&p是指针变量p的地址,和字符串"abcdef"关系不大
printf("%d\n", strlen(&p + 1));
//随机值 而且与&p无关系,因为两者地址中间对于\0的情况是未知的
printf("%d\n", strlen(&p[0] + 1));
//5 代表第二个元素的地址,也就是从b开始计算
return 0;
}
6
5
报错 'a'的Ascll码是97,无意义
报错 p[0]-->*(p+0)-->*p
&p是指针变量p的地址,和字符串"abcdef"关系不大
随机值 而且与&p无关系,因为两者地址中间对于\0的情况是未知的
5 代表第二个元素的地址,也就是从b开始计算