C++基础语法:new定位符的一点思考

本文详细介绍了C++中new运算符的使用,包括内存分配、静态内存和动态内存的区分,以及如何通过定位符进行地址偏移。重点强调了new函数对输入地址类型的要求,特别是char*的特殊性。作者还探讨了内存操作在硬件映射中的应用和C++相对于C的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

        打牢基础,才能写出准确的代码.C++ Prime Plus第六版

引入:

        C++提供了new来使用程序的内存空间,并且提供了定位符功能.

一.举例

data.h

namespace myns {
	struct datas {
		int age;
		int position;
	};
}

new运算符和定位符.cpp

#ifndef new运算符和定位符_H
#define new运算符和定位符_H
#include<iostream>
#include"data.h"
const int NUMBER = 512;

int main() {
	using myns::datas;
	using namespace std;
	char* p = new char[NUMBER];												//分配静态内存,具体地址未知.用char分配内存,其他类型有问题
	for (int i = 0; i < NUMBER; i++) {
		p[i] = 65;															//给元素赋值,看使用该地址的地方是否能用
	}
	cout << "分配空间返回地址是:" << (void*)p << endl;						//打印分配静态内存的地址,如果直接用p,得到字符串非地址
	//把一个含有5个整型的数组放到地址中,可以放数组,可以放对象,所以所有类型数据都可以放到某个位置
	int* pip = new(p) int[5];
	for (int i = 0; i < 5; i++) {
			cout <<"已赋值是:"<< pip[i] << endl;							//警告"未初始化内存pip[i]"但不出错,可以使用地址中已赋值
	}
	cout << "定位后使用空间地址是:" << pip << endl;							//调用定位符new函数的返回值就是定位地址,和上面地址相同
	//delete[] p;															//释放内存,为了下面程序不出错,注释
	for (int i = 0; i < 5; i++) {

		cout << "你需要的数字是:" << pip[i] << endl;						//如果释放内存,结果会改变;此时不变
	}
	cout << "整型数据长度为:" << sizeof(int) << endl;
	cout << "double型数据长度为:" << sizeof(double) << endl;

	double* dp = new(p + 5 * sizeof(int)) double;							//地址偏移5个int;
	cout << "偏移5个整型量后现在所在地址是:" << dp << endl;					//打印当前地址,验证和上面地址是否偏移了20个字节,结果正确

	char* dpm = (char*)(p + 5 * sizeof(int));								//计算地址并强转类型
	double* dp3 = new(dpm) double;											//地址偏移5个int;
	cout << "偏移5个整型量后现在所在地址是:" << dp3 << endl;				//打印当前地址,验证和上面地址是否一致,结果正确

	datas* pstruct = new(p + 5 * sizeof(int) +sizeof(double)) datas[2];		//数组放到指定位置,地址偏移1个double类型
	cout << "偏移1个double后现在所在地址是:" << pstruct << endl;			//打印当前地址,验证和上面地址是否偏移了8个字节,结果正确

	datas* ps = new(dp +sizeof(double)) datas[2];							//警告并得不到正确结果,提示"sizeof 和 countof 量值之间可能不一致。使用 sizeof() 调整字节大小"
	cout << "偏移1个double后现在所在地址是:" << ps << endl;					//打印当前地址,验证和上面地址是否偏移了8个字节,结果错误,64个字节	

	char *dp4 = (char*)(p + 5 * sizeof(int) + sizeof(double));				//计算地址并强转类型
	datas* ps2 = new(dp4) datas[2];											//警告同上
	cout << "偏移1个double后现在所在地址是:" << ps2 << endl;				//打印当前地址,验证和上面地址是否偏移了8个字节,结果正确

	//for (int i = 0; i < 2; i++) {											//给结构赋值
	//	cout << "请输入第" << i << "个的年龄:" << endl;
	//	cin >> pstruct[i].age;
	//	cout << "请输入第" << i << "个的位置:" << endl;
	//	cin >> pstruct[i].position;
	// }

	int* ip = new(p + 5 * sizeof(int) + sizeof(double) + 2 * sizeof(datas)) int;//地址再次偏移;
	cout << "偏移1个datas后现在所在地址是:" << ip << endl;						//打印当前地址,相差16字节,结果正确
	char* pp = (char*)(dpm + sizeof(double) + 2 * sizeof(datas));
	int* ip2 = new(pp) int;
	cout << "偏移1个datas后现在所在地址是:" << ip2 << endl;						//打印当前地址,验证是否和上面一致,结果正确
}
#endif

二.代码说明

怎样方便使用位置偏移,

datas* ps = new(dp +sizeof(double)) datas[2];   //这句里的写法最方便,但是得不到正确的结果.

参考自C++ Prime Plus Edition 6th.  里面没提到new定位符的函数原型,提到了返回值是(void *)可被任意指针接收. 但其传入的地址其实是有要求的,类型为char *,字符指针.所以在每次偏移地址时,将返回值类型强转后才可以继续调用new()定位函数.   

char* dpm = (char*)(p + 5 * sizeof(int));                //计算地址并强转类型

同样,在分配空间时用new char[],得到不会产生歧义的结果.

三.引申

1.char *作为形参传入函数,而这里表示定位地址. 我们知道char *另外有个含义是字符串.所以可以推导出字符串实际上是有单独地址的.

2.虽然类型是地址,但是char *和int *,double *,或者其他类型的地址的数据类型不一样.从例子中可以反映出来.

四 映射硬件

在C++ Prime Plus Edition 6th中,有一句提到了可以控制硬件,但具体操作没说.因为话题会牵涉到操作系统.,不能简单说完.首先语言中使用的内存是虚拟内存,操作系统负责将其转化为物理内存.物理内存可以映射到硬件的寄存器上.这中间可能还会涉及硬件驱动程序.但一般会由硬件设计人员提供接口给软件设计者使用.

C++语言繁琐,但是速度很快是其最大的优势所在.而速度快的原因在于可以直接操作内存.直接操作内存,new定位符就是其中一种方式.下面就试想一下操作内存的两种方式.

假设屏幕上有一个点,有3个寄存器控制颜色,每个寄存器为1字节.其中1个寄存器控制红色,1个控制绿色,1个控制蓝色.(当3个值都为0显示白色,都为255时显示黑色,其余颜色由不同数值控制).这三个寄存器的虚拟地址为0x1a2b3c4d,0x1a2b3c4e,0x1a2b3c4f.

1.直接取得地址,向其中写数据        

char *red=(char *)0x1a2b3c4d;
char *green=(char *)0x1a2b3c4e;
char *blue=(char *)0x1a2b3c4f;

*red=128;
*green=128;
*blue=128;

2.使用定位符,定位地址

char *color=new(0x1a2b3c4d) char[3];
color[0]=128;  //红色寄存器
color[1]=128;  //绿色寄存器
color[2]=128;  //蓝色寄存器

这里因为假设地址是在一起的,所以可以把字节型数组放到起始地址上,逐个赋值.

上述数据是简单类型和数组类型,其他复杂类型,全部用对象或者结构来写入,方法是一样的.

题外话:

C++比C语言繁琐,但应用起来会方便一些.举例:如果有复杂的数据类型,比如某种数据结构来表示的数据,(树的结点还是树),在C++里可以用容器类,结点是容器类对象来表示.如果用C语言的话,定义数据结构的每层增删查都要写算法,相对麻烦.

结语:

new定位符使用时注意传入地址的数据类型是char *.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jllws1

你的鼓励是我创作的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值