C语言指针进阶(3)

这节我们来总结一下指针和数组面试题。

在这节我们主要用到这样几个知识点:

1.数组名是数组首元素的地址。

但是有两个例外:

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

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

 第一组

//一维数组

 int a[] = { 1,2,3,4 };

printf("%d\n", sizeof(a));
//计算的是数组的大小,单位是字节,int类型是4个字节,所以结果是16个字节
printf("%d\n", sizeof(a + 0));
//a代表数组首元素地址,a+0仍然代表数组首元素地址,
//地址的大小统一是4/8个字节(取决于是X86还是X64环境)
printf("%d\n", sizeof(*a));
//a代表数组首元素地址,*a表示对数组首元素地址解引用
//所以结果是计算首元素大小,结果为4
printf("%d\n", sizeof(a + 1));
//a代表数组首元素地址,a+1代表跳过一个整形,代表第一个元素地址
//由于还是地址,所以大小仍然是4/8个字节
printf("%d\n", sizeof(a[1]));
//a[1]代表数组第二个元素,所以结果为4
printf("%d\n", sizeof(&a));
//&a代表数组的地址,为int(*)[4]类型
//但是不管怎么说,还是地址,所以仍然是4/8个字节
printf("%d\n", sizeof(*&a));
//第一个角度:&a代表数组的地址,是int(*)[4]类型
//*&a对数组的地址进行解引用,表示数组名,sizeof(数组名)代表整个数组的大小,16
//第二个角度:*和&可以抵消,相当于啥也没干,*&a==a,这就是脱裤子放屁了,sizeof(a),所以是16
printf("%d\n",sizeof(&a+1));
//&a表示数组的地址,&a+1跳过整个数组,得到下一个数组地址
//但是还是地址,4/8
printf("%d\n",sizeof(&a[0]));
//&a[0]得到a[0]的地址,地址都是4/8
printf("%d\n",sizeof(&a[0]+1));
//&a[0]是a[0]的地址,地址+1跳过地址类型长度
//得到的是a[1]的地址,但还是地址,4/8

 第二组

//字符数组
char arr[] = {'a','b','c','d','e','f'};

printf("%d\n", sizeof(arr));
//sizeof(数组名)统计的是数组的大小,单位是字节,6
printf("%d\n", sizeof(arr+0));
//sizeof(arr+0)不属于这篇博客最开始说的两种情况,
//因此arr表示数组首元素地址,arr+0还是数组首元素地址,4/8
printf("%d\n", sizeof(*arr));
//arr表示数组首元素地址,*arr表示对数组首元素地址解引用
//求的是数组首元素大小 大小是1个字节
printf("%d\n", sizeof(arr[1]));
//计算arr[1]的大小,大小也是1个字节
printf("%d\n", sizeof(&arr));
//&arr表示数组的地址,为char(*)[6]类型,
//数组地址也是地址,4/8
printf("%d\n", sizeof(&arr+1));
//&arr表示数组的地址,&arr+1表示跳过1个数组大小的下一个数组的地址
//地址大小就是4/8
printf("%d\n", sizeof(&arr[0]+1));
//&arr[0]表示arr中第一个元素的地址,再+1表示arr[1]的地址,4/8
printf("%d\n", strlen(arr));
//strlen统计的是\0之前的字符个数,因为字符数组arr中没有\0,
//所以在求字符串长度的时候,会一直往后找,产生的结果就是随机值
printf("%d\n", strlen(arr+0));
//arr+0表示数组首元素地址,和第一个一样,也是随机值
printf("%d\n", strlen(*arr));
//*arr表示'a',其ASCII码值为97,strlen函数参数需要传一个地址
//当我们传递的是'a'时,'a'的ASCII码值就是97,那就是将97作为地址传参
//strlen就会从97这个地址开始统计字符串的长度,这就是非法访问了err
printf("%d\n", strlen(arr[1]));//err
printf("%d\n", strlen(&arr));
//&arr表示的数组的地址,数组的地址和数组首元素地址,值是一样的
//传给strlen后,依然是从第一个元素开始找\0,
//所以仍然是随机值
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));
//第二的元素的地址,结果也是随机值

 第三组

char arr[] = "abcdef";

printf("%d\n", sizeof(arr));
//sizeof(数组名)计算的是数组的大小,单位是字节,大小是7个字节
printf("%d\n", sizeof(arr+0));//大小是4/8
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//char (*)[6],4/8
printf("%d\n", sizeof(&arr+1));//4/8
printf("%d\n", sizeof(&arr[0]+1));//4/8
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr+0));//6
printf("%d\n", strlen(*arr));//err
printf("%d\n", strlen(arr[1]));//err
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));//5

 第四组

char *p = "abcdef";

