指针数组经典笔试习题
对于指针和数组我们最常见的习题就是sizeof操作符与strlen函数与数组和指针的结合进行出题,所以我就整理出了sizeof和strlen与数组和指针的一些习题,这也是我曾经踩过的坑,希望与大家共享。
首先我们在做题之前先要了解sizeof()和strlen():
最值得注意的是:sizeof()不是函数,sizeof()是一个操作符。而strlen()是< string.h >下的函数
sizeof()
- sizeof看的是变量的类型 。单位是字节。 比如 sizeof(int) 是4个字节。sizeof(char*)在32位下是4个字节,在64位下是8个字节。
- sizeof()也有特殊的用法,当sizeof + (数组名arr)的时候,算的是整个数组的字节大小。这里的数组名arr并不是指针。(下面题目中有详解)
- sizeof()算字符串大小的时候,要算上结尾的’\0’.
strlen()
- strlen()接收的只能是char*类型变量。
- strlen()算字符串长度时,遇到’\0’就停止,也就是说’\0’是结尾标志,不算做字符串长度。
习题解析
特此注意:sizeof(指针)在64位中是8个字节,在32位下是4个字节。若笔试题目中没有给出操作系统是多少位的,就按照32位系统处理,因为我们所写的代码大多数都是在32位环境下的。下面的讲解也是。
一维数组
int main ()
{
int a[] = {1, 2, 3, 4};
printf("%d\n",sizeof(a)); // 16 sizeof()+数组名a 算的是整个数组的大小 4个元素,每个元素都是int类型 4*4 = 16
printf("%d\n",sizeof(a+0)); // 4 sizeof(a + 0) 这里是指针,还是元素数组a首元素的地址 所以sizeof(int*) = 4
printf("%d\n",sizeof(*a)); // 4 这里的a是数组a的首地址,解引用a就是第一个元素a[0], 所以是sizeof(int) = 4
printf("%d\n",sizeof(a+1)); // 4 这里的a是数组a的首地址,a+1是下标为1元素(2)的地址,所以sizeof(int*) = 4
printf("%d\n",sizeof(a[1])); // 4 这里是下标为1的元素,sizeof(int) = 4
printf("%d\n",sizeof(&a)); // 4 对整个数组进行取地址,就是数组指针(数组的地址 ---数组指针)。数组指针还是指针,大小为4
printf("%d\n",sizeof(*&a)); // 16 数组指针解引用是整个数组的大小,数组字节数之和 是16
printf("%d\n",sizeof(&a+1)); // 4 数组指针+1,还是数组指针,还是4
printf("%d\n",sizeof(&a[0]));// 4 a[0]元素是int类型,&a[0]就是取首元素的地址 sizeof(int*) = 4
printf("%d\n",sizeof(&a[0]+1)); // 4 a[0]元素的地址+1 就是向下取一位,a[1]的地址,还是int*类型的
}
结果:
字符数组
int main ()
{
char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
printf("%d\n", sizeof(arr)); // 6 因为数组的大小为6, sizeof(char)*6 = 1*6 = 6
printf("%d\n", sizeof(arr+0)); // 4 数组的首地址也是字符'a'的地址, char*类型的 sizeof(char*) = 4
printf("%d\n", sizeof(*arr)); // 1 char*类型的数组首地址arr解引用是char类型的(就是'a') sizeof(char) = 1
printf("%d\n", sizeof(arr[1])); // 1 就是字符'a' char类型的
printf("%d\n", sizeof(&arr)); // 4 取数组的地址--数组指针。 数组指针还是指针, 还是4个字节
printf("%d\n", sizeof(&arr+1)); // 4 数组指针+1 还是数组指针
printf("%d\n", sizeof(&arr[0]+1));// 4 首元素地址+1, 指针+1,就是往后取一位, 就是arr[1]的地址, char*类型的
printf("%d\n", strlen(arr)); // 随机值 没有字符结尾标志'\0'
printf("%d\n", strlen(arr+0)); // 随机值 没有字符结尾标志'\0'
printf("%d\n", strlen(*arr)); // 报错 *arr是对数组首地址(值等于'a'的地址)进行解引用,是char类型的('a'),不是char*类型的
printf("%d\n", strlen(arr[1])); // 报错 arr[1]是char类型的
printf("%d\n", strlen(&arr)); // 报错 &arr是数组指针类型的 是 char(*)[]类型的
printf("%d\n", strlen(&arr+1)); // 报错 数组指针+1 还是数组指针, 类型不匹配
printf("%d\n", strlen(&arr[0]+1)); // 随机。没有'\0' 计算的是从下标为1位置('b')起到结尾的长度
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); // 7 算上'\0' 7个字符
printf("%d\n", sizeof(arr+0)); // 4 char*类型的 4个字节
printf("%d\n", sizeof(*arr)); // 1 char类型的
printf("%d\n", sizeof(arr[1])); // 1 char类型的
printf("%d\n", sizeof(&arr)); // 4 数组指针 4个字节
printf("%d\n", sizeof(&arr+1)); // 4 数组指针+1 还是数组指针
printf("%d\n", sizeof(&arr[0]+1)); // 4 char*类型的, 相当于&arr[1]
printf("%d\n", strlen(arr)); // 6 字符串结尾有'\0'结束标志
printf("%d\n", strlen(arr+0)); // 6 一样
printf("%d\n", strlen(*arr)); // 报错 *arr是char类型的,类型不匹配
printf("%d\n", strlen(arr[1])); // 报错 char类型的
printf("%d\n", strlen(&arr)); // 报错
printf("%d\n", strlen(&arr+1)); // 报错
printf("%d\n", strlen(&arr[0]+1)): // 5 char*+1还是char*, 只是是第一个字符到结尾的距离
char *p = "abcdef";
printf("%d\n", sizeof(p)); // 4 p是char*类型的 不是数组
printf("%d\n", sizeof(p+1)): // 4 p+1还是char*类型的,
printf("%d\n", sizeof(*p)); // 1 p是数组的首地址(数组第一个元素的地址),*p是char类型的
printf("%d\n", sizeof(p[0])); // 1 char类型的
printf("%d\n", sizeof(&p)); // 4 数组指针类型的
printf("%d\n", sizeof(&p+1)); // 4 数组指针+1还是数组指针
printf("%d\n", sizeof(&p[0]+1)); // 4 &p[0]是首元素地址, &p[0]+1第一个字符到结尾的距离
printf("%d\n", strlen(p)); // 6 不算结尾的'\0'
printf("%d\n", strlen(p+1)); // 5 下标为1位置到结尾'\0'的大小
printf("%d\n", strlen(*p)); // 报错
printf("%d\n", strlen(p[0])); // 报错
printf("%d\n", strlen(&p)); // 报错 p是char*类型的,&p是char**类型的, 类型不匹配
printf("%d\n", strlen(&p+1)); // 报错 还是char**类型的
printf("%d\n", strlen(&p[0]+1)); // 5 &p[0]是首元素地址, &p[0]+1是下标为1元素的地址 char*类型的
}
二维数组
我们在讲题之前,先来弄清二维数组的地址关系。
二维数组的地址是二维数组第一行的地址 。
int main()
{
int a[3][4] = {0};
printf("%p\n", &a[0][0]); //二维数组的第一个元素的地址 int*类型的
printf("%p\n", a); // 二维数组的地址也就是第0行的地址,数组的地址,所以是数组指针类型 int(*)[4]
printf("%p\n", &a[0]); //a[0]是第0行数组的首地址,&a[0]是数组指针,指向第0行数组的指针 int(*)[4]类型
}
a是二维数组的地址,二维数组的地址就是第一行的地址,所以是数组的地址。 a[0]是第0行的数组名(后面有讲解), &数组名 = 取数组的地址, 所以类型也是数组指针。 其实a和&a[0]的意义一样。 后面的sizeof(a)和 sizeof(&a[0])的意义也是一样的。~~我们接着向下看,
再看一组容易搞混的概念。
int main()
{
int a[3][4] = { 0 };
printf("%p\n", a[0]); // a[0]是第一行首元素的地址 int*类型的
printf("%p\n", a[0]+1); // int*类型的+1 是+4个字节
printf("%p\n", &a[0]); // &a[0]是第一行的地址,是数组指针 int(*)[4]类型的
printf("%p\n", &a[0]+1); // 数组指针+1 是+一个数组的大小,+16个字节
}
解释: 数组指针+1, +的是一个数组的大小。 指针+1, +的是一个变量类型的大小。
浅显易懂的方法:
其实,二维数组a[3][4],就是由3个大小为4的一维数组。 在内存中地址空间都是连续的。 所以二维数组每一行的地址 a[0], a[1], a[2]都可以理解为一维数组名arr。 二维数组a[i] 就是第i行的数组名。就比如a[0]0, 就是一维数组名为arr[0]的下标为0的元素。 a[1][2]就是数组名为a[1]的下标为2的元素。
所以 ,二维数组a的地址是第一行的地址,也就是a[0]。二维数组的第一行a[0], 可以类比于上面例题中一维数组中的arr。 a[0]+1就相当于arr+1,是一维数组arr下标为1的地址。 &a[0]就相当于&arr, &arr是数组指针。 &a[0]+1就相当于&arr+1, 数组指针+1加的是一个数组的大小(数组字节数之和)。
笔试题目
int main()
{
int a[3][4] = {0};
printf("%d\n", sizeof(a)); // 48 sizeof(数组名) 算的是整个二维数组的大小
printf("%d\n", sizeof(a[0][0])); // 4 sizeof(int) = 4
printf("%d\n", sizeof(a[0])); // 16 a[0]虽说是二维数组的a的地址,也是第一行的地址,但是在这里进行了特殊处理,相当于二维数组第一行的数组名,计算的是a[0]这个一维数组的大小 ---特殊处理
printf("%d\n", sizeof(a[0]+1)); // 4 数组指针+1 还是数组指针 在这里和上面sizeof(a[0]),可以理解为a[0]为一维数组的的数组名,就和上面的一维数组理解起来相同了。 sizeof(arr)算的是arr数组中的总的字节数,而sizeof(arr+0)是指针,还是arr的地址。
printf("%d\n", sizeof(*(a[0]+1)); // 4 第0行下标为1的元素, 相当于a[0][1],int类型的,所以为4
printf("%d\n", sizeof(a+1)); // 4 二维数组a地址+1, 因为二维数组的地址是第一行的地址,所以是数组指针,数组指针+1还是数组指针
printf("%d\n", sizeof(*(a+1)); // 16 a是数组指针,a+1就是下一行第一行的数组指针,数组指针解引用是一个数组的大小。就是第一行的大小
printf("%d\n", sizeof(&a[0]+1)); // 4 &a[0]是数组指针 数组指针+1 还是数组指针
printf("%d\n", sizeof(*(&a[0]+1)));//16 数组指针解引用 就是第a[1]整个数组的大小
printf("%d\n", sizeof(*a)); // 16 a是第一行数组的地址,所以a是数组指针。 数组指针解引用是一个数组的大小
printf("%d\n", sizeof(a[3])); // 16 a[i]相当于第i行的数组名, 所以相当于sizeof(数组名) = 16
}
进一步理解
对于难以理解的在换一层次的解释:
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0]+1));
a[0]可以类比等价于一维数组的arr
二维数组a[i]就相当于第i行的数组名。a[0]就相当于一维数组的数组名。 所以sizeof(a[0]),就相当于sizeof(数组名).所以大小为数组中所有字节的和。 所以就是二维数组中第0行的所有元素的字节和,所以是16。
a[0]+1, a[0]就是第0行首元素的地址, a[0]+1就是下标为1元素的地址。,int*类型的,所以大小为4。 类比于sizeof(arr+1)。
printf("%d\n", sizeof(a+1));
printf("%d\n", sizeof(&a[0] + 1));
其实,这两个表达式意义相同。为什么这样说呢?
二维数组的地址就是二维数组第一行的地址, 第一行的地址,第一行也是数组。所以二维数组的地址的类型就是 数组指针。 数组指针的大小为4,数组指针+1 还是数组指针 。 所以sizeof(a+1)就是4。
a[0]是第0行的数组名,数组名代表的是首元素的地址。取地址数组名&a[0] 就是数组的地址。 类型也是 数组指针。 所以sizeof(&a[0]+1)也是4