指针和数组面试题(逐题分析,完善你可能遗漏的知识)

news2025/1/18 6:53:28

人生不是一种享乐,而是一桩十分沉重的工作。            —— 列夫·托尔斯泰

前言:之前我们就学习了数组和指针的知识。

数组:数组就是能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型

指针:指针就是存放地址的变量,称为指针变量。大小是4/8个字节(32位平台/64位平台)。

而数组和指针有什么联系呢?

数组名是首元素的地址,而地址存放在指针变量中,我们就可以使用指针变量来遍历数组。

而数组名是首元素的地址有两个特例:

1.如果数组名放在sizeof内部,也就是sizeof(数组名),这里的数组名表示整个数组,sizeof求的也就是整个数组的字节大小。

2.&数组名,取出的是整个数组的地址。

这里我们所用的是32位的平台,所以指针的大小都是4个字节。

接下来的题我们会用到sizeof操作符strlen函数。

细节:

1.sizeof计算的是占用内存空间的大小,单位是字节,不关注内存中到存放的是什么。

2.sizeof不是函数,是操作符。

3.strlen是函数,所用的头文件是#include<string.h>。

4.strlen是针对字符串的,求的是字符串长度,本质上统计的是/0之前出现的字符的个数。

5.strlen的参数是char*类型的,即指针。

第一类题:

int main()
{
    int a[] = { 1,2,3,4 };//数组的大小是4
    printf("%d\n", sizeof(a));//16个字节
    //a单独放在sizeof内部,表示整个数组,所以sizeof求的整个数组大小16字节

    printf("%d\n", sizeof(a + 0));//4个字节
    //a没有单独放在sizeof内部,也没有&,所以数组名表示数组首元素的地址
    //加0也是首元素的地址,也就是指针,大小是4

    printf("%d\n", sizeof(*a));//4个字节
    //a表示首元素地址,也就是&arr[0],*a也就是a[0],第一个元素的大小

    printf("%d\n", sizeof(a + 1));//4个字节
    //a表示首元素的地址,a+1表示第二个的地址,即指针大小

    printf("%d\n", sizeof(&a));//4个字节
    //&a表示取出整个数组的地址,但是还是地址,即指针的大小

    printf("%d\n", sizeof(*&a));//16个字节
    //*和&相当于抵消了,也就是表示sizeof(a),代表整个数组的大小

    printf("%d\n", sizeof(&a + 1));//4个字节
    //&a表示取出整个数组的地址,&a+1,跳过整个数组,但是还是地址,即指针的大小

    printf("%d\n", sizeof(&a[0]));//4个字节
    //取出第一个元素的地址,即指针的大小

    printf("%d\n", sizeof(&a[0] + 1));//4个字节
    //第二个元素的地址,即指针的大小
    return 0;
}


第二类题:

int main()
{
    char arr[] = { 'a','b','c','d','e','f' };
    printf("%d\n",sizeof(arr));//6个字节
    //arr单独放在sizeof内部,表示整个数组的大小

    printf("%d\n",sizeof(arr+0));//4个字节
    //arr表示数组首元素的地址,arr+0也是首元素地址,即指针大小

    printf("%d\n",sizeof(*arr));//1个字节
    //arr表示数组首元素的地址,&arr即arr[0]

    printf("%d\n",sizeof(arr[1]));//1个字节
    //表示第二个元素b

    printf("%d\n",sizeof(&arr));//4个字节
    //&arr取出的是整个数组地址

    printf("%d\n",sizeof(&arr+1));//4个字节
    //&arr取出整个数组地址,&arr+1,跳过整个数组,但还是地址,即指针的大小

    printf("%d\n",sizeof(&arr[0]+1));//4个字节
    //&arr[0]取出的是第一个数的地址,&arr[0]+1即第二个数的地址,即指针
    return 0;
}


#include<stdio.h>
#include<string.h>
int main()
{
    char arr[]= { 'a','b','c','d','e','f' };
    printf("%d\n",strlen(arr));//随机值
    //arr表示首元素的地址,strlen求得是首元素地址后面的字符个数
    //但是字符串没有\0存在,所以大小是随机值

    printf("%d\n",strlen(arr+0));//随机值
    //一样的是首元素的地址,求出的是随机值

    printf("%d\n",strlen(*arr));//error
    //*arr表示arr[0],即代表字符a,不是地址,代码错误

    printf("%d\n",strlen(arr[1]));//error
    //一样的不是地址,代码错误

    printf("%d\n",strlen(&arr));//随机值
    //&arr取出整个数组的地址,但是遇不到\0,大小是随机值

    printf("%d\n",strlen(&arr+1));//随机值-6
    //&arr+1跳过整个数组,得到的值是上面随机值-6

    printf("%d\n",strlen(&arr[0]+1));//随机值-1
    //&arr[0]+1代表第二个元素得地址,得到的值是上面随机值-1
    return 0;
}

    printf("%d\n",strlen(*arr));//error
    //*arr表示arr[0],即代表字符a,不是地址,代码错误

    printf("%d\n",strlen(arr[1]));//error
    //一样的不是地址,代码错误

