C语言--指针深入理解--题目篇

C语言--指针深入理解--题目篇

  • 1. sizeof 与 strlen 比较
    • 1.1 sizeof
    • 1.2 strlen
    • 1.3 数组名的意义
  • 2. 数组和指针笔试题解析(均以x86环境为例)
    • 2.1 ⼀维数组
    • 2.2 字符数组
    • 2.3 二维数组
  • 3. 指针运算笔试题解析

1. sizeof 与 strlen 比较

1.1 sizeof

sizeof 计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。

sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。

#inculde <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));//结果为 4printf("%d\n", sizeof a);//结果为 4printf("%d\n", sizeof(int));//结果为 4return 0;
}

上述代码结果均为 4.

1.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

size_t strlen ( const char * str );

strlen 统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。

#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};//结尾没有\0,会造成越界char arr2[] = "abc";//a b c \0  共4个元素//结尾自带\0,不会越界printf("%d\n", strlen(arr1));//结果为随机值,因为越界了printf("%d\n", strlen(arr2));//结果为3printf("%d\n", sizeof(arr1));//结果为3printf("%d\n", sizeof(arr2));//结果为4,\0也算作一个字符return 0;
}

1.3 数组名的意义

  1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩
  2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址
  3. 除此之外所有的数组名都表⽰⾸元素的地址

2. 数组和指针笔试题解析(均以x86环境为例)

2.1 ⼀维数组

int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));//a 为数组名,表示整个数组,计算的是整个数组的大小,结果为 16 (字节)printf("%d\n", sizeof(a + 0));//括号中不只是有数组名 a ,此时 a 仅表示数组中首元素的地址//加 0 之后仍表示首元素的地址,地址的大小在x86环境下是4个字节,结果为4printf("%d\n", sizeof(*a));//*a 表示数组中第一个元素,元素类型是 int 类型,结果为4printf("%d\n", sizeof(a + 1));//括号中不只是有数组名 a ,此时 a 仅表示数组中首元素的地址//加 1 之后表示第二个元素的地址,地址的大小在x86环境下是4个字节,结果为4printf("%d\n", sizeof(a[1]));//a[1] 表示数组中第二个元素,元素类型是 int 类型,结果为4printf("%d\n", sizeof(&a));//&a 是整个数组的地址,数组的地址也是地址,结果为 4printf("%d\n", sizeof(*&a));//&arr 是整个数组的地址,*(&a)则是对整个数组的解引用,等价于a,结果为16printf("%d\n", sizeof(&a + 1));//&a+1 跳过了整个数组,指向了数组的后边的地址,结果为4printf("%d\n", sizeof(&a[0]));//&a[0]是数组第一个元素的地址,结果为4 printf("%d\n", sizeof(&a[0] + 1));//&a[0]是数组第一个元素的地址,&a[0]+1 指向第二个元素的地址,结果为4 return 0;
}

2.2 字符数组

代码1:

char arr[] = {'a','b','c','d','e','f'};//arr数组中有6个元素
printf("%d\n", sizeof(arr));
//arr表示整个数组,此时数组中结尾没有\0,结果为6
printf("%d\n", sizeof(arr+0));
//括号中不只是有数组名 arr ,此时 arr 仅表示数组中首元素的地址
//加 0 之后仍表示首元素的地址,地址的大小在x86环境下是4个字节,结果为4
printf("%d\n", sizeof(*arr));
//*arr 是数组的首元素,这里计算的是首元素的大小,结果为1
printf("%d\n", sizeof(arr[1]));
//arr[1]是数组的首元素,这里计算的是首元素的大小,结果为1
printf("%d\n", sizeof(&arr));
//&arr 是整个数组的地址,数组的地址也是地址,结果为 4
printf("%d\n", sizeof(&arr+1));
//&arr+1 跳过了整个数组,指向了数组的后边的地址,结果为4
printf("%d\n", sizeof(&arr[0]+1));
//&arr[0]是数组第一个元素的地址,&arr[0]+1 指向第二个元素的地址,结果为4 

代码2:

char arr[] = {'a','b','c','d','e','f'};//arr数组中有6个元素,但无"\0"
printf("%d\n", strlen(arr));
//arr 为数组首地址,因为数组中无“\0",结果为随机值
printf("%d\n", strlen(arr+0));
//arr+0 仍为数组首地址,因为数组中无“\0",结果为随机值
printf("%d\n", strlen(*arr));
//将一个具体字符放入strlen函数中,相当于将其ASCII值放入函数中
//*arr结果为字符'a',相当于将97放入strlen中,这是一种错误的用法
printf("%d\n", strlen(arr[1]));
//将一个具体字符放入strlen函数中,相当于将其ASCII值放入函数中
//*arr结果为字符'b',相当于将98放入strlen中,这是一种错误的用法
printf("%d\n", strlen(&arr));
//&arr虽然是整个数值的地址,但也是指向数组的起始位置,数组中无“\0",结果为随机值
printf("%d\n", strlen(&arr+1));
//&arr+1指向整个数组地址的下一个地址,无法预料结果,结果为随机值
printf("%d\n", strlen(&arr[0]+1));
//&arr[0]+1指向第二个元素的地址,但数组中无“\0",结果为随机值

代码3:

char arr[] = "abcdef";//arr数组中有7个元素:a b c d e f \0
printf("%d\n", sizeof(arr));
//此处arr表示整个数组,结果为 7
printf("%d\n", sizeof(arr+0));
//arr+0是数组首元素的地址,地址的大小在x86环境下是4个字节
printf("%d\n", sizeof(*arr));
//*arr 是数组的首元素,这里计算的是首元素的大小,结果为1
printf("%d\n", sizeof(arr[1]));
//arr[1]是数组的首元素,这里计算的是首元素的大小,结果为1
printf("%d\n", sizeof(&arr));
//&arr 是整个数组的地址,数组的地址也是地址,结果为 4
printf("%d\n", sizeof(&arr+1));
//&arr+1 跳过了整个数组,指向了数组的后边的地址,结果为4
printf("%d\n", sizeof(&arr[0]+1));
//&arr[0]是数组第一个元素的地址,&arr[0]+1 指向第二个元素的地址,结果为4 

代码4:

char arr[] = "abcdef";//arr数组中有7个元素:a b c d e f \0
//strlen 遇到\0 就会停下来
printf("%d\n", strlen(arr));
//arr是数组首元素地址,结果为6
printf("%d\n", strlen(arr+0));
//arr+0 是数组的首元素的地址,结果为6
printf("%d\n", strlen(*arr));
//将一个具体字符放入strlen函数中,相当于将其ASCII值放入函数中
//传递的是’a'-97//error
printf("%d\n", strlen(arr[1]));
//将一个具体字符放入strlen函数中,相当于将其ASCII值放入函数中
//传递的是’b'-98//error
printf("%d\n", strlen(&arr));
//&arr虽然是整个数值的地址,但也是指向数组的起始位置,结果为6
printf("%d\n", strlen(&arr+1));
//&arr+1 跳过了整个数组,指向了数组的后边的地址,结果为随机值
printf("%d\n", strlen(&arr[0]+1));
//&arr[0]+1是第二个元素的地址,从第二个元素开始计算,结果为5

代码5:

char *p = "abcdef";//p存放的是第一个字符'a' 的地址,结尾仍有一个'\0'
printf("%d\n", sizeof(p));
//p是指向'a'的指针,sizeof计算的是一个地址,结果为4
printf("%d\n", sizeof(p+1));
//p+1是指向'b'的指针,sizeof计算的是一个地址,结果为4
printf("%d\n", sizeof(*p));
//*p就是'a',大小为一个字节
printf("%d\n", sizeof(p[0]));
//p[0]=*(p+0)=*p,就是'a',大小为一个字节
printf("%d\n", sizeof(&p));
//&p是指针p的地址,仍旧是一个地址,大小为4个字节
printf("%d\n", sizeof(&p+1));
//&p+1是指向指针p后面空间的地址,仍旧是一个地址,大小为4个字节
printf("%d\n", sizeof(&p[0]+1));
//&p[0]+1是'b'的地址,是地址大小就是4个字节

代码6:

char *p = "abcdef"; // a b c d e f \0
printf("%d\n", strlen(p));
//p存放的是第一个字符'a' 的地址
//strlen会根据第一个元素的地址找到其他所有数据,直到遇到\0,结果为6
printf("%d\n", strlen(p+1));
//p+1存放的是第2个字符'b' 的地址,从第二个元素开始,结果为5
printf("%d\n", strlen(*p));
//*p是'a',是将a的ASCII值传入strlen中,错误用法,err
printf("%d\n", strlen(p[0]));
//p[0]是'a',是将a的ASCII值传入strlen中,错误用法,err
printf("%d\n", strlen(&p));
//&p是首元素地址的地址,会得到随机值
printf("%d\n", strlen(&p+1));
//&p+1是首元素地址的后面一个地址,会得到随机值
printf("%d\n", strlen(&p[0]+1));
//&p[0]+1指向的是第二个元素的地址,从第二个元素开始计算,结果为5

2.3 二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));
//数组名单独放在sizeof内部,计算的是整个数组的大小
//一共12个元素,共12*4=48个字节
printf("%d\n",sizeof(a[0][0]));
//a[0][0]是第一个元素,大小为4个字节
printf("%d\n",sizeof(a[0]));
//a[0]是第一行这个一维数组的数组命,数组命单独放在sizeof内部了
//计算的是第一行的大小,共16字节
printf("%d\n",sizeof(a[0]+1));
//a[0]是第一行这个一维数组的数组命,这里表示数组首元素
//也就是a[0][0]的地址,a[0]+1是a[0][1]的地址,大小为4个字节
printf("%d\n",sizeof(*(a[0]+1)));
//a[0]+1是a[0][1]的地址,*(a[0]+1)是第一行第二个元素,大小为4
printf("%d\n",sizeof(a+1));
//a是二维数组的数组名,但这里没有&,也没有单独放在sizeof内部
//所以这里a是数组第一行的地址,a+1是第二行的地址,大小为4个字节
printf("%d\n",sizeof(*(a+1)));
//*(a+1)==>a[1]--第二行的数组名,单独放在sizeof内部,计算的是第二行的大小,共16个字节
printf("%d\n",sizeof(&a[0]+1));
//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,大小为4个字节
printf("%d\n",sizeof(*(&a[0]+1)));
//访问的是第二行,计算的是第二行的大小,共16个字节
printf("%d\n",sizeof(*a));
//a是第一行的地址,*a就是第一行,sizeof(*a)计算的是第一行的大小,16个字节
printf("%d\n",sizeof(a[3]));//这里不存在越界
//因为sizeof 内部的表达式不会真实计算的,它只会根据类型进行计算
//计算的是第4行的大小--16

3. 指针运算笔试题解析

题目1:

#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;
}

&a是将整个数组的地址,&a+1是数组地址后面的地址,所以ptr指向数组后面的一个地址,ptr-1指向的就是数组中最后一个元素
a+1中,a是首元素的地址,a+1指向第二个元素的地址
上面结果为 25

题目2:

/在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

结构体中将0x100000这个十六进制数强制转化为了结构体类型的地址,并将其赋给了结构体指针p,即此时p存放的是地址0x100000
0x1是十六进制表示的1,p+0x1即为p表示的地址往后移动一个相同类型大小的地址,即往后移动20(结构体的大小)个字节。
(unsigned long) p是将p强制转换成无符号长整型类型,仍属于整型,(unsigned long)p + 0x1表示该整型加 1
(unsigned int*)p是将p强制转换成了无符号整型指针,指针加1,往后移动该类型大小的指针,即往后移动4个字节
本题结果为:
0x100000+1=ox100014十六进制中,二十表示为0x000014
0x100000+1=ox100001
0x100000+1=ox100004

题目3:

#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;
}

二维数组中存放的是逗号运算,实际结果为a[3][2]={1,3,5}
a[0]表示的是二维数组第一行数组的地址,即p中放的是第一行的数组{1,2}
p[0]表示的是p代表数组的首元素,即1.

题目4:

#include <stdio.h>
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;
}

