C语言笔记(指针题目)例题+图解

        本文分为两部分 ,第一部分为数组、字符串、字符指针在sizeof和strlen中的辨析,第二部分是一些笔试题目。若有错误,请批评指正。

目录

1.第一部分

1.1.数组名的使用

1.1.1一维整型数组在sizeof中的使用

1.1.2一维字符数组在sizeof中的使用

1.1.3一维字符数组在strlen中的使用

1.1.4.一字符串在sizeof中的使用

1.1.5.一字符串在strlen中的使用

1.2字符指针在sizeo和strlen中的使用

1.2.1 字符指针在sizeof中的使用

1.2.2 字符指针在strlen中的使用

2.第二部分(指针笔试题)


1.第一部分

注意:

1.sizeof()是操作符,只关注占用的内存空间的大小,单位是字节,不访问内存中的存储的内容。
2.strlen()是库函数,用来求字符串的长度,统计的是字符'\0'出现之前的字符的个数,当函数在内存中找到’\0‘才算结束,所以strlen可能会越界访问。

3.以下所有的代码均在32位的环境中,因此地址为4个字节。

3.数组名字的意义

        1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
        2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
        3. 除此之外所有的数组名都表示首元素的地址。

1.1.数组名的使用
1.1.1一维整型数组在sizeof中的使用
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));  //16 ()中只有数组名,表示整个数组,所测量的是整个数组
	printf("%d\n", sizeof(a + 0));//a+0就是数组首元素的地址,地址的大小为4个字节
	printf("%d\n", sizeof(*a));//*a表是的数组首元素,是一个整型变量 4个字节
	//a不是单独存在时,表示的首元素地址,*a就是元素  1 
	printf("%d\n", sizeof(a + 1));//a为首元素地址,+1之后还是地址  4个字节
	printf("%d\n", sizeof(a[1]));// 数组第二个元素  4个字节
	printf("%d\n", sizeof(&a));//&a数组指针,地址为 4个字节
	printf("%d\n", sizeof(*&a));// * & 两者相互抵消,是整个数组, 16个字节
	printf("%d\n", sizeof(&a + 1));//是地址,指向的是第二个元素, 4个字节
	printf("%d\n", sizeof(&a[0])); //首元素地址  4个字节
	printf("%d\n", sizeof(&a[0] + 1)); //第二个元素地址  4个字节
	return 0;
}
1.1.2一维字符数组在sizeof中的使用
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	//char类型数据大小为一个字节
	printf("%d\n", sizeof(arr));// 6个字节,arr单独存放,是整个数组
	printf("%d\n", sizeof(arr + 0));//4个字节,(arr+0)表示为首元素地址
	printf("%d\n", sizeof(*arr));// 1个字节 ,arr表示首元素地址,*arr为首元素'a'
	printf("%d\n", sizeof(arr[1]));// 1个字节,第二个元素'b'
	printf("%d\n", sizeof(&arr));//4个字节  数组指针,&arr为地址
	printf("%d\n", sizeof(&arr + 1));//4个字节  地址加1还是地址,数据类型不变
	printf("%d\n", sizeof(&arr[0] + 1));//4个字节 取首元素的地址,+1还是地址
	return 0;
}
1.1.3一维字符数组在strlen中的使用

        strlen 的返回值是字符的个数,形式参数是字符指针

size_t strlen ( const char * str );

  size_t                无符号整型,返回值

 const char * str  字符指针,形式参数  const为关键字限定str无法修改

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));	//随机值,arr为数组的首元素地址,但是数组中没有'\0'
	printf("%d\n", strlen(arr + 0));//arr+0,arr是地址+0之后还是地址,函数无法接受,
	printf("%d\n", strlen(*arr));	//表示是'a'— 97,非法访问,
	printf("%d\n", strlen(arr[1])); //表示是'b'— 98,非法访问
	printf("%d\n", strlen(&arr));   //数组指针,是指针会报警的,但是从数组指针开始计算还是随机值
	printf("%d\n", strlen(&arr + 1));// 数组指针,+1 之后地址跳过数组,随机值
	printf("%d\n", strlen(&arr[0] + 1));//表示的是第二个元素的地址,也是随机值
	return 0;
}
1.1.4.一字符串在sizeof中的使用
int main()
{
	char arr[] = "abcdef";
	//数组中的元素是 a b c d e f \0  共7个元素
	printf("%d\n", sizeof(arr));	// 7个字节,数组名字单独存放就是整个数组
	printf("%d\n", sizeof(arr + 0));//4个字节 arr+0表示&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));// 四个字节
	return 0;
}
1.1.5.一字符串在strlen中的使用

        数组名在strlen函数中仍然是首个元素的地址。