出现这两种,strlen里面不是地址,编译器编译就会出现下面一样的错误:


第三类题: 

int main()
{
	char arr[] = "abcdef";
	//字符串末尾还隐藏了一个\0,所以数组大小为7

	printf("%d\n",sizeof(arr));//7个字节
	//arr单独放在sizeof内部,表示整个数组,大小为7

	printf("%d\n",sizeof(arr+0));//4个字节
	//arr表示首元素的地址,加0也是一样,即指针

	printf("%d\n",sizeof(*arr));//1个字节
	//arr表示&arr[0],*arr表示arr[0],大小是1

	printf("%d\n",sizeof(arr[1]));//1个字节
	printf("%d\n",sizeof(&arr));//4个字节
	//&arr取出整个数组的地址,但是还是地址,即指针

	printf("%d\n",sizeof(&arr+1));//4个字节
	//&arr+1跳过整个数组的地址,但还是地址,即指针

	printf("%d\n",sizeof(&arr[0]+1));//4个字节
	//表示第二个元素的地址
	return 0;
}


int main()
{
	char arr[] = "abcdef";
	printf("%d\n",strlen(arr));//大小是6
	//arr表示首元素的地址,求得是首元素到\0一共多少个字符

	printf("%d\n",strlen(arr+0));//大小是6
	printf("%d\n",strlen(*arr));//error
	//*arr表示arr[0]
	printf("%d\n",strlen(arr[1]));//error

	printf("%d\n", strlen(&arr));//大小是6
	//&arr整个数组的地址,但数值还是首元素的地址

	printf("%d\n", strlen(&arr+1));//大小是随机值
	//&arr+1表示跳过整个数组

	printf("%d\n", strlen(&arr[0]+1));//大小是5
	//表示第二个元素的地址
	return 0;
}


第四类题: 

char* p = "abcdef";

不代表是,但可以理解为:

char  arr[]="abcdef";

char*p=arr;

int main()
{
	char* p = "abcdef";
	//p表示首元素的地址
	//char arr[]="abcdef";
	//char* p = arr;
	printf("%d\n", sizeof(p));//4个字节
	//p是指针,大小是4

	printf("%d\n", sizeof(p+1));//4个字节 
	//p+1表示第二个元素b的地址,即指针

	printf("%d\n", sizeof(*p));//1个字节
	//p表示&arr[0],*p即arr[0],大小是1

	printf("%d\n", sizeof(p[0]));//1个字节
	//相当于arr[0],即第一元素

	printf("%d\n", sizeof(&p));//4个字节
	//&p表示取出一级指针的地址,跟字符串没关系,但是还是指针

	printf("%d\n", sizeof(&p+1));//4个字节
	//跳过一级指针p的全部地址

	printf("%d\n", sizeof(&p[0]+1));//4个字节
	//&p[0]相当于&arr[0],加1表示第二个元素的地址
	return 0;
}

 ​​​​​​


int main()
{
	char* p = "abcedf";
	printf("%d\n", strlen(p));//大小是6
	//p代表首元素的地址

	printf("%d\n", strlen(p + 1));//大小是5
	//p+1代表第二个元素的地址

	printf("%d\n", strlen(*p));//error
	//p表示&arr[0],*p着代表arr[0]

	printf("%d\n", strlen(p[0]));//error
	printf("%d\n", strlen(&p));//随机值
	//取出的是p的地址,跟字符串无关

	printf("%d\n", strlen(&p + 1));//随机值

	printf("%d\n", strlen(&p[0] + 1));//大小是5
	//代表第二个元素的地址
	return 0;
}


 