如下图,&aa+1指向的是数组后面地址的位置,aa+1指向的是第二行的地址
int *ptr1 = (int *)(&aa + 1);表示将&aa+1指向的地址强制转换成 int* 类型,并赋值给ptr1
int *ptr2 = (int *)(*(aa + 1));表示将aa+1指向的地址强制转换成 int* 类型,并赋值给ptr2
*(ptr1 - 1)指向的是数组最后一个元素,即10
*(ptr2 - 1)指向的是数组第一行最后一个元素,即5
在这里插入图片描述

题目5:

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

如下图,pa最开始指向的是数组a的首地址,p++
在这里插入图片描述

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

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

相关文章

FPGA未解之谜

一.ila一会能加载出波形&#xff0c;一会加载不出波形——在自己做的v7开发板中遇到&#xff0c;其他开发板从未遇到过 1.小梅哥说&#xff1a;可能与硬件jtag连接不稳定导致。

DRF从入门到精通二(Request源码分析、DRF之序列化、反序列化、反序列化校验、序列化器常用字段及参数、source、定制字段、保存数据)

文章目录 一、Request对象源码分析区分原生request和新生request新的request还能像原来的reqeust一样使用吗源码片段分析总结&#xff1a; 二、DRF之序列化组件序列化介绍序列化步骤序列化组件的基本使用反序列化基本使用反序列化的新增反序列化的新增删除单条 反序列化的校验序…

【Linux笔记】网络操作命令详细介绍

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux学习 ⛳️ 功不唐捐&#xff0c;玉汝于成 前言&#xff1a; 网络操作是Linux系统中常见的任务之一&#xff0c;它涵盖了测试网络连接、配置网络接口、显示网络统计信息以及远程登录和文件传…

RabbitMQ笔记(高级篇)

RabbitMQ笔记_高级篇 问题代码准备1. 新建生产者2. 新建消费者 RabbitMQ 高级特性1. 消息的可靠投递☆1.1 两种模式1.2 测试confirm 确认模式1.3 测试return 退回模式1.4 小结 2. Consumer ACK☆2.1 三种ACK2.2 测试手动ACK2.3 小结2.4 消息可靠性总结 3. 消费端限流测试消费端…

【即插即用篇】YOLOv8改进实战 | 引入 Involution(内卷),用于视觉识别的新一代神经网络!涨点神器!

YOLOv8专栏导航:点击此处跳转 前言 YOLOv8 是由 YOLOv5 的发布者 Ultralytics 发布的最新版本的 YOLO。它可用于对象检测、分割、分类任务以及大型数据集的学习,并且可以在包括 CPU 和 GPU 在内的各种硬件上执行。 YOLOv8是一种尖端的、最先进的 (SOTA) 模型,它建立在以前成…

CSS 网页制作-学成在线

1、 准备工作 1.1 项目目录 网站根目录是指存放网站的第一层文件夹&#xff0c;内部包含当前网站的所有素材&#xff0c;包含HTML、CSS、图片、JavaScript等等。 1.2 版心效果 可以发现都是呈现版心居中的效果&#xff0c;但是每次都写一次太麻烦了&#xff0c;可以把版心居中…

python可以做小程序研发嘛,python能做微信小程序吗

大家好&#xff0c;给大家分享一下python可以做微信小程序开发吗&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 大家好&#xff0c;给大家分享一下用python编写一个小程序&#xff0c;很多人还不知道这一点。下面详细解释一下用python代码…

java设计模式学习之【命令模式】

文章目录 引言命令模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用股票示例代码地址 引言 想象一下&#xff0c;你在一个忙碌的厨房里&#xff0c;厨师们正忙于准备各种菜肴。每当服务员带来一个新订单时&#xff0c;他们不会直接对厨师说需要做什么菜。相…

flutter开发实战-设置bottomNavigationBar中间按钮悬浮效果

flutter开发实战-设置bottomNavigationBar中间按钮悬浮的效果 在使用tabbar时候&#xff0c;可以使用bottomNavigationBar来设置中间凸起的按钮&#xff0c;如下 一、效果图 中间按钮凸起的效果图如下 二、实现代码 我们使用BottomAppBar 一个容器&#xff0c;通常与[Sscaf…

2023年PMP证书的含金量有多高?对于企业来说有多大的价值?

