C语言.指针(5)

news2024/11/23 2:14:00

指针(5)

  • 1.sizeof和strlen的对比
    • 1.1sizeof
    • 1.2strlen
    • 1.3sizeof和strlen的对比
  • 2.数组和指针笔试题解析
    • 2.1一维数组
    • 2.2字符数组
    • 2.3二维数组
  • 3.指针运算笔试题解析
    • 3.1 题目1
    • 3.2 题目2
    • 3.3 题目3
    • 3.4 题目4
    • 3.5 题目5
    • 3.6 题目6
    • 3.7 题目7

1.sizeof和strlen的对比

1.1sizeof

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

sizeof 只关注占用内存空间的大小,不在乎内存存放的是什么数据。

比如:

#include<stdio.h>

int main()
{
	int a = 0;

	printf("%zd\n", sizeof(a));//4
	printf("%zd\n", sizeof a);//4
	printf("%zd\n", sizeof(int));//4

	return 0;
}

1.2strlen

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

size_t strlen(const char* str);

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。

strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。

#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[3] = { 'a', 'b', 'c' };
	char arr2[] = { "abc" };

	printf("%zd\n", strlen(arr1));//35:随机值
	printf("%zd\n", strlen(arr2));//3

	printf("%zd\n", sizeof(arr1));//3
	printf("%zd\n", sizeof(arr2));//4

	return 0;
}

1.3sizeof和strlen的对比

在这里插入图片描述

2.数组和指针笔试题解析

2.1一维数组

#include<stdio.h>
#include<string.h>

int main()
{
	int a[] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("%zd\n", sizeof(a));
	//a表示的是整个数组的地址,所以是sizeof(int)*10 == 40个字节
	printf("%zd\n", sizeof(a + 0));
	//a表示的是数组首元素的地址,计算的是首元素的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(*a));
	//a表示的是数组首元素的地址,*a表示的是 首元素的大小,是int类型,为4个字节
	printf("%zd\n", sizeof(a + 1));
	//a表示的是数组首元素的地址,a + 1,表示的是a[1]的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(a[0]));
	//a表示的是数组首元素的地址,a[0]表示的是数组首元素,是int类型,为4个字节
	printf("%zd\n", sizeof(a[1]));
	//a表示的是数组首元素的地址,a[1]表示的是第二个元素,是int类型,为4个字节
	printf("%zd\n", sizeof(&a));
	//&a,表示的是取出的是整个数组的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&a + 1));
	//&a,表示的是取出的是整个数组的地址,&a + 1就跳出整个整型数组,是地址就是4/8个字节
	printf("%zd\n", sizeof(&a[0]));
	//&a[0]表示的是首元素的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&a[0] + 1));
	//&a[0]表示的是首元素的地址,&a[0] + 1表示的是下标为1的元素的地址,是地址就是4/8个字节
	
	return 0;
}

2.2字符数组

代码1:

#include <stdio.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	//             a b c d e f 
	printf("%zd\n", sizeof(arr));
	//arr表示的是整个数组的地址,所以是sizeof(char)*6 == 6个字节
	printf("%zd\n", sizeof(arr + 0));
	//arr + 0表示的是数组首元素的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(*arr));
	//arr表示的是整个数组的地址,*arr得到的是首元素,arr的类型是char,是1个字节
	printf("%zd\n", sizeof(arr[1]));
	//arr[1],表示的是下标为1的数组元素,类型是char,是1个字节
	printf("%zd\n", sizeof(&arr));
	//&arr表示取出的是整个数组的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&arr + 1));
	//&arr,表示的是取出的是整个数组的地址,&a + 1就跳出整个字符数组,是地址就是4/8个字节
	printf("%zd\n", sizeof(&arr[0] + 1));
	//&arr[0]表示的是首元素的地址,&arr[0] + 1表示的是下标为1的数组元素的地址,是地址就是4/8个字节

	return 0;
}

代码2:

#include <stdio.h>
#include<string.h>
//size_t strlen ( const char * str );
//strlen()需要的是首元素的地址
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	//              a b c d e f
	printf("%zd\n", strlen(arr));
	//arr表示的是首元素的地址,数组中没有\0,就会导致越界访问,结果就会是随机值
	printf("%zd\n", strlen(arr + 0));
	//arr表示的是首元素的地址,数组中没有\0,就会导致越界访问,结果就会是随机值
	printf("%zd\n", strlen(*arr));
	//arr是首元素的地址,*arr是首元素,就是'a','a'的ASCII码值是97,相当于把97当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误//err
	printf("%zd\n", strlen(arr[1]));
	//arr[1]表示的是下标为1的数组元素,就是'b','b'的ASCII码值是98,相当于把98当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误//err
	printf("%zd\n", strlen(&arr));
	//&arr表示取出的是整个数组的地址,数组中没有\0,就会导致越界访问,起始位置指向数组的第一个元素的位置,结果就会是随机值 x
	printf("%zd\n", strlen(&arr + 1));
	//&arr表示取出的是整个数组的地址,&arr + 1跳过整个数组的地址,数组中没有\0,就会导致越界访问,起始位置指向数组的最后一个元素的下一个位置,结果就会是随机值 x - 6
	printf("%zd\n", strlen(&arr[0] + 1));
	//从第2个元素开始向后统计的,得到的也是随机值 x - 1
	return 0;
}

代码3:

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[] = { "abcdef" };
	//              a b c d e f \0
	printf("%zd\n", sizeof(arr));
	//arr表示的是整个数组的地址,计算的是整个数组的大小,sizeof(char)*7 == 7个字节
	printf("%zd\n", sizeof(arr + 0));
	//arr + 0表示的是数组首元素的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(*arr));
	//*arr得到的是数组的首元素,类型是char,1个字节
	printf("%zd\n", sizeof(arr[1]));
	//arr[1]是数组下标为1的元素,类型是char,1个字节
	printf("%zd\n", sizeof(&arr));
	//&arr取出的是整个数组的地址,是地址就是4/8字节
	printf("%zd\n", sizeof(&arr + 1));
	//&arr取出的是整个数组的地址,&arr + 1跳过整个数组,还是地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&arr[0] + 1));
	//&arr[0]表示的是数组首元素的地址,&arr[0] + 1就是下标为1的数组元素的地址,是地址就是4/8个字节
	return 0;
}

代码4:

#include <stdio.h>
#include<string.h>

int main()
{
	char arr[] = "abcdef";
	//            a b c d e f \0
	printf("%zd\n", strlen(arr));
	//arr首元素的地址,向后在\0之前有6个字符
	printf("%zd\n", strlen(arr + 0));
	//arr首元素的地址,arr+0还是首元素的地址,向后在\0之前有6个字符
	printf("%zd\n", strlen(*arr));
	//arr是首元素的地址,*arr是首元素,就是'a','a'的ASCII码值是97,相当于把97当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误
	printf("%zd\n", strlen(arr[1]));
	//arr[1]是下标为1数组的元素,就是'b','b'的ASCII码值是98,相当于把98当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误
	printf("%zd\n", strlen(&arr));
	//&arr表示取出的是整个数组的地址,起始位置指向数组的第一个元素的位置,向后在\0之前有6个字符
	printf("%zd\n", strlen(&arr + 1));
	//&arr表示取出的是整个数组的地址,&arr + 1跳过整个数组的地址,起始位置指向数组的最后一个元素的下一个位置,数组中没有\0,就会导致越界访问,结果就会是随机值
	printf("%zd\n", strlen(&arr[0] + 1));
	//&arr[0]表示的是数组首元素的地址,&arr[0] + 1就是下标为1的数组元素的地址,向后在\0之前有5个字符
	return 0;
}

代码5:

#include <stdio.h>

