区块链技术博客
www.b2bchain.cn

New关键字、引用&与指针的学习记录

这篇文章主要介绍了New关键字、引用&与指针的学习记录的讲解,通过具体代码实例进行16913 讲解,并且分析了New关键字、引用&与指针的学习记录的详细步骤与相关技巧,需要的朋友可以参考下https://www.b2bchain.cn/?p=16913

本文实例讲述了2、树莓派设置连接WiFi,开启VNC等等的讲解。分享给大家供大家参考文章查询地址https://www.b2bchain.cn/7039.html。具体如下:

文章目录

  • 一、New关键字的学习
  • 二、&的学习
  • 三、指针的学习
  • 1.指针是什么?
  • 2.变量在程序中的储存
  • 3.指针对象(变量)
    • 3.1定义指针对象
    • 3.2获取对象地址
    • 3.3解析地址对象
    • 3.4指针值的状态
    • 3.5指针之间的赋值
  • 4.指针内含信息
  • 5.函数和指针
    • 5.1函数的参数和指针
    • 5.2函数的指针
    • 5.3返回值和指针
  • 6.const与指针
    • 6.1常量指针
    • 6.2指向常量的指针
  • 小结


一、New关键字的学习

1.C++通过new关键字进行动态分配内存。
2.new开辟的空间存储在堆上,而我们定义的变量存储在栈上。
3.new分配的空间使用delete释放,new[]使用delete[]释放。

Int* pi = new int(5); //表示动态分配一个int,初始化为5 Int* 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,假设计算机使用大端方式存储:
New关键字、引用&与指针的学习记录
内存数据有几点规律:
①计算机中的所有数据都是以二进制进行存储的
②数据类型决定了占用内存的大小
③占据内存的地址就是地址值最小的那个字节的地址。

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

3.指针对象(变量)

用来保存指针的对象,就是指针对象。
如果指针变量p1保存了变量a的地址,则就是说:p1指向了变量a,也可以说p1指向了a所在的内存块,这种指向关系,在图中一般用箭头表示:
New关键字、引用&与指针的学习记录
指针对象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的空间应确保可以存放任意字符对应的数字值。
整型
New关键字、引用&与指针的学习记录
浮点型,即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 <iostream> int main() { int age = 19; int* p_age = &age; *p_age = 20;  //通过指针修改指向的内存数据  std::cout<<"age = "<<*p_age<<"n";  //通过指针读取指向的内存数据 std::cout<<"age = "<<age<<std::endl;  return 0; } 

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

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"<<p_stu->name<<"age"<<p_stu->age<<"score"<<p_stu->score 	<<std::endl; 	return 0; } 

3.4指针值的状态

指针的值(即地址)总会是下列四种状态之一:
①指向一个对象的地址
②指向紧邻对象所占空间的下一个位置
③空指针,意味着指针没有指向任何对象
④无效指针,上述情况之外的其他值

3.5指针之间的赋值

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

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

4.指针内含信息

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

5.函数和指针

5.1函数的参数和指针

实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。
这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。

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

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

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

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

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

这样返回值就是age = 20

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

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

5.2函数的指针

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

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

#include <iostream>  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"<<c<<std::endl; std::cout<<"The value of d"<<d<<std::endl;  return 0; } 

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;  //正确 

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

小结

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

本文转自互联网,侵权联系删除New关键字、引用&与指针的学习记录

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » New关键字、引用&与指针的学习记录
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们