第五类题:

 二维数组:

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48个字节
	//a单独放在sizeof内部表示整个数组的大小

	printf("%d\n", sizeof(a[0][0]));//4个字节
	//表示第一个元素的大小
	printf("%d\n", sizeof(a[0]));//16字节
	//a[0]表示第一行的数组名。单独放在sizeof内部,即第一行的大小

	printf("%d\n", sizeof(a[0]+1));//4个字节
	//a[0]表示第一行的数组名,即数组首元素的地址,a[0]+1表示第一行第二个数的地址

	printf("%d\n", sizeof(*(a[0]+1)));//4个字节
	//代表第一行第二个数

	printf("%d\n", sizeof(a+1));//4个字节
	//二维数组的数组名首元素的地址,即表示第一行的地址

	printf("%d\n", sizeof(*(a+1)));//16个字节
	//第一行的四个数的大小

	printf("%d\n", sizeof(&a[0]+1));//4个字节
	//&a[0]代表取出第一行的地址,加1即第二行的地址

	printf("%d\n", sizeof(*a));//16个字节
	//a表示第一行的地址,*a即第一行的四个数

	printf("%d\n", sizeof(a[3]));//16个字节
	//感觉a[3]已经数组越界了,但是sizeof内部的值不会进行计算
	return 0;
}


 

第六类题: 

struct test
{
	int num;//4个字节
	char* name;//4个字节
	short date;//2个字节
	char ch[2];//2个字节
	short p[4];//8个字节
}*p=0x100000;//上面全部加起来就是20,所以这里结构体的大小就是20个字节
//这里我们假设p的地址就是0x100000
int main()
{
	printf("%p\n", p + 0x1);
	//结构体指针加1也就是跳过一个结构体,相当于加了十进制的20个字节,转换为16进制就是14
	//所以这里的地址就是0x100014,使用%p打印出来就是没有0x,前面再补两个0到8个比特位
	//结果就是00100014

	printf("%p\n", (unsigned long)p + 0x1);
	//unsigned long讲0x100000强制转换为无符号的整型为100000
	//加1也就是100001,最终结果就是00100001

	printf("%p\n", (unsigned int*)p + 0x1);
	//unsigned int*转换为无符号的指针
	//加1也就是加4,最终结果就是00100004
	return 0;
}

这就是全部的内容,希望能对你有所帮助。你们的支持就是我的动力,感谢! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux操作系统学习(进程等待)

文章目录进程等待进程等待的必要性如何进程等待waiwaitpid验证进程等待 ​ 我们知道fork函数可以创建一个子进程&#xff0c;而子进程通常是替父进程完成一些任务&#xff0c;而父进程在fork之后需要通过wait/waitpid等待子进程退出。这就是进程等待 进程等待的必要性 通过获…

Allegro如何导入第三方网表操作指导

Allegro如何导入第三方网表操作指导 在用Allegro做PCB设计的时候,除了支持第一方网表的导入,同样也是可以导入第三方网表的,第三方网表如下图 如何导入,具体操作如下 点击Setup点击User Preference

【抽水蓄能电站】基于粒子群优化算法的抽水蓄能电站的最佳调度方案研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

Linux操作系统学习(进程替换)

文章目录进程替换进程替换是什么&#xff1f;替换的方法进程替换简易shell模拟进程替换 进程替换是什么&#xff1f; 如下图所示&#xff1a; ​ 进程替换就是&#xff0c;把进程B的代码和数据&#xff0c;替换正在执行的进程A的代码和数据在内存中的位置&#xff08;若代码…

etcd集群通过 Leader 写入数据,为什么K8s HA集群中讲每个 kube-apiserver 只和本机的 ETCD 通信

写在前面 对这个我不太明白&#xff0c;所有在 stackOverflow 的请教了大佬这里分享给小伙伴理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整…

spark sql(二)sql解析流程扩展

1、前言 通过前面的文章我们了解到&#xff0c;spark sql通过catalyst框架解析sql&#xff0c;而在将sql语句转变为可执行的任务过程中会将大的sql解析流程划分为未解析的逻辑计划、解析后的逻辑计划、优化后的逻辑计划、物理计划、可执行物理计划等阶段。大概的解析流程如下所…

Handler与线程

简介 Handler提供的种异步消息处理机制是&#xff1a;当它发出一个消息进入消息队列后&#xff0c;发送消息的函数立刻返回&#xff0c;接着主线程会逐个地从消息队列中把消息取出&#xff0c;然后对消息进行处理。明显&#xff0c;Handler发送消息和接收消息是异步进行的&…

三八送什么数码产品好?适合送礼的数码产品

数码产品是我们生活中比较常见到的物品&#xff0c;相比较于一般礼物的观赏性&#xff0c;它的实用性更强一些&#xff0c;所以如果你不知道送什么礼物给别人的话&#xff0c;数码产品也是不错的选择。 一、南卡小音舱蓝牙耳机 这个时代的女性&#xff0c;变得越来越自信了&am…

ChatGPT解答:根据使用者输入的字符串,自动判断规则,并给出各种正则表达式,用Python实现