int main()
{
	const char* p = "abcdef";
	//               a b c d e f \0
	printf("%zd\n", sizeof(p));
	//p是指针变量,计算的是指针变量的大小,4/8个字节
	printf("%zd\n", sizeof(p + 1));
	//p + 1是b的地址,是地址大小就是4/8个字节
	printf("%zd\n", sizeof(*p));
	//p的类型是const char*,*p就是char类型,大小是1个字节
	printf("%zd\n", sizeof(p[0]));
	//1.p[0] -> *(p + 0) -> *p -> 得到的就是'a',大小是1个字节
	//2.把常量字符串想象成数组,p可以理解为数组名,p[0], 就是首元素
	printf("%zd\n", sizeof(&p));
	//取出的是p的地址,地址的大小是4/8个字节
	printf("%zd\n", sizeof(&p + 1));
	//&p + 1是跳过p指针变量后的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&p[0] + 1));
	//&p[0]表示的是取出字符串首字符的地址,&p[0] + 1是第二个字符的地址,大小是4/8个字节
	return 0;
}

代码6:

#include <stdio.h>
#include <string.h>

int main()
{
	const char* p = "abcdef";
	//               a b c d e f \0
	printf("%zd\n", strlen(p));
	//p是指针变量,向后在\0之前有6个字符
	printf("%zd\n", strlen(p + 1));
	//p是指针变量,p + 1向后在\0之前有5个字符
	//printf("%zd\n", strlen(*p));
	//p的类型是const char*,*p就是char类型,*p就是'a'-97,err
	//printf("%zd\n", strlen(p[0]));
	//p[0] -> *(p + 0) -> *p -> 得到的就是'a'-97.err
	printf("%zd\n", strlen(&p));
	//&p是指针变量p的地址,和字符串"abcdef"关系不大,从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以是随机值
	printf("%zd\n", strlen(&p + 1));
	//和上面的情况一样了,随机值
	printf("%zd\n", strlen(&p[0] + 1));
	//p[0] -> *(p + 0) -> *p,&p[0] == &*p == p:首元素的地址
	//&p[0]-取出字符串首字符的地址,+1是第二个字符的地址, 5
	return 0;
}

2.3二维数组

#include<stdio.h>

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

	printf("%zd\n", sizeof(a));
	//a是二维数组的数组名,单独放在sizeof()中,计算的是整个数组的大小,3*4*sizeof(int) == 48个字节
	printf("%zd\n", sizeof(a[0][0]));
	//a[0][0] 是第一行第一个元素,大小是4个字节 
	printf("%zd\n", sizeof(a[0]));
	//a[0]表示的是第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节
	printf("%zd\n", sizeof(a[0] + 1));
	//a[0] + 1表示的是第二行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节
	printf("%zd\n", sizeof(*(a[0] + 1)));
	//*(a[0] + 1)表示的是第一行第二个元素,大小就是4
	//*(*(p + 0) + 1) == p[0][1]
	printf("%zd\n", sizeof(a + 1));
	//a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节
	printf("%zd\n", sizeof(*(a + 1)));
	//1.a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,a+1,跳过一行,指向了第二行,*(a+1)表示的是第二行,a+1是数组指针,计算的是第二行的大小 - 16字节
	//2.*(a + 1) == a[1] -> 表示的是第二行的数组名,单独放在sizeof中,4*sizeof(int) == 16字节
	printf("%zd\n", sizeof(&a[0] + 1));
	//&a[0]取出的是第一行的数组名,&a[0] + 1指向的是第二行的地址,是地址大小就是4/8个字节
	printf("%zd\n", sizeof(*(&a[0] + 1)));
	//&a[0] + 1指向的是第二行的地址,*(&a[0] + 1)是对第二行的地址解引用,访问的就是第二行,大小是16字节
	printf("%zd\n", sizeof(*a));
	//1.a表示的是二维数组首元素的地址,计算的就是第一行的大小,16字节
	//2.*a == *(a + 0) == a[0] ->第一行的数组名
	printf("%zd\n", sizeof(a[3]));
	//a[3]无需真实存在,仅仅通过类型的推断就能算出长度a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16个字节
	return 0;
}

数组名的意义:

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

3.指针运算笔试题解析

3.1 题目1

#include <stdio.h>

