指针面试题详解

news2024/11/25 11:01:17

目录

前言(数组名的总结):

一、int 型数组和 sizeof 的组合

sizeof计算原理

 二、char类型和strlen()组合

三、char*类型和sizeof()组合(有 '\0' 版本)

四、char*类型和strlen()组合(有 '\0' 版本)

五、二维数组和sizeof()组合


前言(数组名的总结):

因为本文章大部分与数组名有关,我们首先温习一下数组名的知识,数组名通常都表示数组的首元素地址,但是有两个例外:

  • &数组名,这里的数组名就表示整个数组的地址
  • sizeof(数组名),这里的数组名也表示整个数组的地址

除上述两种特殊情况外,其余我们见到的数组名都表示数组的首元素地址。

一、int 型数组和 sizeof 的组合

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

此时的数组名就是表示整个数组的地址,所以计算结果就是4*4=16

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

此时的数组名不是两种特殊情况,因此就表示数组的首元素地址,+0无效果,所以最终还是数组的首元素地址,因此答案4/8个字节(指针的大小)

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

此时数组名也表示数组的首元素地址,然后解引用*就是数组的第一个元素,也就是4个字节

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

 这个数组名也表示数组的首元素地址,然后+1,因为a是int *类型,+1就跳过一个int类型的大小,所以a+1就表示数组的第二个元素的地址,答案是4/8(指针大小)

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

 此时的数组名确实表示整个数组的地址,但他本质上还是一个指针,不能在门缝里看指针,把指针看扁了,无论什么类型的指针,他的大小都是4/8个字节!

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

* 和 & 是两个相逆的运算,相当于求导和求微分的意思,所以这两个在一起,就可以抵消。

因此*&a==a

而我们上面已经讲过,答案就是4*4

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

&a+1 相较于 &a 跳过了整个数组,但本质上还是地址,所以结果是4/8

sizeof计算原理

sizeof只需要知道数据类型是什么,不需要访问内存去计算,甚至sizeof(int),这样的表达式也是可以的 

 二、char类型和strlen()组合

首先我们明确,strlen计算字符串的长度,计算的是\0之前出现的字符的个数

	char arr[] = { 'a','b','c','d','e','f' };

注意这一种初始化方式,内存中存储的是

a b c d e f

后面内容未知,前面内容也未知。

	strlen(arr);

因为arr里面没有存放\0,所以strlen会一直向后寻找,直到找到为止,而后面存储的内容我们是未知的,因此最后结果就是随机值。

	strlen(arr + 0);

表示的仍然是首元素的地址,跟第一个一样,因此结果也是随机值

	strlen(*arr);

这样写是非法的!

因为strlen()需要的参数是字符指针类型,而我们将*arr也就是数组的第一个元素 'a' 作为参数传递进去,转换为97,而strlen会将97作为地址访问,而97并不是我们的地址,所以就造成了非法访问内存了。

	strlen(arr[1]);

这一题跟上一题一样,都是非法访问内存,是错误的。

	strlen(&arr);

我们首先需要明确&arr,和数组的首元素的地址值是一样的。

但是类型不一样,前者是 char (*) [ ],后者是 char* 。

但是我们将地址传到strlen之后,函数会将地址自动转换为想要的const char* 

因此,还是会从数组的首元素开始访问,答案也就是随机值

	strlen(&arr + 1);

这题表示跳过了整个数组,答案也就是随机值,并且跟上一题的结果有联系,相差6,因为跳过整个数组,数组的6个字符元素。

三、char*类型和sizeof()组合(有 '\0' 版本)

	char* p[] = { "abcdef" };//字符串已经含有'\0'

把字符串首元素a的地址赋给arr。 

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

注意这里的p不是数组名,他本质上就是一个指针变量,所以结果就是4/8个字节

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

首先表示字符串第二个元素的地址,因为 p是char* 类型,所以p+1就跳过一个字符的大小,所以就是b的地址。是地址就是4/8个字节

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

因为p存储的是字符串首元素的地址,所以解引用就是字符串的首元素,因此结果就是一个字符的大小——1

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

答案是显而易见的,仍然是地址(4/8),但这题的关键在于&p+1到底指向哪里?

我们首先明确&p的类型是char **,p的类型是char*。

+1就跳过char*的内容,而char*的内容指向的是p,所以+1就跳过p,最终指向的是p后面

注意字符串首元素的地址和p的地址是两码事,是两块不同的内存空间

四、char*类型和strlen()组合(有 '\0' 版本)

	char* p[] = { "abcdef" };//字符串已经含有'\0'
	printf("%d\n", strlen(p));

