数组、指针练习题及解析(含笔试题目讲解)其一(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 数组、指针练习题及解析(含笔试题目讲解)其一

前言

前几期的博客已经将有关指针、数组的所以知识都已基本讲解完毕,那么接下来我们就做一些练习巩固,这些练习依据历年来一些公司笔试题进行改编,更有经典笔试题目,如果您想要提高自己的 C 语言编程能力,那么数组和指针练习题是必不可少的。在本文中,我们将为您提供一些有趣且具有挑战性的问题,并附上详细的解析和讲解。


题目列表:

//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a)
printf("%d\n",sizeof(a[3]));
指针笔试题
笔试题1:
int main()
{
  int a[5] = { 1, 2, 3, 4, 5 };
  int *ptr = (int *)(&a + 1);
  printf( "%d,%d", *(a + 1), *(ptr - 1));
  return 0;
}
//程序的结果是什么?
笔试题2:
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
笔试题3:
int main()
{
  int a[4] = { 1, 2, 3, 4 };
  int *ptr1 = (int *)(&a + 1);
  int *ptr2 = (int *)((int)a + 1);
  printf( "%x,%x", ptr1[-1], *ptr2);
  return 0;
}
笔试题4:
#include <stdio.h>
int main()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  int *p;
  p = a[0];
  printf( "%d", p[0]);
return 0;
}
笔试题5;
int main()
{
  int a[5][5];
  int(*p)[4];
  p = a;
  printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
  return 0;
}
笔试题6:
int main()
{
  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int *ptr1 = (int *)(&aa + 1);
  int *ptr2 = (int *)(*(aa + 1));
  printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}
笔试题7:
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
笔试题8:
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}

大家可以先尝试自己做,最后与我的解析进行对比,思路是否正确。

题目解析

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));

看到第一题sizeof(数组名),这里提到数组名,那再次强调一次数组名的理解,后边的题目几乎都牵扯到数组名的理解

数组名的理解

数组名指的是数组首元素的地址

2个例外

sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。

&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

一维数组

我们接着来看第一个

printf("%d\n",sizeof(a));

sizeof(a),a是一个整形数组,里边有4个字节,那么输出的结果也就是4*4=16,16个字节

printf("%d\n",sizeof(a+0));

sizeof(a+0)括号里不再是数组名,而是数组名+0,这里就不再表示是整个数组了。a是数组首元素的地址+0还是数组首元素地址。是地址所占空间就是4/8个字节

printf("%d\n",sizeof(*a));

sizeof(*a),这里并没有将a单独放在sizeof内部,所以就不能表示为整个数组,所以这里的a表示的是数组首元素的地址,解引用就是数组的首元素。数组为整形所以占4个字节

printf("%d\n",sizeof(a+1));

sizeof(a+1),这里也是并没有将a单独放在sizeof内部,所以这里的a表示数组首元素的地址,a+1,跳过一个整形的空间,也就是第二个元素的地址。是地址所占的内存空间就是4/8个字节

printf("%d\n",sizeof(a[1]));

这个就简单了,a[1]代表的是数组第二个元素,是一个整形数字,占4个字节

printf("%d\n",sizeof(&a));

sizeof(&a),这里a表示数组首元素的地址,&a取出整个数组的地址,&a也是个地址,是地址就占4/8个字节

printf("%d\n",sizeof(*&a));

sizeof(*&a),这里可以从两个角度去理解

1.*&相互抵消,sizeof(*&a)等价于sizeof(a),占16个字节。

2.&a取出的是整个数组的地址,那它的数据类型也就是int (*)[4]一个指向4个整形空间大小的指针,解引用也就是4个整形空间的大小。4*4=16,占16个字节

printf("%d\n",sizeof(&a+1));

sizeof(&a+1),&a取出的是整个数组的地址,+1跳过一个数组的空间,但它终究还是个地址,是地址就占4/8个字节

printf("%d\n",sizeof(&a[0]));

sizeof(&a[0]),a[0]是数组首元素,那&a[0]就是数组首元素的地址,所以占4/8个字节

printf("%d\n",sizeof(&a[0]+1));

&a[0]是数组首元素的地址,&a[0]+1就是数组第二个元素的地址占4/8个字节

通过一维数组的练习我们发现了什么规律?

sizeof计算大小时根本就不关心数组的大小,它只关注数据的类型。

字符数组

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));

sizeof(arr),数组名单独放在sizeof内部,那就是整个数组的大小,char类型的数组每个元素占1个字节的空间,所以arr数组也就占6个字节

printf("%d\n", sizeof(arr+0));

这里并不是将arr(数组名)单独放在sizeof内部,这里的arr表示数组首元素地址,arr+0还是数组首元素的地址,是地址就占4/8个字节

printf("%d\n", sizeof(*arr));

arr没有单独放在sizeof内部,那么arr表示数组首元素地址,*arr就是数组首元素,占1个字节

printf("%d\n", sizeof(arr[1]));