int main()
{
	int a[] = { 1,2,3,4,5 };
	int* ptr = (int*)(&a + 1);

	printf("%d %d\n", *(a + 1), *(ptr - 1));
	//                  2         5
	return 0;
}
//输出的结果是什么?

3.2 题目2

//在X86的环境下
//假设结构体的大小是20个字节
//输出的结果是什么?
#include <stdio.h>

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

3.3 题目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]);//1

	return 0;
}

3.4 题目4

//假设环境是x86环境,程序输出的结果是啥?
#include<stdio.h>

int main()
{
	int a[5][5];
	int(*p)[4];//p是一个数组指针,p指向的数组是4个整型元素

	p = a;

	printf("%p, %d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	//                 FFFFFFFC,            -4
	return 0;
}

3.5 题目5

#include<stdio.h>

int main()
{
	int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)(*(a + 1));

	printf("%d, %d\n", *(ptr1 - 1), *(ptr2 - 1));
	//                   10,          5
	return 0;
}

3.6 题目6

#include<stdio.h>

int main()
{
	char* a[] = {"work", "at", "alibaba"};
	char** pa = a;
	pa++;

	printf("%s\n", *pa);//at

	return 0;
}

3.7 题目7

#include <stdio.h>

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

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

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

相关文章

SNRO 编号范围对象管控,唯一ID

事务代码:SNRO 代码引用: DATA: MAXTID TYPE I,NEWNO TYPE CHAR8. CALL FUNCTION NUMBER_RANGE_ENQUEUE EXPORTING OBJECT ZQC57 EXCEPTIONS FOREIGN_LOCK 1 OBJECT_NOT_FOUND 2 SYSTEM_FAILURE 3 OTHERS …

【论文阅读——Profit Allocation for Federated Learning】

1.摘要 由于更为严格的数据管理法规&#xff0c;如《通用数据保护条例》&#xff08;GDPR&#xff09;&#xff0c;传统的机器学习服务生产模式正在转向联邦学习这一范式。联邦学习允许多个数据提供者在其本地保留数据的同时&#xff0c;协作训练一个共享模型。推动联邦学习实…

开发日志2024-04-12

开发日志2024/04/12 1、分店月业绩和年业绩都需要添加为真实数据 **开发思路&#xff1a;**分店下所属的技师的业绩总和 代码实现&#xff1a; 前端 无 后端 //TODO 将技师多对应的积分累加到他所属的分店的月/年累计业绩销量中//TODO 查询技师所对应的分店地址String f…

智算时代的基础设施如何实现可继承可演进?浪潮云海发布 InCloud OS V8 新一代架构平台

从 2023 年开始持续火爆的 AIGC 正在加速落地应用&#xff0c;为全行业带来生产生活效率的变革与升级。面对数字化转型与智能化转型&#xff0c;对于技术团队来说&#xff0c;既要根据业务与 AI 应用去部署以云为基础的 AI 算力&#xff0c;又要与已有数据和系统&#xff08;甚…

网络流量分析与控制

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计5477字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

架构设计参考项目系列主题:新零售SaaS架构:客户管理系统架构设计

什么是客户管理系统? 客户管理系统,也称为CRM(Customer Relationship Management),主要目标是建立、发展和维护好客户关系。 CRM系统围绕客户全生命周期的管理,吸引和留存客户,实现缩短销售周期、降低销售成本、增加销售收入的目的,从而提高企业的盈利能力和竞争力。 …

YOLOV5 分类:利用yolov5进行图像分类

1、前言 之前介绍了yolov5的目标检测示例,这次将介绍yolov5的分类展示 目标检测:YOLOv5 项目:训练代码和参数详细介绍(train)_yolov5训练代码的详解-CSDN博客 yolov5和其他网络的性能对比 yolov5分类的代码部分在这 2、数据集准备 yolov5分类的数据集就是常规的摆放方式…

PyCharm远程链接AutoDL

AutoDL使用方法&#xff1a; Step1&#xff1a;确认您安装的PyCharm是社区版还是专业版&#xff0c;只有专业版才支持远程开发功能。 Step2&#xff1a;开机实例 复制自己实例的SSH指令&#xff0c;比如&#xff1a;ssh -p 38076 rootregion-1.autodl.com 在ssh -p 38076 roo…