int main()
{
	char arr[] = "abcdef";
	//数组中的元素是 a b c d e f \0  共7个元素
	printf("%d\n", strlen(arr)); // 6 字符串中有6个字符 '\0' 不算在内
	printf("%d\n", strlen(arr + 0));//6 表示&arr[0],首元素的地址,
	printf("%d\n", strlen(*arr));//*arr是'a',非法访问 
	printf("%d\n", strlen(arr[1]));//arr[1]是'b',属于非法访问
	printf("%d\n", strlen(&arr));//6  &arr是数组指针,
	printf("%d\n", strlen(&arr + 1));// 5 &arr是数组指针,但是其指向的仍然是数组的首元素处
	// +1 之后指向数组的第二个元素,跳过了第一个元素  
	printf("%d\n", strlen(&arr[0] + 1));// 5  一个元素的地址 +1 跳过了 第一个元素
	return 0;
}

1.1.6二维数组在sizeof中的使用

        二维数组的数组名表示的是首行元素的地址,是数组指针。arr[0]是第一行数组。

int main()
{
	int a[3][4] = { 0 };

	printf("%d\n", sizeof(a));// 48个字节,一共12个元素,一个元素 4个字节
	printf("%d\n", sizeof(a[0][0]));// 第一个元素, 4 个字节
	printf("%d\n", sizeof(a[0]));// 第一行数组  a[0]是第一行数组的名字,单独存在即一个数组  16个字节
	printf("%d\n", sizeof(a[0] + 1));//a[0]为首元素地址,+1跳到第二个元素地址,4个字节
	printf("%d\n", sizeof(*(a[0] + 1)));// 4个字节  第二个元素
	printf("%d\n", sizeof(a + 1));// a + 1表示是a[1]是第二行地址 4个字节
	printf("%d\n", sizeof(*(a + 1)));// 表示的是第二行的数组, 16个字节
	printf("%d\n", sizeof(&a[0] + 1));// &a[0]是第一行的地址,+1 指是第二行的地址, 4个字节
	printf("%d\n", sizeof(*(&a[0] + 1)));//第二行有四个元素, 16个字节
	printf("%d\n", sizeof(*a));//a为首元素地址,就是第一行的地址, 16个字节
    printf("%d\n", sizeof(a[3]));//访问的是数组的第四行元素,数组越界,但是可以计算,
    //sizeof()中表达式是不会计算的,不会访问真是的空间,按照类型出的结果。
	// *a -- *(a+0) -- a[0]
	return 0;
}
1.2字符指针在sizeo和strlen中的使用
1.2.1 字符指针在sizeof中的使用
int main()
{
	char *p = "abcdef";
	printf("%d\n", sizeof(p));//p为指针 4个字节
	printf("%d\n", sizeof(p + 1));// +1 跳出整个字符串地址4个字节
	printf("%d\n", sizeof(*p));// p 指向的第一个元素 *p 就为 'a'  1个字节
	printf("%d\n", sizeof(p[0]));// p[0] --*(p+0),首个元素   1个字节
	printf("%d\n", sizeof(&p));//  二级指针   4个字节 
	printf("%d\n", sizeof(&p + 1));// 二级指针 +1 还是指针 4个字节
	printf("%d\n", sizeof(&p[0] + 1));//第一个元素的指针 +1 表示的第二个元素的指针 4个字节 
	return 0;
}
1.2.2 字符指针在strlen中的使用
int main()
{
	char *p = "abcdef";
	printf("%d\n", strlen(p));// p是一个指向'a'的一个字符指针, 6
	printf("%d\n", strlen(p + 1));// 5 指针+1  指针指向的是 'b'
	printf("%d\n", strlen(*p));// 非法访问
	printf("%d\n", strlen(p[0]));// 相当于 *(p+0)非法访问
	printf("%d\n", strlen(&p));// 二级指针 随机值
	printf("%d\n", strlen(&p + 1));// 随机值 
	printf("%d\n", strlen(&p[0] + 1)); //5 &p[0]相当于p了 , p+1指向第二个元素
	return 0;
}

