C++复合类型(二)——指针

程序在存储数据时,需要知道数据类型、数据值、数据被存储在哪里。
获取内存两种方式:声明变量获得内存,动态分配内存!
C++支持通过声明变量达到上述的目的:类型、访问符合名(可得数据值)、程序会为数据分配内存空间并跟踪该内存单元。其实,声明变量在静态编译下已经可以很好地表示我们希望存储的数据,但我们希望能更灵活的操作内存空间,比如,对于一个数组,运行时才确定数组的大小,为此C++提供了动态声明数组的语句,以实现在运行时分配内存空间,相较于编译时可确定类型长度的数组来说,动态生成的数组在内存中没有变量名称,对于未命名的内存空间用指针变量来访问其数据值。(new 支持动态分配内存空间,指针用来跟踪新分配的内存位置)
从上面叙述中,可以看出指针变量的提出,是为了解决访问未命名的内存空间的数据值。否则,用变量就够了,指针最大的用途在于动态分配内存访问数据值。当然对于一个变量,通过&可得地址并将其存入指针变量,通过解除引用符*可得指针变量所指向内存空间的数据值。
对于在内存中有名称的变量来说,既可以简单的使用变量名来获取其数据值,也可使用指针来访问该数据,无论是利用哪一种方式修改了数据值,通过另一种方式访问数据值时也会发生相应的改变。

一、指针基本用法
1.声明及初始化指针变量
指针就是地址,对于程序来说,存储数据时需要知道数据值、内存位置、类型;数据值可通过指针获取,位置即指针,数据类型则是声明中要指定的,想想看,在获取某一地址的数据值时,不知道数据类型,又怎么能取出正确的数据来呢?(知道是int类型的,那么只需要连续取出四个字节机试所存储的值)
可以认为指针变量的类型是复合类型,指针是个地址,但不仅仅是个地址,是个指向特定数据类型的地址,可以说指针也有多个类型;
int * p:p的类型是指向int的指针
内存也会为指针变量分配内存空间,但是指针变量占用空间的大小是确定的,无论其类型是什么。通常指针占用2个或4个字节。
2.特别注意的地方
不要对未初始化的指针变量解除引用!!!未初始化的指针变量意味着随机的指向内存的一个数据块,使用解除引用得到的值也是非法值,或是对该地址执行的内存空间赋值,如果内存地址中存储了其他有用的值,相当于篡改了有效值,程序将产生未定义行为。
对指针使用*前,确保指针存储的是一个我们知道的地址。
3.指针类型和整数类型区分
从数据表示来看,指针的值也是用整形数表示,但指针变量是有含义的,表示一个指向确定类型的地址;而整形变量没有含义。此外,两种类型支持的运算不同。哪怕我们知道一个内存的地址,但我们不能直接将一个十六进制的数值直接赋值给指针,而通过强制类型转化可将整形转为指针类型。
4.使用new来动态分配内存
为数据对象分配内存空间:数据类型* pointer=new 数据类型(数据类型可以是数组,结构,基本类型)
用new动态分配内存空间得到的未命名的变量,其地址在自由存储区或堆中;而静态分配的变量地址在栈中。

int main()
{

	int x = 100;
	int *p1 = &x;
	int *p2 = new int;
	*p2 = x;
	cout << x << " " << p1 << endl;
	cout << *p2 << " " << p2 << endl;
	cin.get();
	return 0;	
}


堆和栈
堆和栈地址明显不一样

内存被耗尽无法为变量分配内存空间,将返回空指针nullptr,保证不指向任何有效数据。
5.使用delete释放内存地址
采用new分配的内存空间,必须用delete释放,不服从于自由变量规则(作用域结束,自动释放通过变量声明获取到的内存空间,new所申请的内存空间不会被释放)。
对于通过声明变量获得的内存空间不可以用delete显示释放
我们delete的对象是什么?是由new向内存空间申请来的地址(空间),因此可以delete另一个指针变量,只要这个指针变量也是指向new所申请到的内存空间。

int *p2 = new int;
	*p2 = x;
	int *p3 = p2;
	cout << x << " " << p1 << endl;
	cout << *p2 << " " << p2 << endl;
	delete p3;//delete p2 无所谓 p2或p3,反正他们的值都是通过new 申请来的地址 只要是new申请的内存就得手动释放

6.使用new动态创建数组
静态联编:变量声明创建数组,编译时将固定大小的数组加入程序
动态联编:运行时确定数组大小并将数组加入程序
创建动态数组:
类型* pointer =new 类型[个数] ,需要指出数组元素的个数,再为数组分配好了内存空间后,将第一个元素的地址值返回给一个指针变量。利用该指针变量可以访问数组的其余元素(支持数组表示法和指针方式)。
释放动态数组:
delete[] pointer

访问动态数组:
方式一:数组表示法
将返回的指针当数组名来使用,比如pointer[0],pointer[1]…
数组名是个不可变的,但指针变量是可变的

//没想到for也是在运行时加入到程序中
    int n;
	cout << "input numbers:";
	cin >> n;
	int *p4 = new int[n];
	for (int i = 0; i < n; i++)
		p4[i] = i;
	for (int i = 0; i < n; i++)
		cout << p4[i] << " ";

二、数组与指针等效性解释
指针算术:对指针变量+1实际上是其确切类型字节数的累加,比如,指向int类型的指针,对其加1,若以字节为内存单位,其指针值是加了4(一个int类型的变量是4字节)。怎么理解+1呢?可以想成取出一个完整的数据。
多数情况下,可以将数组名解释为第一个元素的地址,但是sizeof(数组名)获得是整个数组所占的字节数
编译器将数组表示法转化为指针表示:
p4[i] == *(p4 + i)
所以可以拿数组名当指针用,也可以拿指针当数组名使用
对于数组来说,指针减运算可获得元素间隔。

三、指针与字符串
利用cout 输出,对象为字符地址时,包括用数组表示的字符串、字符串字面值、指向字符的指针,将他们统一看作第一个字符指针传递给cout,有了指针便可得内存中的字符,一直输出字符直到遇到空字符。
char p="hello ":
在计算机内存中,专门留了一片空间存储字符串字面值,并记录值和地址间的关系。因此,p指向的就是字符串hello。
char name[10]=“hello”:
name就是字符h的地址
从输入流中接收一个字符串时,可以使用new申请的内存空间,也可使用一个足够大的数组,千万别用未初始化的字符指针,输入的字符串最后都不知道被存哪里去了。
cout后面若是指针,通常输出地址,但如果指针类型是指向字符的,输出字符串,用(int
*)强制转化便可以输出地址。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值