AWS CloudFront + Route53 + EC2 + Certificate Manager

CloudFront Route53 EC2 Certificate Manager 教程 先理解它是怎么运转的 用户请求Route53解析到CloudFront&#xff0c;CloudFront解析EC2也就是资源。 了解了运作&#xff0c;接下来就一步步实现 首先处理CloudFront解析资源EC2 EC2是服务器&#xff0c;并不是资源&…

SQLite从出生到现在(发布历史记录)(二十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;从 SQLite 3.5.9 迁移到 3.6.0&#xff08;二十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 引言&#xff1a; SQLite拥有别人无法比拟的装机量&#xff0c;究竟什么成就了SQLite呢&#xff0c;本…

uni-app调用苹果登录,并获取用户信息

效果 模块配置 dev中的配置 需要开启登录的权限&#xff0c;然后重新下载配置文件&#xff0c;发布打包基座&#xff0c;再运行程序 代码 <button click"appleLogin">苹果登录</button>function appleLogin() {uni.login({provider: apple,success: …

预印本仓库ArXiv——防止论文录用前被别人剽窃

文章目录 一、什么是预印本二、什么是ArXiv2.1 ArXiv的领域2.2 如何使用 一、什么是预印本 预印本&#xff08;Preprint&#xff09;是指科研工作者的研究成果还未在正式出版物上发表&#xff0c;而出于和同行交流目的自愿先在学术会议上或通过互联网发布的科研论文、科技报告…

使用了代理IP怎么还会被封?代理IP到底有没有效果?

代理IP作为一种网络工具&#xff0c;被广泛应用于各种场景&#xff0c;例如网络爬虫、海外购物、规避地区限制等。然而&#xff0c;很多用户在使用代理IP的过程中却发现自己的账号被封禁&#xff0c;这让他们不禁产生疑问&#xff1a;使用了代理IP怎么还会被封&#xff1f;代理…

前端开发攻略---简化响应式设计:利用 SCSS 优雅管理媒体查询

1、演示 2、未优化前的代码 .header {width: 100px;height: 100px;background-color: red; } media (min-width: 320px) and (max-width: 480px) {.header {width: 10px;} } media (min-width: 320px) and (max-width: 480px) {.header {height: 20px;} } media (min-width: 48…

Pygame教程10:在背景图片上,添加一个雪花特效

------------★Pygame系列教程★------------ Pygame经典游戏&#xff1a;贪吃蛇 Pygame教程01&#xff1a;初识pygame游戏模块 Pygame教程02&#xff1a;图片的加载缩放旋转显示操作 Pygame教程03&#xff1a;文本显示字体加载transform方法 Pygame教程04&#xff1a;dra…

【银行测试】性能瓶颈出现崩溃怎么办?支付类测试关注点整理...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、银行系统线上因…

基于springboot实现桂林旅游景点导游平台管理系统【项目源码+论文说明】

基于springboot实现桂林旅游景点导游平台管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了桂林旅游景点导游平台的开发全过程。通过分析桂林旅游景点导游平台管理的不足&#xff0c;创建了一个计算…

速率再次翻倍!现有SSD显卡又要被强制换代了

去年 AMD Ryzen 7000 和 Intel 第 13 代 CPU 发布的同时&#xff0c;消费级的 PCI-E 5.0 平台出现在了大众视野。 这个用了快 20 年的接口虽然外形上似乎没变过、新老平台通吃&#xff0c;但其实内在已更新了好多个版本了。 和 3.0 换 4.0 一样&#xff0c;5.0、6.0 换代只是时…

全国火情预报卫星遥感应用方案

一、引言 火情预报应急卫星遥感解决方案是一种利用卫星遥感技术进行火灾预警和应急响应的方法。该方案通过实时监测和分析森林、草原等地区的火情信息&#xff0c;为火灾预警和应急响应提供科学依据&#xff0c;有效减少火灾造成的损失。本技术文档将介绍火情预报应急卫…