PMP含金量更多的是“敲门砖”作用&#xff0c;公司招聘的门槛 当然现在PMP管理模式也很热门&#xff0c;各大企业都有引进改良应用在公司的项目上&#xff0c;之前在校友群里面大家在讨论PMP 的作用也有说到这一点&#xff0c;给大家看看吧。 至于为什么PMP认证从国外引进大陆…

⭐Unity 读取本地图片再区域裁剪

现在需求是将本地的图片读取之后再区域截图成新的图片 话不多说直接上代码 using UnityEngine; using System.IO;public class LocalRegionCapture : MonoBehaviour {public string fullScreenImagePath "Assets/SavedImages/fullScreenScreenshot.png";public str…

【PyQt学习篇 · ⑭】:QTableView的使用

文章目录 QTableView的使用示例 QTableView的使用 QTableView 是 PyQt 中用于显示表格数据的窗口部件&#xff0c;它提供了一个灵活的方式来显示和编辑数据。下面是一些关于 QTableView 的使用的具体信息&#xff1a; 创建 QTableView 对象&#xff1a; from PyQt5.QtWidgets …

python/C 生成beta分布的随机数

python/C 生成beta分布的随机数 文章目录 python/C 生成beta分布的随机数前言一、beta分布理论知识二、python 生成服从beta分布的随机数三、C语言生成服从beta分布的随机数 前言 想把一个算法用C语言实现&#xff0c;其中涉及到了beta分布取随机数&#xff0c;记录一下结果 一…

雀巢困在业绩和质量里

撰稿|行星 来源|贝多财经 雀巢集团CEO马克施奈德曾在2023年中报中表示&#xff0c;后疫情时代居家消费已恢复常态&#xff0c;从而消除了制约雀巢部分品类增长的阻碍。 但就雀巢前三季度财报而言&#xff0c;该公司在全球及大中华区的销售额均有所下降&#xff0c;有机增长主…

如何使用Java的GeoTools地理库计算WGS84坐标下的两个经纬度之间得距离

介绍 本章讲解如何使用Java的GeoTools地理库计算基于WGS84坐标的两点之间的距离。适用于后台服务的距离计算。 GeoTools介绍 GeoTools是开源的Java地理信息计算库。GeoServer地图引擎就是基于GeoTools库构建得地图服务,可以说非常强大。 官网地址:https://docs.geotools.o…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存(C#)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机通过SDK实现Raw格式的图像保存的技术背景通过SDK获取相机信息的代码分析Baumer工业相机回调函数里保存原始图像数据Baumer保存Raw图像格式重要核心代…

【JS】按照a>b>c>d>e>f的优先级,将a,b,c,d,e,f元素进行筛选,选出三个不为空字符的元素进行字符拼接

设计思路&#xff1a; 1、定义一个数组&#xff0c;把元素按照优先级进行排序&#xff1b; 2、 使用 filter() 方法过滤掉空字符串元素&#xff0c;得到一个新的数组; 3、在排序函数中&#xff0c;循环数组&#xff0c;使用 indexOf() 方法获取元素 a 和 b 在数组中的索引&a…

描述一个bug及定义bug的级别

&#xff08;一&#xff09;描述一个bug 描述一个bug&#xff0c;需要以下几个因素&#xff1a; 故障标题、故障发现的版本、故障类别&#xff08;功能/兼容/界面&#xff09;、故障优先级、故障描述&#xff08;测试环境、测试步骤、预期结果、实际结果&#xff09;。 举个例…

MySQL,使用Union组合查询

1、基本使用 Union可将多条select语句组合成一个结果集&#xff0c;常见的使用场景有2种&#xff1a; 在单个查询中&#xff0c;从不同的表返回类似结构的数据&#xff1b;对单个表执行多个查询&#xff0c;按单个查询返回数据。 例&#xff1a;检索出所有价格<50的产品&…

批发订货系统小程序怎么推广 四个方案高效获客

微信小程序基于强社交属性&#xff0c;天然自带引流特性&#xff0c;但毕竟小程序也只是一个工具&#xff0c;想要快速获客&#xff0c;还是需要商家主动采取一些措施的。下面分享是个方法&#xff0c;尤其是最后一个&#xff0c;是十分凑效的。大家点个关注点个赞&#xff0c;…