自学笔记,不喜勿喷,如有错误,欢迎指正
文章目录
运算符名称
在地址运算中
&表示取地址,寻址,取址
*表示解引用
当然在程序运行中,这两种运算符也存在复用的情况
运算符的其他含义(复用)
&
1、按位与(两个与连起来&&,是条件与)
eg:
0101&0001=0001
2、引用(在C++当中)
就是给变量取别名
eg:
int a = 10;
int &ref = a; // ref是a的引用
ref = 20; // 修改ref等同于修改a
// 此时 a == 20
*
乘法运算
地址运算
取地址&
int a=10;
int* b=&a;
cout<<a<<endl;
cout<<b<<endl;
运行结果:
10
0x8f036e75a466
在这里10就a存储的值,0x8f036e75a466就是a在内存当中的地址
解引用*
需要注意的是*在声明/定义中,和运算中的含义不同
int a=10;
int* b=&a;
cout<<a<<endl;
cout<<*b<<endl;
运行结果:
10
10
理解
取地址&与解引用*二者互为逆运算
取地址&可以理解为这间房子里面住着我大舅,我要知道我大舅家的地址
解引用*可以理解为我知道我二舅家的地址,我去找我二舅
指针的定义与运算
指针的定义
对于个人习惯而言我更喜欢如下的方式
int* b=&a;
但实际上int【空格】*【空格】b之间的空格是随意的,也就是说,也可以是如下的形式
int * b=&a;
int *b=&a;
int*b=&a;
理解:
int*可以看作一个整体,表示int类型的指针
int* b=&a;
(也可以这么理解,但我觉得这么理解有一个小bug)
int看作整型类型,b表示对b进行解应用,也就是b这个地址所对应的解应用的数据是int。 (但这么理解无法解释将&a赋给b)
cpp int *b=&a;
需要注意的是,int类型的指针这一概念不是说这个指针的存储类型是int(在内存当中所占的空间),而是指所存储的这个地址地一个属性。
举例:
int* b=&a;
char* d=&c;
在这里b是int类型的指针,其存储a的地址,
对于a而言:a的存储占4个字节(也可能是两个,具体根据系统定,比如在单片机中就是2个字节)
对于b来说:b(0x8f036e75a466)的存储占6个字节
而d是char类型的指针,其存储c的地址,
对于c而言:c的存储占1个字节
对于d来说:d(0x8f036e75a46a)的存储占6个字节
也就是说指针的类型这个概念,只是属性,并不代表实际的存储空间,指针的存储空间是由内存容量决定的,整个内存有多少地址,需要多少位来进行寻址,则指针的存储就占几位。
那可能有人就要问了,既然指针的存储空间是一定的,并且在不同的主机上占的不一样,为什么还要在声明/定义的时候来规定他的类型呢?为什么要赋予他这种属性呢?
这就体现在指针的运算上了
指针的运算
对于指针而言,其运算只有两种,一种是加,另一种是减,对地址的乘除是没有意义的。
加运算
还是上面的例子
int* b=&a;
b++;
char* d=&c;
d++;
b(0x8f036e75a466)“属性”:int(4字节)
自加一之后变为0x8f036e75a466+4=0x8f036e75a46a
d(0x8f036e75a46a)“属性”:char(2字节)
自加一之后变为0x8f036e75a46a+2=0x8f036e75a46c
总结:
将指针变量加一后,其增加的值等于指向类型占用的字节数。
new关键字分配内存(C++)
new
在c当中,使用malloc来分配内存,小白可能不太知道这个函数,实际上这个函数也包含在<stdio.h>当中,也就是说和一开始咱们最一开始使用的printf这个函数是一个地位。
在C++中分配内存被定义成了关键字new。
举例:
int* p = new int;
运行过程:
我们告诉new,我们需要的内存大小(要四个字节,也就是int),new为我们在堆区找到一块合适的内存大小,并返回他的地址。返回的地址被我们付给指针p。
需要注意的是,使用new分配的内存是没有名称的,只能通过指针来进行访问。
什么叫没有名称呢?还是上面的例子。
int a=10;
int* b=&a;
a就是存储这个内容为10的内存的名称,我们可以通过a(这个变量名)或者是*b(对指针解应用)的方式来访问这块内存。
需要注意的是,这里创建的变量,如果是在函数中,则存储在栈区。如果全局变量,则存储在全局/静态存储区
可能有人就要问了,占用内存的什么区域有什么关系吗?在此我简单提及一下。
堆区:new分配的内存在堆区,使用new分配完之后需要使用delete进行进行内存释放,如果不释放则会一直占用,直到程序运行结束由操作系统释放。
栈区:函数的局部变量存放的地方,函数运行结束时被释放。
全局/静态存储区:全局变量和静态变量存储的地方。程序运行结束后释放。
delete
使用new分配的内存都需要使用delete进行释放。需要注意:
1、一个new和一个delete对应。
2、new完不delete会造成内存泄漏。
3、new完多次delete是不允许的。
4、不可delete声明变量获得的内存。
new与动态数组(这部分之后再写)
数组与指针
首先,我们来复习一下数组的定义:一块连续的存储空间,当中数组的名字就是数组第一个元素的地址。
举例:
int a[10]={0,1,2,3,4,5,6,7,8,9};
a就是a[0]的地址。即
a=&a[0];
这里我们对数组与地址做两个深入的思考。
1、数组的指针表示方法
由上可知,数组第一个元素a[0]的地址是a,即
a==&a[0];
也可以说对a进行解引用,得到a[0],即
a[0]==*a;
那数组第二个第三个…元素呢?这里直接给出
a[1]==*(a+1);
a[2]==*(a+2);
a[3]==*(a+3);
...
这就体现出来将指针变量加一后,其增加的值等于指向类型占用的字节数。
引用一下C++ Primer Plus的原话
将指针(包括数组名)加1,实际上是加上了一个与指指向的类型的长度(以字节为单位)相等的值。对于遍历数组而言,使用指针加法和数组下标时等效的。
同时这里引用C++ Primer Plus当中的一张图片,便于大家更好的理解。
需要注意的是,使用sizeof()函数对数组名使用,得到的是数组的长度,这里的数组名没有解释成地址。而对指针使用得到的是指针的长度。
2、对数组名取地址
由上面的论述可知,数组名即为数组首元素的地址,那如果我们进行以下操作呢?
int a[10]={0,1,2,3,4,5,6,7,8,9};
cout<<a<<endl;
cout<<&a<<endl;//对数组名取地址
会得到什么呢?地址的地址吗?
实际上不是的,在这里数组名也没有解释成为地址,实际的输出为,
0x8f036e75a485
0x8f036e75a485
是的,这两个输出是一样的,但是含义却不一样。
对于a(也就是&a[0])是一块4字节的内存
对于&a则是一块4x10字节的内存
也就是说
int a[10]={0,1,2,3,4,5,6,7,8,9};
cout<<a+1<<endl;
cout<<&a+1<<endl;//对数组名取地址
得到:
0x8f036e75a485 + 4 = 0x8f036e75a489
0x8f036e75a485 + 4 x 10 = 0x8f036e75a4c5
这就又体现出来属性的概念
a的属性是int*
&a的属性是int(*)[20]