我们要使用sizeof和strlen对数组,指针笔试题运算,那么就必须先了解strlen,sizeof和数组名的含义。
了解strlen和sizeof
1.1sizeof
sizeof 计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。
sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
你可以放指针类型,结果就是4或者8个字节(指针的大小与系统的位数相关,即在32位系统上,指针大小为4个字节(32位),而在64位系统上,指针大小为8个字节(64位))。
你放的是int类型,结果就是4个字节。你放的是char类型,结果就是1个字节。
其它类型以此类推,只关注数据占用内存的大小,不关心里面是什么数据。
1.2strlen
strlen 是C语⾔库函数,功能是求字符串⻓度,统计的是 \0 之前字符的个数。使⽤需要包含头⽂件 string.h。
我们使用strlen函数时要注意strlen函数里面存放的数据是地址,strlen是通过地址来访问数据的,直到访问的地址内部存放的数据内部是\0字符才停止运算.
如果strlen函数里面存放的数据不是地址而是字符的话,编译器会自动将字符转换为它们对应的ASCll码值,以与ASCll值大小相同的地址为起点进行访问。
如果strlen函数里面存放的数据不是地址而是数字的话,以与数值大小相同的地址为起点进行访问。
这两种都是传输野指针给strlen,代码是有问题的运行不起来,所以我们在使用尽量符合strlen的运算规则,放地址在strlen函数,而不放其它类型数据。
了解数组名
既然我们我们要使用sizeof和strlen来和数组相结合运算,我们肯定要了解数组名的含义。
- sizeof(数组名),这⾥单独出现的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
- &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
在这有一个要点:整个数组的地址等于数组中首元素地址
一维数组
&arr==arr==&arr[0];
//&arr是整个数组的地址等于数组中首元素地址,arr是首元素地址,所以(&arr==arr)
//arr是首元素地址,&arr[0]也是首元素地址,所以(arr==&arr[0])
二维数组
&arr==arr==&arr[0]==&arr[0][0]
//&arr是整个数组的地址等于数组中首元素地址,arr是首元素地址,所以(&arr==arr)
//arr是首元素地址也是第一行地址等于&arr[0],所以(arr==&arr[0])
//第一行又可看作是一个一维数组,
//整个一维数组的地址&arr[0]等于数组中首元素地址&arr[0][0],所以(&arr[0]==&arr[0][0])
- 除此之外所有的数组名都表⽰⾸元素的地址。
//一维数组
char arr1[] = "ftrbh";
一维数组的数组名就是arr1
//二维数组
char arr2[3][4] = { '0' };
二维数组的数组名为arr2
二维数组有三行四列,和一维数组有所差距的是:
它每一行都可看作为一个一维数组,所以有多少行就有————多少个行数组名和行首元素地址:
arr[0]是第一行的首元素地址也是第一行的数组名;
arr[1]是第二行的首元素地址也是第二行的数组名;
arr[2]是第三行的首元素地址也是第三行的数组名;
有三行所以有三个行首元素地址。
二维数组有多个数组名所以运算是要更加注意。
数组和指针笔试题解析
int a[] = { 1,2,3,4 };//数组有几个元素?
printf("%zd\n", sizeof(a));
//16 -- sizeof(数组名)的场景,计算整个数组,有四个元素,每个元素有4个字节,总共有16个字节。
printf("%zd\n", sizeof(a + 0));
//a是首元素的地址,没有单独出现在sizeof内部-类型是int*, a+0 还是首元素的地址,是地址大小就是4/8
printf("%zd\n", sizeof(*a));
//a是首元素的地址,*a就是首元素,大小就是4个字节
printf("%zd\n", sizeof(a + 1));
//a是首元素的地址,类型是int*,a+1跳过1个整型指针,a+1就是第二个元素的地址,既然是地址那么结果就是4/8
printf("%zd\n", sizeof(a[1]));
//a[1]就是第二个元素,int类型,大小4个字节
printf("%zd\n", sizeof(&a));
//&a符合&数组名类型,是表示整个数组的地址,数组的地址也是地址,类型为int*,大小就是4/8个字节
printf("%zd\n", sizeof(*&a));
//1. *& 互相抵消了,sizeof(*&a) = sizeof(a) -16
//2. &a 是数组的地址,对数组指针解引用访问的是整个数组, 计算的是整个数组的大小 -16
printf("%zd\n", sizeof(&a + 1));
//&a+1是跳过整个数组后的那个位置的地址,类型为int*,就是4/8个字节
printf("%zd\n", sizeof(&a[0]));
//首元素的地址,类型为int*,大小4/8个字节
printf("%zd\n", sizeof(&a[0] + 1));
//&a[0] + 1 -- 数组第二个元素的地址,类型为int*,大小是4/8个字节
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
//数组名单独放在sizeof内部了,计算的是数组的大小,有6个元素,每个元素字节为1个单位,结果为6
printf("%d\n", sizeof(arr + 0));
//arr没有单独放在sizeof内部,所以arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));
//arr没有单独放在sizeof内部,arr是首元素的地址,*arr就是首元素,大小就是1个字节
//*arr -- arr[0] - *(arr+0)
printf("%d\n", sizeof(arr[1]));
//arr[1] 是第二个元素,大小也是1个字节
printf("%d\n", sizeof(&arr));
//&arr 是数组地址,数组的地址也是地址,类型为char*,是指针类型,大小是4/8个字节
//&arr -- char (*)[6]
printf("%d\n", sizeof(&arr + 1));
//&arr+1, 跳过整个数组,指向了数组后边的空间,访问还是指针类型,4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节
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是首元素的地址,*arr是首元素,就是'a','a'的ascii码值是97
//就相当于把97作为地址传递给了strlen,strlen得到的就是野指针, 代码是有问题的
printf("%d\n", strlen(arr[1]));//arr[1]--'b'--98,传给strlen函数也是错误的
printf("%d\n", strlen(&arr));
//&arr是整个数组的地址,起始位置是数组的第一个元素的地址,数组中没有\0,就会导致越界访问,结果是随机值
printf("%d\n", strlen(&arr + 1));
//随机值
printf("%d\n", strlen(&arr[0] + 1));
//从第2个元素的地址开始向后统计的,得到的也是随机值
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
//arr是数组名,单独放在sizeof内部,计算的是数组总大小,是7个字节
printf("%d\n", sizeof(arr + 0));
//arr表示数组首元素的地址,arr+0还是首元素的地址,是地址就是4/8
printf("%d\n", sizeof(*arr));
//arr表示数组首元素的地址,*arr就是首元素,大小是1字节
printf("%d\n", sizeof(arr[1]));
//arr[1]是第二个元素,大小1个字节
printf("%d\n", sizeof(&arr));
//&arr是数组的地址,是地址就是4/8
printf("%d\n", sizeof(&arr + 1));
//&arr是数组的地址,+1跳过整个数组,还是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//&arr[0] + 1是第二个元素的地址,大小是4/8个字节
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
//从首元素的地址开始访问,访问6个字节后遇见\0,结果为6
printf("%d\n", strlen(arr + 0));//arr首元素的地址,arr+0还是首元素的地址,向后在\0之前有6个字符
printf("%d\n", strlen(*arr));
//'a'-97, 就相当于把97作为地址传递给了strlen,strlen得到的就是野指针, 代码是有问题的
printf("%d\n", strlen(arr[1]));
//'b'-98, 就相当于把98作为地址传递给了strlen,strlen得到的就是野指针, 代码是有问题的出错
printf("%d\n", strlen(&arr));
//&arr是数组的地址,也是从数组第一个元素开始向后找,结果是6
printf("%d\n", strlen(&arr + 1));
//&arr是数组的地址,+1跳过整个数组,因为不知道访问多少个字节才能遇见\0,所以结果为随机值
printf("%d\n", strlen(&arr[0] + 1));
//&arr[0]是数组首元素的地址,+1跳过整个一个元素,因为不知道访问多少个字节才能遇见\0,所以结果为随机值
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
//a是数组名,单独放在sizeof内部,计算的是数组的大小,单位是字节 - 48 = 3*4*sizeof(int)
printf("%d\n", sizeof(a[0][0]));
//a[0][0] 是第一行第一个元素,大小4个字节
printf("%d\n", sizeof(a[0]));
//a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节
printf("%d\n", sizeof(a[0] + 1));
//a[0]第一行的数组名,但是a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是
//数组首元素的地址,就是&a[0][0],+1后是a[0][1]的地址,大小是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));
//*(a[0] + 1)表示第一行第二个元素,大小就是4
printf("%d\n", sizeof(a + 1));
//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
//第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址是指针,是地址大小就是4/8个字节
printf("%d\n", sizeof(*(a + 1)));
//1.a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小 - 16
printf("%d\n", sizeof(&a[0] + 1));
//a[0]是第一行的数组名,&a[0]取出的就是数组的地址,就是第一行的地址
//&a[0]+1 就是第二行的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(*(&a[0] + 1)));
//*(&a[0] + 1)意思是对第二行的地址解引用,访问的就是第二行,大小是16字节
printf("%d\n", sizeof(*a));
//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
//第一行的地址,*a就是第一行,计算的就是第一行的大小,16字节
//*a == *(a+0) == a[0]
printf("%d\n", sizeof(a[3]));
//a[3]无需真实存在,仅仅通过类型的推断就能算出长度
//a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16个字
以上就是与sizeof和strlen有关的数组,指针笔试题运算。各位宝子们觉得还行吗?多提点意见,我会一一阅读更改。谢谢。