ChatGPT解答&#xff1a; 根据使用者输入的字符串&#xff0c;自动判断规则&#xff0c;并给出各种正则表达式&#xff0c;用Python实现 根据输入的字符串&#xff0c;自动给出正则表达式 根据使用者输入的字符串&#xff0c;自动判断规则&#xff0c;并给出各种正则表达式&am…

JVM系统优化实践(7):垃圾回收器与垃圾回收算法

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e;上回说到了年轻代、老年代与数据计算的一个案例。接下来就先讲一讲年轻代和老年代的两个垃圾回收器&#xff1a;ParNew和CMS。和Serial垃圾回收器一样&#xff0c…

实战:yaml方式安装ingress-nginx-2023.3.2(测试成功)

实战&#xff1a;yaml方式安装ingress-nginx-2023.3.2(测试成功) 目录 文章目录实战&#xff1a;yaml方式安装ingress-nginx-2023.3.2(测试成功)目录实验环境实验软件1、安装过程2、第一个示例关于我最后最后实验环境 实验环境&#xff1a; 1、win10,vmwrokstation虚机&#x…

AI_News周刊:第四期

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 News 1.对抗“唤醒人工智能”马斯克招募团队开发 OpenAI 竞争对手 据两位直接了解这项工作的人士和另一位了解情况的人士透露&#xff0c;埃隆马斯克最近几周与人工智能研究人员接洽&#xff0c;商讨成…

详细分析什么是进程?如何理解进程状态?

什么是进程&#xff1f; 比较官方一点的回答是&#xff1a;当一个程序加载到内存的时候&#xff0c;就是一个进程。 但是这是不准确的回答&#xff0c;进程是怎么在内存中形成的&#xff0c;以及内存是如何管理进程的&#xff0c;是通过什么描述进程的&#xff1f;下面我们将…

Neo4j数据库部署配置

这里写目录标题一、neo4j图形数据库安装与部署1.1配置JDK运行环境&#xff08;注意jdk与neo4j版本对应&#xff09;1.2部署Neo4j&#xff08;注意jdk与neo4j版本对应&#xff09;二、数据库基本操作演示一、neo4j图形数据库安装与部署 1.1配置JDK运行环境&#xff08;注意jdk与…

centos安装rocketmq

centos安装rocketmq1 下载rocketmq二进制包2 解压二进制包3 修改broker.conf4 修改runbroker.sh和runserver.sh的JVM参数5 启动NameServer和Broker6 安装rockermq dashboard(可视化控制台)1 下载rocketmq二进制包 点击rocketmq二进制包下载地址&#xff0c;下载完成之后通过ft…

javaEE 初阶 — 数据链路层中的以太网数据帧

文章目录以太网帧格式1. MAC 地址2. MAC 地址是如何与 IP 地址相互配合的3. 以太网帧格式中的类型MTU&#xff08;了解&#xff09;以太网帧格式 数据链路层主要考虑的是相邻的两个结点之间的传输。 这里最知名的协议就是 以太网。 一个以太网数据帧有三个部分组成。帧头载荷…

【GlobalMapper精品教程】055:GM坐标转换器的巧妙使用

GM软件提供了一个简单实用的坐标转换工具,可以实现地理坐标和投影坐标之间的高斯正反算及多种转换计算。 文章目录 一、坐标转换器认识二、坐标转换案例1. 地理坐标←→地理坐标2. 地理坐标←→投影坐标三、在输出坐标上创建新的点四、其他转换工具的使用一、坐标转换器认识 …

653600-56-7,Ac4GaINAz,N-叠氮四酰化半乳糖用于PROTAC合成

基础产品数据&#xff1a;CAS号&#xff1a;653600-56-7中文名&#xff1a;N-叠氮四酰化半乳糖&#xff0c;叠氮修饰半乳糖英文名&#xff1a; Ac4GaINAzAc4GaINAz结构式&#xff08;Structural&#xff09;&#xff1a;详细产品数据&#xff1a;分子式&#xff1a;C16H22N4O10…

python学习——【第二弹】

前言 上一篇文章 python学习——【第一弹】给大家介绍了python中的基本数据类型等&#xff0c;这篇文章接着学习python中的运算符的相关内容。 运算符 python中的运算符主要有&#xff1a;算术运算符&#xff0c;赋值运算符&#xff0c;比较运算符&#xff0c;布尔运算符以及…

NPP夜间灯光遥感数据读取与可视化

1、Google Earth EngineGoogle Earth Engine是Google推出的行星尺度的遥感云计算平台&#xff0c;提供了大量遥感数据的集成与运算工具。同时也包括DMSP和NPP夜间灯光遥感数据&#xff08;月尺度和年尺度&#xff09;。这里给出样例的可视化代码。var dataset ee.ImageCollect…