C/C++指针入门(自用笔记)

自学笔记,不喜勿喷,如有错误,欢迎指正

运算符名称

在地址运算中
&表示取地址,寻址,取址
*表示解引用
当然在程序运行中,这两种运算符也存在复用的情况

运算符的其他含义(复用)

&

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当中的一张图片,便于大家更好的理解。
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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值