C++学习 六、指针

前言

指针是C,C++与其它语言的一大区别,也是C++程序设计里的难点。

本篇学习C++指针的基本用法。

指针与地址

地址是内存空间的位置,指针是保存地址的特殊数据类型。

广义的说,指针就是地址,指针变量用于存储地址。

狭义的说,地址就是内存空间的编号,而指针有具体的存储数据类型(比如int *p;),因此指针不完全是地址。

指针使用

声明指针

声明指针必须说明是指向什么数据类型的指针(这样才能确定数据在内存空间的使用量):

int *p_int;
double *p_double;

指针变量的创建细节

声明指针时,计算机会给指针变量分配内存空间用于存储地址,但是不会给指针指向的数据分配内存空间,下面的使用方法将报错:

int *p_n;
*p_n = 0;

声明指针p_n时,系统给p_n分配了内存空间,其地址为addr1,存储的是p_n;但系统没有在p_n存储的地址addr2分配空间,因此addr2是个未定值,系统不知道把0放到哪个地址上,因而报错。

取地址符

&被用于取得变量的地址:

int variable = 0;
std::cout << &variable;

初始化

可以在声明指针时初始化指针:

int a = 2;
int *p_a = &a;

指针p_a被初始化,获得a的地址,指向变量a

赋值

可以通过赋值运算符,把地址赋给指针:

int b = 2;
int *p_b;
p_b = &b;

指针的整形赋值

计算机将指针当作整数处理,但指针和整形是两种不同的数据类型,指针没有乘除计算。因此不能简单的把整形赋给指针,必须使用强制类型转换:

int *p_s = (int *) 0x10000000;

算术运算

指针有加减法:

int *pp = new int;
cout << (pp + 1); // pp地址后的一个位置

比如pp=0x10000000,pp + 1 = 0x10000004,即地址增加了4个字节的长度(int类型长度)。

在数组中的两个元素的指针相减,能得到两个元素的间隔。

指针解引用(取值运算符)

*除了是指针类型名,还用于取得指针指向的数据,也叫指针的解引用:

double c = 5.2f;
double *p_c = &c;
std::cout << *p_c;

区分指针类型与解引用

在声明和初始化中,*表示声明的是指针类型。

在指针变量被声明和赋值后,*表示的是指针解引用。

short d = 1;
short *p_d = &d; // 声明指针类型
*p_d; // 解引用

动态内存分配

定义变量是一种分配内存空间的方法(自动变量,栈空间):

int e = 5; // 在栈空间中分配内存
int *p_e = &e;

使用new是另一种分配内存空间的方法(动态存储,堆空间):

int *p_f = new int;

new TypeName在内存空间中找到一块满足TypeName类型的块,返回内存空间的地址。

动态数组

new TypeName []用于创建动态数组:

int *p_vec = new int [10];

``delete []````用于释放动态数组空间:

delete [] p_vec;

动态内存释放

动态分配的内存空间,如果不需要再使用时,要及时通过delete释放,new,delete要成对使用。否则容易出现内存泄漏memory leak。

delete不会把指针删除,而是释放指针指向的内存空间。空间释放后,最好把指针置空:

int *p_g = new int;
delete p_g;
p_g = nullptr;

delete不能释放栈空间上的内存,但是可以delete空指针。

也不能对同一个指针释放两次,会报double free的错误。

C++11推出了智能指针,能够降低内存泄漏的风险。

数组名与指针

C++中,数组和指针基本是等价的,数组名表示数组第1个元素的地址。区别在于,数组名的值是不能改变的,但指针变量的值是可以改变的。通过指针访问数组元素:

p_vec[1] = 1; // 使数组第2个元素为1;
*(p_vec + 1) = 1; // equal;

需要注意,对数组使用sizeof得到数组长度,对一个指向数组的指针应用sizeof得到指针长度。

指针数组与数组指针

指针数组

指针数组,变量名表示一个数组,也就是数组中的每个元素都是一个指针,:

int* vec_p[5];

上面这个声明中,[]*的优先级高,因此vec_p[5]是一个数组,而int*指定了数组类型为整形指针。

指针数组常用于字符串数组:

char* vec_string[2] {"Hello, ", "World!"};

数组指针

数组指针,变量名表示一个指针,指向整个数组:

int (*p_vec)[10];

上面这个声明中,首先声明了p_vec是一个指针,指向一个10元素整形数组。此时,p_vec + 1是p_vec地址后40个字节的位置。

数组指针常用于多维数组(比如OpenCV中Mat数据读取),举个二维数组的例子:

ushort pixel[5][10];
ushort (*p_pixel)[10] = pixel;
(*(p_pixel + 2))[4] = 3 // 设置第3行,第5列数据的值为3
std::cout << (*(p_pixel + 2))[4]; // 输出第3行,第5列数据的值

p_pixel[2][4] = 3; // equal

对数组取地址

数组名表示数组首元素的地址,对数组取地址也会获得数组的地址,但二者的含义是不一样的:

int vec[5] {0, 1, 2, 3, 4};
std::cout << vec << "\n";
std::cout << &vec << "\n";

std::cout << (vec + 1) << "\n";
std::cout << (&vec + 1) << "\n";

结果:

0x7ffe8742ebd0
0x7ffe8742ebd0
0x7ffe8742ebd4
0x7ffe8742ebe4

取数组的地址时,返回的是整个数组的地址,也就是包含5个int元素的地址,&vec + 1的地址为数组首元素地址 + 5 * 4

而数组名,就是数组首元素的地址,vec + 1的地址为数组首元素地址 + 4

指针与字符串

C++中,char数组名,char指针,字符串常量都被解释为字符串中第一个字符的地址。

cout提供一个字符的地址,将从该字符开始打印,直到遇到空字符为止,比如:

char str[6] = "hello";
std::cout << str;

结果:

hello

cout虽然接收的是char地址,但输出是字符串。如果要打印字符串的地址,则必须使用强制类型转换:

std::cout << (int *) str;

:发现可以使用字符串常量的列表初始化字符串数组:

char str[6] {"hello"};

后记

本篇记录了C++中指针的基本使用,以及指针和数组,字符串的关系,下一篇将学习枚举和结构体。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值