到\0前面停止,就是6个字符

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

p是a的地址,+1就是b的地址,所以结果就是6-1=5

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

此时输入是非法的,因为*p就是把a传进去,而strlen需要一个字符指针。

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

p的地址和字符串存的地址没有任何关系,也是随机值

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

也是随机值,但与&p有没有关系呢?

其实并没有关系,因为p是一个地址,4/8个字节,我们并不能确定这4~8个字节里面是否含有\0,如果有,那这两者无任何关系

五、二维数组和sizeof()组合

	int arr[3][4] = { 0 };

 

二维数组在内存中的存储方式就是这样的。

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

注意此时的数组名直接放在了sizeof里面,所以就是表示整个数组3*4*4=48

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

 TIP:

在二维数组中,我们认为第一行就是第一个元素

arr[0]:二维数组第一行这个一维数组的数组名

arr[1]:二维数组第二行这个一维数组的数组名

arr[2]:二维数组第三行这个一维数组的数组名

以此类推……

所以此时的arr[0]就是二维数组第一行的数组名,既然又是数组名,那么就仍表示整个数组

4*4=16

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

首先arr[0]并没有单独放在sizeof()内部,也没有&arr,所以此时的arr[0]就表示数组第一行的首元素地址,也就是arr[0][0]的地址,再+1就表示arr[0][1]的地址,结果是4/8个字节

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

arr是表示数组的首元素地址,但这是二维数组,所以首元素也就是二维数组的第一行的地址

再+1就表示第二行整体的地址,是地址就是4/8个字节、

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

第一种思路:

*(arr+1)==arr[1],这两者互相转换,所以我们把arr[1]单独放在sizeof()内部就表示整个第二行的数组,所以就是4*4

第二种思路:

上一题我们讲过arr+1就是数组的第二行元素的地址,类型是int (*) []是数组指针,而我们对数组指针解引用,访问的就是整个数组。4*4

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

&arr[0]表示的二维数组第一行的地址,再+1就表示第二行的地址。4/8

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

我们由上一题已经直到&arr[0]+1就表示数组的第二行地址,再解引用就是整个第二行元素的大小4*4

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

因为数组名没有单独放在sizeof(),也没有&,所以就表示数组的首元素地址,在二维数组中也就是第一行的地址,然后解引用,计算整个第一行,4*4

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

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

相关文章

【干货】Mysql解决中文乱码

登录数据库后,选择数据库然后执行 MariaDB [test]> status; -------------- mysql Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1Connection id: 6 Current database: test Current user: rootlocalhost SSL: …

开源人力资源管理系统OrangeHRM

什么是 OrangeHRM ? OrangeHRM 是一个全面的人力资源管理(HRM) 系统,它包含任何企业所需的所有基本功能。该软件旨在支持任何规模的团队,包括初创企业、中小企业以及大型跨国组织。 你也可以去官方的演示站点进行体验 网址:https…

【Java】一文学透四种内部类|保姆级详解,一看就会

文章目录 一、什么是内部类?二、内部类的分类2.1:成员内部类(实例内部类)2.1.1:定义:2.1.2:特性2.1.3:实现原理:2.1.4:应用场景: 2.2:…

字节跳动-抖音支付大量招聘实习生

字节跳动-抖音支付大量招聘实习生 字节跳动-抖音支付大量招聘实习生 要求:2024年6月毕业且有时间来实习(大于3个月)的在校学生(本三,研二),日常和暑期都有转正机会~ 职位描述&…

WPF 自定义控件完成库容表盘显示效果

先看一下显示效果: 需要注意的地方有以下几点: 表盘的刻度分部,长刻度和短刻度显示。在数值80W时,需要更改刻度盘的颜色渐变。在数值80W时,更改库容总数背景的显示,也是颜色渐变。刻度盘控件属性定义&…

印刷企业如何利用MES管理系统实现智能计划排产

在数字化时代,印刷企业面临着日益激烈的市场竞争和不断攀升的成本压力。为了提高生产效率和质量,印刷企业需要采用先进的生产管理系统。其中,MES生产管理系统已成为实现智能计划排产的重要工具。本文将探讨如何利用印刷MES管理系统实现印刷企…

界面控件DevExtreme PivotGrid,拥有新的HTML编码体验!

虽然DevExtreme刚刚发布了v23.1,但今天我们仍然要继续总结一下之前的主要更新(v22.2)中发布的一些与DevExtreme PivotGrid(透视网格)组件相关的重要特性。 DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#…

