首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

C++指针等于地址加偏移量

编程知识
2024年10月02日 17:59

概述

本文通过c++示例代码演示指针的加减法运算及对 “指针 = 地址 + 偏移量” 的理解。

研究示例

1. 首先来检查各种变量类型所占的内存大小

#include <iostream>
using namespace std;

int main(){
	cout << sizeof(char) << endl;      // 1 Byte
	cout << sizeof(short) << endl;     // 2 Byte
	cout << sizeof(int) << endl;       // 4 Byte
	cout << sizeof(long long) << endl; // 8 Byte
	return 0;
}

2. 各类型的指针进行加减运算

各类型的指针进行加减运算是以元素为单位进行加减,而非地址的最小单位(1个Byte)。以下演示各类型指针指向的地址:

#include <iostream>
using namespace std;

int main(){
	char *p_char = new char('a');
	cout << "*p_char = " << *p_char << endl; 
	cout << "p_char = " << (void*)p_char << endl;    // char指针在使用cout输出会直接打印变量而非地址,要加(void*)
	cout << "p_char + 1 = " << (void*)(p_char + 1) << endl; 
	cout << "p_char + 2 = " << (void*)(p_char + 2) << endl; 
	cout << "p_char - 1 = " << (void*)(p_char - 1) << endl; 

	short *p_short = new short(456);
	cout << "*p_short = " << *p_short << endl; 
	cout << "p_short = " << p_short << endl; 
	cout << "p_short + 1 = " << p_short + 1 << endl; 
	cout << "p_short + 2 = " << p_short + 2 << endl; 
	cout << "p_short - 1 = " << p_short - 1 << endl; 

	int *p_int = new int(123);
	cout << "*p_int = " << *p_int << endl; 
	cout << "p_int = " << p_int << endl; 
	cout << "p_int + 1 = " << p_int + 1 << endl; 
	cout << "p_int + 2 = " << p_int + 2 << endl; 
	cout << "p_int - 1 = " << p_int - 1 << endl; 

	long long *p_long_long = new long long(456789);
	cout << "*p_long_long = " << *p_long_long << endl; 
	cout << "p_long_long = " << p_long_long << endl; 
	cout << "p_long_long + 1 = " << p_long_long + 1 << endl; 
	cout << "p_long_long + 2 = " << p_long_long + 2 << endl; 
	cout << "p_long_long - 1 = " << p_long_long - 1 << endl; 

	return 0;
}

输出:(char, short, int, long long的指针的最小移动单位分别是1, 2, 4, 8 Byte,刚好是对应的单个元素的类型所占内存大小)

*p_char = a
p_char = 0xe41600
p_char + 1 = 0xe41601
p_char + 2 = 0xe41602
p_char - 1 = 0xe415ff
*p_short = 456
p_short = 0xe41620
p_short + 1 = 0xe41622
p_short + 2 = 0xe41624
p_short - 1 = 0xe4161e
*p_int = 123
p_int = 0xe41640
p_int + 1 = 0xe41644
p_int + 2 = 0xe41648
p_int - 1 = 0xe4163c
*p_long_long = 456789
p_long_long = 0xe41660
p_long_long + 1 = 0xe41668
p_long_long + 2 = 0xe41670
p_long_long - 1 = 0xe41658

说明:指针 = 地址 + 偏移量。即指针除了包含地址信息之外,还包含解析这个地址的方式(从该地址开始向后读取多少个Byte),因此“指针就是地址”的说法是不准确的,一个int* p1和char* p2 指向的地址可能是相同的,但是解析这个地址的方式是不同的。

3. 强制转换指针类型对地址进行解析

可以强行指定指针的类型对同一块内存的数据进行不同方式的解析。例如:

#include <iostream>
using namespace std;

int main(){
	char arr[10] = {0,1,2,3,4,5,6,7,8,9};
	unsigned int l = sizeof(arr)/sizeof(arr[0]);

	char* p_char = arr;
	cout << "*p_char = " << (int)*p_char << endl; 
	cout << "*(p_char + 1) = " << (int) *(p_char + 1) << endl; 
	cout << "*(p_char + 2) = " << (int)*(p_char + 2) << endl; 
	cout << "*(p_char + 3) = " << (int)*(p_char + 3) << endl; 
	cout << "*(p_char + 9) = " << (int)*(p_char + 9) << endl; 
		
	short* p_short = (short*)arr;
	cout << hex << "*p_short = " << *p_short << endl; 
	cout << hex << "*(p_short + 1) = " << *(p_short + 1) << endl; 
	cout << hex << "*(p_short + 2) = " << *(p_short + 2) << endl; 
	
	int *p_int = (int*)arr;
	cout << hex << "*p_int = " << *p_int << endl; 
	cout << hex << "*(p_int + 1) = " << *(p_int + 1) << endl; 
	cout << hex << "*(p_int + 2) = " << *(p_int + 2) << endl; 

	return 0;
}

输出:

*p_char = 0
*(p_char + 1) = 1
*(p_char + 2) = 2
*(p_char + 3) = 3
*(p_char + 9) = 9
*p_short = 100
*(p_short + 1) = 302
*(p_short + 2) = 504
*p_int = 3020100
*(p_int + 1) = 7060504
*(p_int + 2) = fdf60908

解释如下图:arr数组在内存中占10个Byte,分别定义了三种类型的指针char*, short*, int*并且都指向首地址arr[0],则三种指针的差异体现在两个方面:1、解引用(解析地址)时的偏移量分别为1,2,4个Byte;2、加减时分别以1,2,4个Byte为单位移动地址。

注意:

1、本编译器采用小端模式,因此*p_short = 0x0100 而非 0x0001。

2、*(p_int + 2)访问到了未知的内存,因此结果中打印出来了不受控制的数据"0xfdf60908",警示了我们在使用指针时,尤其是涉及到类型转换、加减运算、赋值等操作时,一定要避免指针越界,否则将会产生不可预知的危险后果。

总结

本文通过几个简单的c++程序验证了 “指针 = 地址 + 偏移量” 这一结论,希望能对指针如何操作内存有更深入的理解。

另外,本文所讨论的指针均为变量指针,而函数指针不能进行加减运算(会报warning: pointer to a function used in arithmetic),我会另写一篇文章讨论函数指针。

From:https://www.cnblogs.com/phyjack/p/18444984
本文地址: http://www.shuzixingkong.net/article/2445
0评论
提交 加载更多评论
其他文章 transaction_timeout:达到事务超时时终止会话
功能实现背景说明 我们已经有两个参数来控制长事务:statement_timeout 和 idle_in_transaction_session_timeout。但是,如果事务执行的命令足够短且不超过 statement_timeout,并且命令之间的暂停时间适合 idle_in_transacti
transaction_timeout:达到事务超时时终止会话 transaction_timeout:达到事务超时时终止会话 transaction_timeout:达到事务超时时终止会话
《痞子衡嵌入式半月刊》 第 108 期
痞子衡嵌入式半月刊: 第 108 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻,农历年分二十四节气,希望在每个交节之日准时发布一期。 本期刊是开源项目(GitHub: JayHeng/pzh-mcu-bi-weekly),欢迎提交 issue,投稿或推荐你知道的嵌入式那些事儿。 上期回
《痞子衡嵌入式半月刊》 第 108 期 《痞子衡嵌入式半月刊》 第 108 期 《痞子衡嵌入式半月刊》 第 108 期
Nuxt.js 应用中的 app:rendered 钩子详解
title: Nuxt.js 应用中的 app:rendered 钩子详解 date: 2024/10/2 updated: 2024/10/2 author: cmdragon excerpt: 摘要:本文详细介绍了 Nuxt.js 应用程序中的 app:rendered 钩子,包括其定义、调用时
Nuxt.js 应用中的 app:rendered 钩子详解 Nuxt.js 应用中的 app:rendered 钩子详解
【Wing】背后的插件们
wing 作为我们日常开发的命令行开发工具,项目开源以来,陆陆续续接入了多个插件,在这里集中分享给大家。
【Wing】背后的插件们 【Wing】背后的插件们 【Wing】背后的插件们
Blazor开发框架Known-V2.0.13
大家好,国庆节快乐,Known又更新了一波功能。 继上个版本以来,一直在完善网站文档、KnownCMS开源项目和解决框架客户提出的一些问题。这期间客户反馈的问题主要如下: 微信模板消息收不到,查其原因是网络问题,因此本版本改成后台任务发送消息 无代码页面模板需要自定义 无代码表单字段组件需要自定义
Blazor开发框架Known-V2.0.13
Linux_动态库与静态库(其一)
1.动态库和静态库的定义 动态库(.so):动态库是编译后不嵌入目标文件中的共享库,在程序运行的时候才去链接动态库的代码,可以被多个程序共享使用,通常以 .so 结尾。 静态库(.a):静态库是将一组目标文件(.o文件)打包成一个单一的归档文件。在编译时,链接器会将所需的目标文件代码复制到最终生成的
Linux_动态库与静态库(其一) Linux_动态库与静态库(其一) Linux_动态库与静态库(其一)
Nuxt.js 应用中的 app:redirected 钩子详解
title: Nuxt.js 应用中的 app:redirected 钩子详解 date: 2024/10/3 updated: 2024/10/3 author: cmdragon excerpt: app:redirected 是 Nuxt.js 中的一个钩子,主要用于处理服务器端渲染(SSR)
Nuxt.js 应用中的 app:redirected 钩子详解 Nuxt.js 应用中的 app:redirected 钩子详解
全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串
在Python中,字符编码是将字符映射为字节的过程,而字节序列(bytes)则是存储这些字节的实际数据结构,字节序列和可变字节字符串的主要区别在于其可变性和用途,bytearray是可变的字节序列,允许修改其内容。
全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串 全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串 全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串