指针

本系列文章主要参照C++Primer Plus,以及网上的一些文章。讲述一下在学习C++时碰到的一些重点难点,以及面试时有可能会问的点。本文介绍的是指针的内容。

指针

计算机存储数据必须有的3个属性为

  • 信息存储的地方
  • 信息的值
  • 信息的类型

其中指针是用于跟踪数据在内存中的位置,知道了指针的值,就能够在内存找到其位置,并对其操作。指针的简单应用可以参考其他文章,在这里不赘述。

1. new关键字

new是在C++中才引入的用来分配内存的关键字,在C中是用malloc来分配内存。

1.1 new与delete

和C中的malloc、free对应类似,在C++中用new分配内存后,如果该内存不再使用,则应该用delete释放,否则该内存在整个程序运行周期将一直被占用,也就是内存泄漏,如果程序很大时,可能会导致崩溃。
new 与delete的应用如下:

int *pt = new int;
//some code here
delete pt;

//some different for dynamic array
int *pt = new int[10];
//some code here
delete []pt;

当用new创建一个指针时,用delete直接将其删除即可,如果创建的是一个动态数组,则在delete后需要加一个中括号[],才能将整段数组空间释放,否则只是释放该指针指向的第一个元素的空间。

1.2 new 与 malloc的异同

在面试时,有时会问到new与malloc的联系,下边总结一下我能理解的异同。

  • 1.返回类型不一样

在使用new分配内存时,返回的内存就是对象类型的指针。同时如果对象是类,则还会调用类的构造函数,初始化成员变量,再返回对象类型的指针。如下

int *a = new int;//返回的是类型为int的指针
SomeClass *b = new SomeClass();// 返回的是类SomeClass的指针,并调用默认构造函数

而用malloc时,返回的是一个void(*)的指针,如果要使用的话需要用强制类型转换。并且由于malloc是C中的库函数,因此没有调用类的构造函数的权限,因此整个过程只是声明了一块空间。

int* p;
p = (int *) malloc (sizeof(int));// malloc返回的指针需要用强制类型转换为int*类型
  • 2.两者在分配内存失败时的操作不一样

在用new分配内存时,如果分配失败,会抛出bad_alloc异常终止程序。
而用malloc分配内存时,如果分配失败,则会返回一个空指针,程序会继续运行。
所以在用malloc时,通常要在其后边添加判断其是否空指针的判断代码。

  • 3.分配内存时是否需要指定大小

在用malloc分配内存时,需要显示指定其分配空间的大小。
而用new的话,会根据类型进行自动计算需要分配空间的大小。

int *a = (int*)malloc(sizeof(int));//分配4个字节大小的空间
int *b = new int;//分配4个字节大小的空间

int *c = (int*)malloc(sizeof(int)*100)//分配可储存100个整形变量的空间
int *d = new int[100]; //分配100个整形变量空间并返回第一个空间的指针
  • 4.是否有调用构造函数和析构函数

在使用new和delete来声明类时,除了分配以及释放空间,还会根据声明的类型来调用类的构造函数和析构函数,而malloc则没有这个功能。
原因是malloc是C中的库函数,没有能够调用类的构造和析构函数的权限,而new是C++中的运算符,因此可以调用。

int main(){
	A *a = new A();//创建一个A类大小的储存空间,并调用构造函数,此处可调用默认构造函数
	delete a;//释放a的空间,并调用其析构函数
	return 0;
}
  • 5. 两者的内存区域不一样

对于malloc,其分配的内存空间位于堆中。堆是操作系统的术语,是操作系统维护的一块的内存,用于程序的内存分配。
对于new,其分配的内存空间位于自由存储区,自由存储区是基于new的一个抽象术语,凡事用new分配的内存就称为是自由存储区,其区域可以不位于堆中。

2 指针算术

指针算术其实很简单,以前使用比较少所以不太熟悉。在一些笔试题中使用指针算术的话十分方便。
C++中允许指针和整数相加,加1的结果是原来地址值加上指向对象的总字节数。如下:

int a[10] = {9,8,7,6,5,4,3,2,1,0};
int *pt = a;

cout<<*pt<<endl;//打印 9,也就是a[0]
pt++;
cout<<*pt<<endl;//打印 8
pt+=2;
cout<<*pt<<endl;//打印 6

在C++中,数组名是解释为第一个元素的地址,因此将a赋值给pt后,pt指向的就是a的第一个元素,pt++后指向a的第二个元素,以此类推。

3 指针与字符串

在C++中,引入了string作为表示字符串的方式,但是这里不讨论string的用法,而是说一下用字符指针来表示C-风格字符串的方式。

char flower[10] = "rose";
cout<<flower;

以上代码创建一个长度为10的字符数组并将前4个字符初始化为"rose"。但是在输出的时候也只是输出rose,并不是只输出第一个字符r,也没有输出后边6个字符。

这是因为在初始化字符时,默认会首先将每个字符设置为空字符"\0",然后再根据情况对其初始化。在输出时程序会从第一个字符开始逐个打印,直到碰到空字符就认为已经到达字符串的末尾,之后的内容就不再输出。

char animal[10] = "bear";
char *ps;
ps = animal;
cout<<animal<<" "<<(int*)animal<<endl;
cout<<ps<<" "<<(int*)ps<<endl;

ps = new char[strlen(animal)+1]
strcpy(ps,animal);
cout<<animal<<" "<<(int*)animal<<endl;
cout<<ps<<" "<<(int*)ps<<endl;

以上代码可以两部分,第一部分声明了animal的字符串并将其初始化为bear,之后通过等于号将其赋给字符串指针ps。然后打印两个变量的值和地址,正常输出的话animal和ps两个变量的值和地址是一模一样的。意味着这两个变量是指向同一块内存单元,这时如果对其中一个进行修改的话也会改变另一个,这应该不是我们想要的。

这时因为在进行ps=animal的赋值运算时,并不是将animal变量的内容赋值给ps,而是把地址赋值,因此完成后两者的地址和变量变得一模一样。

如果需要将animal的值赋予给ps,但是并不赋予地址,这时可以用代码下半部分的方法,利用strcpy函数来实现这个功能。首先在ps中申请好足够的空间,代码中是用new申请足够空间给ps指针。然后再应用strcpy函数将animal中的字符串内容拷贝到ps里。打印两个变量发现,此时它们的地址已经不一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值