Django + Bootstrap - 【echart】 统计图表进阶使用-统计用户日活日增、月活月增等数据(二)

一. 前言 Bootstrap是一个流行的前端框架,而ECharts是一个流行的可视化库。 Bootstrap可以用来设计网站和应用程序的用户界面,而ECharts可以用来创建交互式和可视化的图表。 chart.js中文文档:http://www.bootcss.com/p/chart.js/docs/ 二. …

手把手教你搭建SpringCloud项目(六)Eureka实现服务发现

一、服务发现简介 各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件上(eureka,zookeeper,Consul),服务发现组件会存储这些信息。服务消费者会从服务发现组件查询服务提供者的网络地址,然后根据该地址调用服务提供者的接口。各个微服务与服务…

centos升级龙蜥

centos升级龙蜥 龙蜥简介龙蜥官方社区centos升级龙蜥首先确认自己的centos版本下载迁移镜像源安装epel源迁移工具安装i686包查看执行迁移脚本结果查看重启机器查看系统信息 龙蜥简介 2021年10月19日的大会上,阿里云发布全新操作系统“龙蜥”并宣布开源。龙蜥操作系…

SAP与顺丰快递接口签名验证加密ABAP程序例子(MD5加密、转换为Base64字符串) <转载>

原文链接:http://www.baidusap.com/abap/7408 1, 顺丰平台数字签名简介 SAP系统和顺丰快递平台中的API接口对接时,需要将传输的JSON字符串进行数字签名加密。数字签名具体使用的是MD5方式,格式如下:msgData(业务报文&a…

DOM编程

DOM编程 DOM树: 获取DOM对象的方式: 通过id直接获取 id禁止使用,因为项目都是css、html、js分离的 2、通过API,doucument.getElementById 3、通过class,doucument.getElementsByClassName 4、通过标签名称&#xff0…

【框架篇】Bean作用域和生命周期

Bean作用域和生命周期 一,Bean作用域 Bean作用域指的是在Spring框架中,定义了Bean实例的创建和销毁方式,以及可以访问该实例的范围,并决定了每次通过容器获取Bean时返回的是同一个实例还是不同的实例。 1.1,Bean作用…

mysql 2 -- 数据库基本操作、数据表的操作、mysql查询操作

一、数据库基本操作 1、数据库的登录及退出 连接数据库: mysql -u用户名 -h主机地址(省略代表本机) -p 密码(格式为123...);注: 刚下载安装的时候需要通过管理员进入 退出数据库,以下三种方式都可以: exit quit …

Spring:表达式语言

Spring EL 概述使用概述 Spring 表达式(Spring EL) 是一种功能强大的表达式语言,以 #{ 表达式 } 作为定界符,用于在运行时对对象进行访问和操作。通过使用 Spring 表达式达到简化开发、减少逻辑或配置的编写的目的。 使用 Spring EL 主要可以引用 bean ,调用其属性和方…

苹果手机备忘录如何导入新手机?手机备忘录怎么转移?

一般来说,大多数手机用户更换手机的频率是3—5年,在一部手机使用了几年之后,就会出现内存不足、系统卡顿、电池续航时间较短等问题,这时候就需要更换新的手机了。有不少苹果手机用户在更换新手机的时候,都很发愁一个问…

Hugging News #0717: 开源大模型榜单更新、音频 Transformers 课程完成发布!

每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…

TypeScript 学习笔记(六):索引签名类型、映射类型

一、索引签名类型 1. 索引类型查询操作符 keyof keyof可以用于获取某种类型的所有键,其返回类型是联合类型。 interface Info {name: string;age: number; } let infoProp: keyof Info; infoProp "name"; infoProp "age"; infoProp "…

知识普及:Boc-Hynic,133081-25-1,6-叔丁氧羰肼基-3-吡啶甲酸,

(文章资料汇总来源于:陕西新研博美生物科技有限公司小编MISSwu)​ Boc-Hynic,6-[2-(tert-Butoxycarbonyl)hydrazinyl]nicotinic acid,6-[2-(叔丁氧羰基)肼基]烟酸,6-叔丁氧羰肼基-3-吡啶甲酸 ------------…

追梦之旅【数据结构篇】——C语言手撕八大经典排序

追梦之旅【数据结构篇】——C语言手撕八大经典排序😎 前言🙌排序的认识排序的稳定性:排序的时间复杂度和空间复杂度以及如何选择适合的排序: 优化版选择排序冒泡排序普通版冒泡排序升级版冒泡排序 直接插入排序希尔排序堆排序快速…