【C++】指针

一、什么是指针

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。

	int* ip; //一个整形的指针
	double* dp;//一个double类型的指针
	float* fp;//一个浮点型的指针
	char* cp;//一个字符型的指针

所有指针的值的实际数据类型,不管是整形、浮点型、字符型还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们一般用16进制表示。指针的值(虚拟地址值)使用一个机器字的大小来存储,也就是说,对于一个机器字为32位的电脑而言,指针的值(地址值)使用32位(4字节来存储)。它的虚拟地址空间是
[ 0 , 2 32 − 1 ] [0,{2^{32}-1}] [0,2321]
程序最多能访问2的32次幂个字节。这就是为什么xp这种32位系统的最大支持4GB内存的原因了。

因此可以理解为:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。

二、Null指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个Null值是一个良好的编程习惯。赋为Null值得指针被称为空指针。Null指针是一个定义在标准库中得值为零得常量。

在大多数的操作系统上,程序不允许访问地址为0的内存,因为该内存是操作系统保留的。然而,内存地址为0有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值,则假定它不指向任何东西。

三、指针数组

可能有一种情况,我们想要让数组存储指向int或char或其他数据类型的指针。指向整形的指针数组的声明:

int* ip[3]

在这里,ip声明为一个数组,由3个整形指针组成。因此,ip中看每一个元素,都是一个指向整形值得指针。

#include <iostream>
using namespace std;

int main()
{
	int data[3] = { 10,100,1000 };//整形数组
	int* ip[3]; //指针数组
	for (size_t i = 0; i < 3; i++)
	{
		ip[i] = &data[i];
	}
}

四、void*指针

void*指针是一种特殊的指针类型,可用于存放任意对象的地址,但是丢失了类型信息。如果想要完整的提取指向的数据,程序员就必须对这个指针做出正确的类型转换,然后再解指针。

五、函数和指针

5.1、函数的参数和指针

实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝,形参和实参只是在值上面一样,而不是同一个内存数据对象。这就意味着:这种数据传递是单向的,即从调用者传递给被调用者,而被调用者无法修改传递的参数达到回传的效果。

有时候我们可以使用函数的返回值来回传数据,在简单的情况下是可以的,但是如果返回值有其他用途(例如返回函数的执行状态量),或者要回传的数据不止一个,返回值就解决不了了。传递变量的指针就可以 轻松解决上述问题。,当然也可以用引用的方式。

传递指针还有另外一个原因:有时我们会传递类或者结构体对象,而类或者结构体占用的内存有时会比较大,通过值传递的方式会拷贝完整的数据,降低程序的效率。而指针只是固定大小的空间,效率比较高。当然如果你用C++,使用引用效率比指针更高。

5.2、函数的指针

每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区。既然是存在内存中,那么函数也是有自己的指针的。其实函数名单独进行使用时就是一个函数的指针。

#include <iostream>
using namespace std;

void swap(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}

int main()
{
	int a = 20, b = 30;
	cout << "swap之前" << "a:" << a << "  b:" << b << endl;
	
	void (*function)(int&, int&);//函数指针的声明
	function = swap;//给函数指针赋值
	function = &swap;//同上,两种写法而已

	function(a, b);//跟函数名一样使用
	(*function)(a, b);//同上,两种写法而已
}

5.3、返回值和指针

这里唯一需要注意的是 不要把非静态局部变量的地址返回。我们知道局部变量是在栈中的,有系统创建和销毁,返回之后的地址有可能有效也有可能无效,这样会造成bug。可以返回全局变量、静态的局部变量、动态内存等的地址返回。

六、const和指针

这里主要的就是指针常量和常量指针了,两者的区别是看const修饰的谁。

6.1、常量指针

实际是一个指针,指针本身是一个常量。必须在声明的时候初始化,并且不能够再被修改。

#include <iostream>
using namespace std;

int main()
{
	int b = 40;

	int* const ap = &b;//声明常量指针--实际是一个指针,但是本身是常量的。意味着必须在声明的时候初始化,并且不能够再被修改。
	ap = &b;//编译报错
}

6.2、指向常量的指针

所谓的指向常量的指针,仅仅要求不能通过该指针改变对象的值,但是对象的值可以通过其他途径进行改变。

#include <iostream>
using namespace std;

int main()
{
	int a = 30;
	int b = 40;

	const int* ptr = &a;//指向常量的指针---不能通过该指针改变对象的值。
	*ptr = b;//编译报错
	ptr = &b;//没有问题
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值