printf("%d\n", sizeof(p));
//p是char* 类型的指针,大小4/8个字节
printf("%d\n", sizeof(p+1));
//p+1指向b,仍然是地址,大小4/8
printf("%d\n", sizeof(*p));//1
printf("%d\n", sizeof(p[0]));//1
printf("%d\n", sizeof(&p));//&p表示字符指针p的地址,大小是4/8个字节
printf("%d\n", sizeof(&p+1));//4/8
printf("%d\n", sizeof(&p[0]+1));//4/8
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p+1));//5
printf("%d\n", strlen(*p));//err
printf("%d\n", strlen(p[0]));//err
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p+1));//随机值
printf("%d\n", strlen(&p[0]+1));//5

 第五组

//二维数组
int a[3][4] = {0};

printf("%d\n",sizeof(a));//48
printf("%d\n",sizeof(a[0][0]));//4
printf("%d\n",sizeof(a[0]));
//a[0]表示二维数组第一行的数组名,sizeof(数组名)j计算的是数组的大小,为16个字节
printf("%d\n",sizeof(a[0]+1));
//arr[0]是数组名,没有单独放在sizeof内部,没有&,
//数组名表示数组首元素地址,也就是a[0][0]的地址,+1表示arr[0][1]的地址
//4/8
printf("%d\n",sizeof(*(a[0]+1)));//4
printf("%d\n",sizeof(a+1));//4/8
//a是数组首元素的地址,是第一行的地址,int(*)[4]
//a+1就是第二行的地址
printf("%d\n",sizeof(*(a+1)));//16
//*(a+1)-->a[1]-->sizeof(*(a+1))-->sizeof(a[1])计算的第二行的大小
//a+1是第二行的地址,int(*)[4]
//*(a+1)访问第二行的值
printf("%d\n",sizeof(&a[0]+1));//4/8
//&a[0]是第一行地址 int(*)[4]
//&a[0]+1是第二行的地址
printf("%d\n",sizeof(*(&a[0]+1)));//16
//计算的是第二行的大小
printf("%d\n",sizeof(*a));//16
//计算的是第一行的大小
//a是数组首元素的地址,就是第一行的地址
//*a就是第一行的数组名
//*a --> *(a+0) --> a[0]
printf("%d\n",sizeof(a[3]));
//a[3]--> int [4]
//16

指针笔试题

笔试题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,5

 笔试题2

//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

第一个:p为结构体类型的指针,p+1跳过一个结构体类型,结构体大小是20个字节,所以0x100000+20 == 0x100014

第二个:把p转换为unsigned long,p就是无符号整形了,这时p+1表示真正加1,0x100001

第三个:把p强制转换成unsigned int*类型,p+1跳过unsigned int类型大小的字节,即+4,0x100004

00000014
00000001
00000004

笔试题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,2000000 

笔试题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;
}

 特别注意:这道题数组初始化的时候是(  ,),这是逗号表达式(0,1)的结果是1,以此类推

1

笔试题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;
}

&p[4][2] - &a[4][2]:指针-指针计算的是指针之间元素的个数(-4)

//10000000000000000000000000000100

//1111111111111111111111111111111111011

//1111111111111111111111111111111111100---以%p的形式打印出来FFFFFFFC

//以%d形式打印出来的是补码,因此是-4

FFFFFFFC, -4

笔试题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;
}

10,5

笔试题7

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

at

 笔试题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;
}

POINT
ER
ST
EW

 指针阶段到此结束,完结撒花!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在Windows本地快速搭建SFTP文件服务器,并通过端口映射实现公网远程访问

文章目录 1. 搭建SFTP服务器1.1 下载 freesshd服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内网连接测试成功 3 使用cpolar内网穿透3.1 创建SFTP隧道3.2 查看在线隧道列表 4. 使用SFTP客户端&#xff0…

四、MySQL(表操作)如何添加字段?修改表?删除字段?修改表名?删除表?格式化某张表?

1、添加字段 &#xff08;1&#xff09;基础语法&#xff1a; alter table 表名 add 字段名 类型名(长度) [comment注释] [约束]; &#xff08;2&#xff09;示例&#xff1a;添加nickname这个字段 2、修改表 修改表中某个字段的【数据类型】/【数据类型&字段名】 &…

c# - - - 安装.net core sdk

如图&#xff0c;安装的是.Net Core 2.2版本 查看安装成功

【Centos8_配置单节点伪分布式Spark环境】

安装centos8 jdk部署伪分布式spark环境 安装Centos8 环境下的JDK 下载jdk linux版本 下载链接&#xff1a; jdk-8u381-linux-x64.tar.gz 将该文件上传到Centos8 主机 部署配置jdk&#xff08;java8&#xff09; # 解压到指定路径 [lhangtigerkeen Downloads]$ sudo tar …

vite 配置自动补全文件的后缀名

vite 不建议自动补全&#xff0c;文件的后缀名的 const Home ()>import("/views/Home.vue");文件是必须要加上 .vue 的后缀名的 如果 想要像 webpack 一样的不用写&#xff0c; 可以在vite.config.js中配置如下就可以了

UDP通信、本地套接字

#include <sys/types.h> #include <sys/socket > ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);- 参数&#xff1a;- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度…

ElasticSearch-集成ik分词器

