【C语言】指针和数组经典笔试题

指针数组经典笔试习题

对于指针和数组我们最常见的习题就是sizeof操作符与strlen函数与数组和指针的结合进行出题,所以我就整理出了sizeof和strlen与数组和指针的一些习题,这也是我曾经踩过的坑,希望与大家共享。

首先我们在做题之前先要了解sizeof()和strlen():

最值得注意的是:sizeof()不是函数,sizeof()是一个操作符。而strlen()是< string.h >下的函数

sizeof()
  1. sizeof看的是变量的类型 。单位是字节。 比如 sizeof(int) 是4个字节。sizeof(char*)在32位下是4个字节,在64位下是8个字节。
  2. sizeof()也有特殊的用法,当sizeof + (数组名arr)的时候,算的是整个数组的字节大小。这里的数组名arr并不是指针。(下面题目中有详解)
  3. sizeof()算字符串大小的时候,要算上结尾的’\0’.
strlen()
  1. strlen()接收的只能是char*类型变量。
  2. 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

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值