2.第二部分(指针笔试题)

本部分共八个题目

1.

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);           // &a+1 已经跳出整个数组了 
	//强制转换成int*类型的指针 
	printf("%d,%d", *(a + 1), *(ptr - 1));//(a+1)中的a为首元素地址 a+1 只想第二个元素
	return 0;							  
}
//结果为 2,5  

分解

(1)第4行

int *ptr = (int *)(&a + 1);    

        &a为数组指针,指向的是数组的首元素地址;所以&a+1就可以跳出整个数组,+1它的步长就是整个数组的长度。

        (int*)为强制转换类型,(int *)(&a + 1)可以把数组指针&a+1强制转换成整型指针,并且将指针的值赋予ptr,那么ptr的值和(&a+1)是一样的,但是其类型,步长是不一样的

printf("%d,%d", *(a + 1), *(ptr - 1))

        a+1中的a表示首元素的地址,a+1表示是第二个元素的地址,*(a+1)解引用的就是 2

*(ptr-1),ptr的地址向低地址移动四个字节,指向的是第五个元素。*(ptr-1)为5。

2.

#include <stdio.h>
struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//结构体的大小是20字节
int main()
{
	int p = 0x100000;
	printf("%p\n", p + 0x1);
	//p+1 0x100000+0x1=0x100001
	printf("%p\n", (unsigned long)p + 0x1);
	//强制转换成 无符号整型 0x100001
	printf("%p\n", (unsigned int*)p + 0x1);
	//强制转换成无符号整型指针 +1 就是+0x4  结果为 0x100004 
	return 0;
}

     上述程序结果为0x00100001 0x00100001 0x00100004 

         *p为结构体指针,但是此题中根本没有使用到结构体指针的大小和指向等问题,

printf("%p\n", p + 0x1);

        0x1对于十进制来说就是1;但是输出的是%p形式,以地址的方式输出,要输出8位数字。

p=0x100000+0x1=0x100001;输出的是0x00100001。

printf("%p\n", (unsigned long)p + 0x1);

        (unsigned long)p 将p强制转换成无符号整型,但是输出的仍然是地址的形式,因此和上面+1计算一样,结果都是 0x00100001。

printf("%p\n", (unsigned int*)p + 0x1);

     (unsigned int*)p 将p强制转换成无符号指针类型,其大小为4个字节,+1步长为4个字节,

因此p+1就是指针加4,结果就是0x00100001+0x4,输出为0x00100001。

3.

//机器为小端存储
int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);//a为数组的第一个元素的指针,强制转换成int 图解
	//数组a 的存储方式 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
	printf("%x,%x", ptr1[-1], *ptr2);//ptr[-1]-- *(ptr-1)
	return 0;
}
//结果 0x4 ,0x2000000

//%x就是打印16进制的字符

        数组元素的存储方式为小端存储,小端存储就是数据低位放在地址值,数据高位放在高地址。

a[4]数组在内存中的存储方式:每一个小方块为一个字节,有8个bit的内存。

       

int *ptr1 = (int *)(&a + 1);

            &a为数组指针,指向的是数组的首元素地址;所以&a+1就可以跳出整个数组,+1它的步长就是整个数组的长度。

int *ptr2 = (int *)((int)a + 1)

        a为数组名,是首元素地址,强制转化成int类型,+1就是数字+1,强制转换成int*类型,a在原来地址的基础上向高地址挪动一个字节,相当于指向第一个整型元素的第2个字节。*ptr,输出的是整型元素,需要从低地址到高地址四个字节,从第一个元素的第二个字节,到第二个元素的第一个字节,因此 *ptr就是 0x2000000 。

4.

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	//int a[3][2] = {1,3,5};
	int *p;
	p = a[0];//a[0]是第一行的数组名,是第一行的首元素地址
	printf("%d", p[0]);//p[0] -- *(p+0)
	return 0;
}

   结果为 1 。

int a[3][2] = { (0, 1), (2, 3), (4, 5) }

         (0,1)逗号表达式,表达式从左向右,最后表达式的结果就是整个表达式的结果。那么得出:

int a[3][2] = { 1, 3, 5 }
p = a[0]

        a[0]为二维数组首行数组的名字,数组名字就是首元素的地址,将首元素地址赋值给p,输出的自然是首元素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;//二者的步长一致,相差为4  图解
	//fffffffc  -4
}

a等价于 int (*)[5] 指向是元素为5的数组
p等价于 int (*)[4] 指向是元素为4的数组
根据图&p[4][2] - &a[4][2]相差四个元素 结果为-4
-4 的原码 10000000 00000000 00000000 00000100
     反码 10000000 00000000 00000000 00000011
     补码 11111111 11111111 11111111 111111100 
    地址不会区分原码、反码 、补码,地址就是内存中存储的补码。
    转换成16进制 ff ff ff fc 
p = a;

        将a的int (*)[5]的数值强行赋值给了p;p的类型是int (*)[4],指向的是四个指针的数组。

a为首元素地址,是第一行的数组指针,类型是int (*)[5]。

数组在内存中存储的排序为

        强制复制后p就为a地址,但是p指向的是int[4]类型的数组,因此步长为4个整型数据,假设所模拟后的数组为4个元素为一行。

图解

 &p[4][2] - &a[4][2],

        可以看出,其中间相差4个步长,数值为-4。

6.

7.

8.

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

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

相关文章

ADC开启

ADC性能参数&#xff1a; 1.分辨率 用LSB表示&#xff1a; LSBVref/2^N 2.失调误差 3.增益误差 4.微分非线性误差 微分非线性&#xff1a;指的是数字输出每增加“1”时&#xff0c;输出模拟量的变化值与LSB的差距。 DNL &#xff08;2.2-1&#xff09;LSB 1.2LSB 5.积分非…

深度学习案例:带有一个隐藏层的平面数据分类

该案例来自吴恩达深度学习系列课程一《神经网络和深度学习》第三周编程作业&#xff0c;作业内容是设计带有一个隐藏层的平面数据分类。作业提供的资料包括测试实例&#xff08;testCases.py&#xff09;和任务功能包&#xff08;planar_utils.py&#xff09;&#xff0c;下载请…

学习threejs,使用粒子实现下雪特效

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Points简介1.11 ☘️…

在Excel中如何快速筛选非特定颜色

Excel中的自动筛选是个非常强大的工具&#xff0c;不仅可以筛选内容&#xff0c;而且可以筛选颜色&#xff0c;例如筛选A列红色单元格。但是有时希望筛选除了红色之外的单元格&#xff08;下图右侧所示&#xff09;&#xff0c;其他单元格的填充色不固定&#xff0c;有几种颜色…

llama.cpp基础知识与原理导读

llama.cpp 是一个轻量化的 C++ 实现,专注于 Meta 的 LLaMA 模型的推理和部署。该项目致力于在不依赖庞大的深度学习框架(如 PyTorch、TensorFlow 等)的情况下,实现对 LLaMA 模型的高效运行,特别是在资源受限的设备上(如个人电脑和手机)。以下是 llama.cpp 的主要工作原理…

【Android14 ShellTransitions】(八)播放动画

书接上回&#xff0c;话说当WMCore部分走到了Transition.onTransactionReady&#xff0c;计算完参与动画的目标&#xff0c;构建出TransitionInfo后&#xff0c;接下来就把这个包含了动画参与者的TransitionInfo发给了WMShell&#xff0c;然后就该播放动画了&#xff0c;这部分…

ELK + Filebeat + Spring Boot:日志分析入门与实践(二)

目录 一、环境 1.1 ELKF环境 1.2 版本 1.3 流程 二、Filebeat安装 2.1 安装 2.2 新增配置采集日志 三、logstash 配置 3.1 配置输出日志到es 3.2 Grok 日志格式解析 3.2 启动 logstash ​3.3 启动项目查看索引 一、环境 1.1 ELKF环境 springboot项目&#xff1a;w…

C#实现word和pdf格式互转

1、word转pdf 使用nuget&#xff1a; Microsoft.Office.Interop.Word winform页面&#xff1a; 后端代码&#xff1a; //using Spire.Doc; //using Spire.Pdf; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using Sy…

成都睿明智科技有限公司抖音电商服务的领航者

