New关键字、引用&与指针的学习记录
发布日期:2022-02-06 00:27:03 浏览次数:22 分类:技术文章

本文共 4748 字,大约阅读时间需要 15 分钟。

文章目录


一、New关键字的学习

1.C++通过new关键字进行动态分配内存。

2.new开辟的空间存储在堆上,而我们定义的变量存储在栈上。
3.new分配的空间使用delete释放,new[]使用delete[]释放。

Int* pi = new int(5); //表示动态分配一个int,初始化为5Int* pa = new int[5]; //表示动态分配一个数组,数组大小为5

若定义了一个类A,类成员有 int i;

构造函数为:A::A(int _i):i(_i*_i);

A* pa = new A(3);

共做了三件事:
1.获得一块内存空间,空间大小为sizeof(A);
2.调用构造函数;
3.返回指针pa

二、&的学习

//1.取地址,int型指针b的值为a的地址int a = 1; int* b = &a;//2.引用,b是a的别名int a = 1;int &b = a;

三、指针的学习

1.指针是什么?

指针是“指向”另外一种类型的复合类型。复合类型是指基于其他类型定义的类型。

理解指针首先从内存说起,内存是一个很大的,线性的字节数组。每一个字节都是固定的大小,由8个二进制位组成。最关键的是,每一个字节都有一个唯一的编号,编号从0开始,一直到最后一个字节。程序加载到内存中后,在程序中使用的变量、常量、函数等数据都有自己唯一一个的编号,这个编号就是这个数据的地址。

指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们一般使用16进制表示。指针的值使用一个机器字的大小来存储,也就是说,对于一个机器字为w位的电脑而言,它的虚拟地址空间是0~2(w次幂)-1,程序最多能够访问2的w次幂个字节,这就是为什么xp这种32位系统最大支持4GB内存的原因。

因此可以理解为:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。

2.变量在程序中的储存

举一个最简单的例子int a = 1,假设计算机使用大端方式存储:

在这里插入图片描述
内存数据有几点规律:
①计算机中的所有数据都是以二进制进行存储的
②数据类型决定了占用内存的大小
③占据内存的地址就是地址值最小的那个字节的地址。

现在可以理解a在内存中为什么占用4个字节,而且首地址为0028FF40了。

3.指针对象(变量)

用来保存指针的对象,就是指针对象。

如果指针变量p1保存了变量a的地址,则就是说:p1指向了变量a,也可以说p1指向了a所在的内存块,这种指向关系,在图中一般用箭头表示:
在这里插入图片描述
指针对象p1也有自己的内存空间,32位机器占4个字节,64位机器占用8个字节。

3.1定义指针对象

定义指针变量时,在变量名前写一个*号,这个变量就变成了对应变量类型的指针变量。

必要时要加()来避免优先级的问题:

Int* p_int ;  //指向int类型的变量指针double* p_double;  //指向double类型的指针Student* p_stuct;  //类或结构体类型的指针Int** p_pointer;  //指向一个整形变量指针的指针Int(*p_aar)[3];  //指向含有3个int元素的数组的指针Int(*p_func)(int,int); //指向返回类型为int,有2个int形参的函数的指针

其中,几种基本的数据类型再进行简单的介绍

布尔型,即bool,它的取值只能为true或者false,分别代表非零与零。对布尔型的赋值可以直接用true或者false进行赋值。
字符型,即char,它是基本的字符类型,一个char的空间应确保可以存放任意字符对应的数字值。
整型
在这里插入图片描述
浮点型,即float数据类型,被认为是单精度,double数据类型通常是float的两倍大小,因此被认为是双精度。顾名思义,long double数据类型要比double要大。这些数据类型的确切大小取决于当前使用的计算机。可以唯一保证的是:
Double 至少与 float 一样大
Long double 至少与double 一样大

对于float数来说有效数字约为7位,所以整数部分占的位数越多,小数部分的精度就会越低,当整数部分超过9999999后小数部分已经完全无精度了。

而我们有时候采用float64,它在一个内存中占用8个字节,可以有效提高精度。

3.2获取对象地址

指针用于存放某个对象的地址,要想获取该地址,需要使用取地址符(&),如下:

int add(int a,int b){
return a+b;}int main(void){
int num = 97;float score = 10.00F;int arr[3] = {
1,2,3};int* p_num = #int* p_arr1 = arr; //p_arr1意思是指向数组的第一个元素float* p_score = &score;int (*p_arr)[3] = &arr;int (*fp_add)(int, int) = add;const char* p_msg = "Hi";return 0;}

通过上面可以看到&的使用,但是有几个例子没有使用&,因为这是特殊情况:

①数组名的值就是这个数组的第一个元素的地址
②函数名的值就是这个函数的地址
③字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称,也就是这个字符串在内存中的地址。

3.3解析地址对象

如果指针指向了一个对象,则允许使用解引用符(*)来访问该对象,如下:

#include 
int main(){
int age = 19;int* p_age = &age;*p_age = 20; //通过指针修改指向的内存数据std::cout<<"age = "<<*p_age<<"\n"; //通过指针读取指向的内存数据std::cout<<"age = "<
<

对于结构体和类,两者的差别很小,所以几乎可以等同,则使用->符号访问内部成员:

struct Student{
char name[31]; int age; float score;};int main(){
Student stu = {
"Bob", 19, 98.0}; Student* p_stu = &stu; p_stu->age = 20; p_stu->score = 99.0; std::cout<<"name"<
name<<"age"<
age<<"score"<
score <

3.4指针值的状态

指针的值(即地址)总会是下列四种状态之一:

①指向一个对象的地址
②指向紧邻对象所占空间的下一个位置
③空指针,意味着指针没有指向任何对象
④无效指针,上述情况之外的其他值

3.5指针之间的赋值

指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。指针之间的赋值是一种浅拷贝,就是在多个编程单元之间共享内存数据的高效的方法。

Int* p1 = &a;Int* p2 = p1;

4.指针内含信息

通过上面介绍,我们可以看出指针包含两部分信息:所指向的值和类型信息。

5.函数和指针

5.1函数的参数和指针

实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。

这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。

#include 
void change(int a){
a++; //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁。}int main(){
int age = 19; change(age); std::cout<<"age = "<

输出结果为age = 19,说明被调函数无法修改传递的参数达到回传的效果

有时候我们可以使用函数的返回值来回传数据,在简单的情况下是可以的,但是如果返回值有其他用途(例如返回函数的执行状态量),或者回传的数据不止一个,返回值就解决不了了。

传递变量的指针可以轻松解决上述问题

#include 
void change(int* a){
(*a)++; //因为传递的是age的地址,因此a指向内存数据age //当在函数中对指针a进行解地址时,会直接去内存中找到age这个数据,然后将它增1 }int main(){
int age = 19; change(&age); std::cout<<"age = "<

这样返回值就是age = 20

除了上述方法,还可以选择使用引用:

void change(int &a){
a++; //a就是age的别名,或者也可以说外号,所以对a进行加1同样就是对age//加1}int main(){
int age = 19; change(age); std::cout<<"age = "<

5.2函数的指针

每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。在程序载入到内存之后,函数的机器指令存放在一个特定的逻辑区域:代码区。既然是存放在内存中,那么函数也有自己的指针。

其实函数名单独使用时就是这个函数的指针。

#include 
int add(int a, int b) //函数的定义{
return a+b;}int main(){
int (*p_add)(int, int); //函数指针的声明p_add = add; //给函数指针赋值p_add = &add; //跟上面是一样的int c = p_add(1,2); //跟函数名一样使用int d = (*p_add)(1,2); //跟上面的调用是一样的std::cout<<"The value of c"<
<
<<"The value of d"<
<

5.3返回值和指针

这里唯一需要注意的是不要把非静态局部变量的地址返回。我们知道局部变量是在栈中的,由系统创建和销毁,返回之后的地址可能无效,这样会造成bug。

可以返回全局变量、静态的局部变量、动态内存等的地址返回。

6.const与指针

这里主要就是指针常量和常量指针,两者主要的区别是看const修饰的谁。

6.1常量指针

实际是个指针,指针本身是个常量。

Int a = 97;Int b = 98;Int* const p = &a;*p = 98; //正确P = &b;  //错误

常量指针必须初始化,而且一旦初始化完成,则它的值就不能改变了。

6.2指向常量的指针

Int a = 97;Int b = 98;Const int* p = &a;Int const *p = &a;  //两者的含义是一样的*p = 98;  //编译出错P = &b;  //正确

所谓指向常量的指针仅仅要求不能通过该指针改变对象的值,但是对象的值可以通过其他途径进行改变。

小结

今天又是摸鱼的一天…周一快乐[爱心]!

转载地址:https://blog.csdn.net/weixin_46181372/article/details/109579777 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:ROS初学者编写小乌龟以一定速度旋转一定角度的server
下一篇:odom坐标系的理解

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月09日 00时44分09秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章