arr[1]表示数组第二个元素,占1个字节

printf("%d\n", sizeof(&arr));

arr没有单独放在sizeof内部,所以arr表示数组首元素地址,&arr又表示整个数组的地址。是地址就占4/8个字节的空间

printf("%d\n", sizeof(&arr+1));

&arr取的是整个数组的地址,+1跳过整个数组,&arr+1是跳过整个数组后的地址,是地址就占4/8个字节

printf("%d\n", sizeof(&arr[0]+1));

&arr[0]+1表示数组第二个元素的地址,是地址就占4/8个字节

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));

这次我们用的不是sizeof了,使用的是strlen。

arr在内存中存储如下图:

内存条中,arr前和arr后数据都未知,我们知道strlen求字符串长度是到 '\0' 才会停止计算。

在数组arr中我们存'a','b','c','d','e','f'时是不会在数组是最后补上‘\0’,

所有就会造成在使用strlen求arr字符串长度时会越界访问数组arr后未知区域的数据,直到遇到‘\0’为止。这时计算的strlen就是随机值。

在知道这些的前提下,我们继续来看题目。

strlen(arr),arr是数组首元素的地址,从首元素开始向后遍历,直到\0为止,在遍历完数组后,还会一直向后遍历,直到遇到\0为止,所有输出会是一个随机值

printf("%d\n", strlen(arr+0));

arr+0,还是数组首元素地址,和上一个一样也是一个随机值

printf("%d\n", strlen(*arr));

arr是数组首元素地址,*arr就是数组首元素,但这里我们要注意,strlen这个库函数参数部分需要传的是一个地址。当我们传递一个‘a’时,编译器就会将‘a’的ASCII值97当作地址传参,这时strlen就会从97这块空间开始取计算字符串长度,这样就造成了内存的非法访问,我们在运行时程序就会崩溃,出现错误

printf("%d\n", strlen(arr[1]));

arr[1]数组的第二个元素‘b’,传进去一个字符‘b’,结果和上一个一样,出现错误。

printf("%d\n", strlen(&arr));

&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计,所以输出会是一个随机值

printf("%d\n", strlen(&arr+1));

&arr+1,跳过了数组arr,那传过去的地址就是arr[7](已经越界)的地址,从arr[7]的位置开始向后统计,所以输出也是一个随机值

printf("%d\n", strlen(&arr[0]+1));

&arr[0]+1,表示数组第二个元素的地址,从数组第二个元素的位置开始向后统计,所以输出是一个随机值

相关文章
|
11天前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
40 0
|
2月前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
2月前
|
算法 测试技术
软件设计师软考题目解析24 --每日五题
这篇文章提供了软件设计师软考的每日五题解析,包括测试用例设计、软件维护类型、路径覆盖测试、软件维护工具和系统改进等知识点。
33 0
软件设计师软考题目解析24 --每日五题
|
2月前
|
项目管理
软件设计师软考题目解析20之英语题
软件设计师软考中英语题目的解析和答题技巧,帮助考生攻克英语部分的题目。
25 0
软件设计师软考题目解析20之英语题
|
2月前
|
存储 数据安全/隐私保护
软件设计师软考题目解析下午题01
这篇文章提供了对软件设计师软考下午题目的解析,涉及农业基地信息化管理服务平台的人员管理、基地管理、种植管理、投入品管理和信息服务功能,并要求考生根据上下文描述和数据流图来回答问题。
34 0
软件设计师软考题目解析下午题01
|
2月前
|
安全 算法 网络安全
软件设计师软考题目解析15 --每日五题
这篇文章是关于软件设计师软考的题目解析,包括防火墙功能、网络连接分析、DMZ区服务器类型、拒绝服务攻击特点以及公开密钥加密算法的选择题,旨在帮助考生准备考试。
32 0
软件设计师软考题目解析15 --每日五题
|
2月前
|
前端开发 数据处理
软件设计师软考题目解析23 --每日五题
每日五题解析,涉及结构化开发方法的特点、数据流图的基本加工、MVC体系结构的优点以及模块间耦合类型的判断等知识点。
18 0
|
2月前
|
算法 数据建模 数据库
软件设计师软考题目解析22 --每日五题
每日五题解析,涉及结构化开发方法中的接口设计依据、数据结构和算法设计、数据流图的使用场景、外部实体的识别以及决策树在数据流图中表示复杂条件逻辑的应用。
23 0
|
2月前
|
网络协议 PHP
软件设计师软考题目解析21 --每日五题
每日五题解析,包括海明码纠错、POP3协议通信模式、中断处理、HTML邮件链接创建和结构化开发方法中的接口设计等知识点。
17 0
|
2月前
|
测试技术
软件设计师软考题目解析19 --每日五题
这篇文章提供了软件设计师软考的每日五题解析,包括白盒测试方法、回归测试、面向对象开发方法、总线复用方式和海明码纠错等知识点。
16 0

推荐镜像

更多