在这个短视频风起云涌的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为无数商家争夺流量与销量的新战场。在这片红海之中&#xff0c;如何脱颖而出&#xff0c;实现销售额的飞跃&#xff1f;今天&#xff0c;就让我们一同走进成都睿明智科技有限公司&#xf…

力扣hot100-->递归/回溯

目录 递归/回溯 1. 17. 电话号码的字母组合 2. 22. 括号生成 3. 39. 组合总和 4. 46. 全排列 5. 78. 子集 递归/回溯 1. 17. 电话号码的字母组合 中等 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到…

快速遍历包含合并单元格的Word表格

Word中的合并表格如下&#xff0c;现在需要根据子类&#xff08;例如&#xff1a;果汁&#xff09;查找对应的品类&#xff0c;如果这是Excel表格&#xff0c;那么即使包含合并单元格&#xff0c;也很容易处理&#xff0c;但是使用Word VBA进行查找&#xff0c;就需要一些技巧。…

js 获取当前时间与前一个月时间

// 获取当前时间的毫秒数 var currentTimeMillis new Date().getTime();// 获取前一个月的Date对象 var dateLastMonth new Date(); dateLastMonth.setMonth(dateLastMonth.getMonth() - 1);// 获取前一个月的毫秒数 var timeMillisLastMonth dateLastMonth.getTime();conso…

C++之多态的深度剖析

目录 前言 1.多态的概念 2.多态的定义及实现 2.1多态的构成条件 2.1.1重要条件 2.1.2 虚函数 2.1.3 虚函数的重写/覆盖 2.1.4 选择题 2.1.5 虚函数其他知识 协变&#xff08;了解&#xff09; 析构函数的重写 override 和 final关键字 3. 重载&#xff0c;重写&…

【linux网络编程】| socket套接字 | 实现UDP协议聊天室

前言&#xff1a;本节内容将带友友们实现一个UDP协议的聊天室。 主要原理是客户端发送数据给服务端。 服务端将数据再转发给所有链接服务端的客户端。 所以&#xff0c; 我们主要就是要实现客户端以及服务端的逻辑代码。 那么&#xff0c; 接下来开始我们的学习吧。 ps:本节内容…

【PTA】4-2 树的同构【数据结构】

给定两棵树 T1​ 和 T2​。如果 T1​ 可以通过若干次左右孩子互换就变成 T2​&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树。而图2就不是同构的。 图一…

「Mac畅玩鸿蒙与硬件13」鸿蒙UI组件篇3 - TextInput 组件获取用户输入

在鸿蒙应用开发中,TextInput 组件用于接收用户输入,适用于文本、密码等多种输入类型。本文详细介绍鸿蒙 TextInput 组件的使用方法,包括输入限制、样式设置、事件监听及搜索框应用,帮助你灵活处理鸿蒙应用中的用户输入。 关键词 TextInput 组件用户输入输入限制事件监听搜索…

单元测试详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 为什么需要单元测试&#xff1f; 从产品角度而言&#xff0c;常规的功能测试、系统测试都是站在产品局部或全局功能进行测试&#xff0c;能够很好地与用户的需…

如何从PPT中导出600dpi的高清图

Step1. 修改PPT注册表 具体过程&#xff0c;参见如下链接&#xff1a;修改ppt注册表&#xff0c;导出高分辨率图片 Step2. 打开PPT&#xff0c;找到自己想要保存的图&#xff0c;选中图像&#xff0c;查看图像尺寸并记录 Step3. 重新新建一个PPT&#xff0c;并根据记录的图片…

「Mac畅玩鸿蒙与硬件7」鸿蒙开发环境配置篇7 - 使用命令行工具和本地模拟器管理项目

本篇将讲解在 macOS 上配置 HarmonyOS 开发环境的流程&#xff0c;聚焦 hvigorw 命令行工具的使用。我们将以创建 HelloWorld 项目为例&#xff0c;演示使用 hvigorw 进行项目构建、清理操作&#xff0c;并通过 DevEco Studio 的本地模拟器进行预览&#xff0c;帮助提升项目开发…

Linux基础—基础命令及相关知识5(ubuntu网络配置)

网络的配置方法 centos网络配置 centos的网卡位置 /etc/sysconfig/network-scripts/ifcfg-ens33(centos网卡文件) bootproto表示获得IP地址的方式是静态的还是动态 onboot表示启动系统时是否激活该网络接口 设置IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;dns…