本文已收录于专栏 《中间件合集》 目录 背景介绍版本选择优势说明集成过程1.下载安装包2.解压安装包3.重启ElasticSearch服务3.1通过ps -ef | grep elastic查看正在启动的es进程号3.2使用kill -9 xxx 杀死进程3.3使用 ./elasticsearch 启动es服务 分词测试细粒度分词方式分词请…

删除命名空间一直处于Terminating

删除命名空间一直处于Terminating 通常删除命名空间或者其他资源一直处于Terminating状态&#xff0c;是由于资源调度到的节点处于NotReady状态&#xff0c;需要将节点重新加入到集群使其状态变为Ready状态才能解决问题&#xff0c;当node重新加入处于Ready状态后&#xff0c;…

Linux centos7 bash编程(break和continue)

在学习shell知识时&#xff0c;简单编程要从格式入手。 首先学习好单行注释和多行注释。 先学习简单整数的打印输出&#xff0c;主要学习echo命令&#xff0c;学习选项-e -n的使用。 下面的练习是常用的两个分支跳转程序&#xff1a;break和continue。 #!/bin/bash # 这是单…

贪心算法总结篇

文章转自代码随想录 贪心算法总结篇 我刚刚开始讲解贪心系列的时候就说了&#xff0c;贪心系列并不打算严格的从简单到困难这么个顺序来讲解。 因为贪心的简单题可能往往过于简单甚至感觉不到贪心&#xff0c;如果我连续几天讲解简单的贪心&#xff0c;估计录友们一定会不耐…

dayjs格式转换成日期

目录 方法一&#xff1a; ​编辑方法二&#xff1a; 这个项目在筛选订单时间的时候是由前端进行筛选的&#xff0c;用的是adt-design-pro进行二开的&#xff0c;其中在用日期组件的时候遇到了一个问题&#xff0c;组件返回的是&#xff1a; 但是我需要的是年-月-日&#xff…

正则表达式学习笔记

正则表达式学习笔记 常用正则表达式 1、匹配字母 Pattern patternPattern.compile("[a-zA-Z]"); 2、匹配数字 Pattern patternPattern.compile("[0-9]"); 3、匹配字母和数字 Pattern patternPattern.compile("([0-9])|([a-zA-Z])")…

本地电脑搭建Plex私人影音云盘教程,内网穿透实现远程访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语6 总结 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特…

PageHelper实现SpringBoot+Mybatis中的数据分页查询

1、通过PageHelper实现数据分页查询&#xff08;SpringBootMabatis&#xff09;。首先&#xff0c;在pom.xml中导入pagehelper相关依赖。 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</arti…

ChatRWKV 学习笔记和使用指南

0x0. 前言 Receptance Weighted Key Value&#xff08;RWKV&#xff09;是pengbo提出的一个新的语言模型架构&#xff0c;它使用了线性的注意力机制&#xff0c;把Transformer的高效并行训练与RNN的高效推理相结合&#xff0c;使得模型在训练期间可以并行&#xff0c;并在推理…

Typora导出的PDF目录标题自动加编号

Typora导出的PDF目录标题自动加编号 在Typora主题文件夹增加如下文件后&#xff0c;标题便自动加上了编号&#xff1a; https://gitcode.net/as604049322/blog_data/-/blob/master/base.user.css 例如&#xff1a; 但是导出的PDF中&#xff0c;目录却没有编号&#xff1a; 这…

Spooling的原理

脱机技术 程序猿先用纸带机把自己的程序数据输入到磁带中&#xff0c;这个输入的过程是由一台专门的外围控制机实现的。之后CPU直接从快速的磁带中读取想要的这些输入数据。输出也类似。 假脱机技术&#xff08;Spooling技术&#xff09; 即用软件的方式来模拟脱机技术。要…

三星申请新商标:未来将应用于智能戒指,作为XR头显延伸设备

三星最近向英国知识产权局提交了名为“Samsung Curio”的新商标&#xff0c;这预示着三星正积极扩展可穿戴设备生态。该商标被分类为“Class 9”&#xff0c;这表明它有可能被用于未来的智能戒指。 据报道&#xff0c;三星计划将智能戒指作为XR头显设备的延伸&#xff0c;与苹果…

Jmeter(三十一):制造大批量的用户数据数据

需求&#xff1a;因测试需要&#xff0c;要造100w用户数据&#xff0c;通过用户名、手机号、密码可新增用户&#xff0c;其中用户名和电话号码要求100w用户不能重复 要点&#xff1a; 1、通过Bean shell Sampler实现用户名和手机号的足够随机。 符合我们常用规则的手机号&#…

DELL Power Edge R740 安装 OracleLinux-R7-U9-Server

一、准备好 OracleLinux-R7-U9-Server-x86_64-dvd 安装介子&#xff1a; 二、通过 iDRAC挂dvd 安装介子 三、在 iDRAC 开机控制选择虚拟 CD/DCD/ISO 电源控制选择 复位系统&#xff08;热启动&#xff09; 四、进入安装阶段 五、配置时区 六、配置磁盘 七、删除之前的旧分区 …