1.概述
程序在运行时,所有的程序和数据都存放在内存中。内存是以字节为单位的连续的存储空间,每个内存单元有唯一的内存编号,称为内存地址,每个变量都有自己的内存地址,系统对内存单元进行操作时,需要通过内存地址找到相应的内存单元。
一般来说,对于简单数据类型,通过变量名就可以对内存单元进行操作,如:i=400,不需要知道内存地址,很多高级程序语言都不允许通过内存地址访问内存单元,C和c++中则可以通过指针类型对允许通过地址来访问内存单元,只不过这个地址的确切值不需要程序员了解;
对于变量i,如果用另一个变量p记住他的内存地址,变量p的数据类型就是指针类型。如果p的内容是I的地址,则称为p指向i;
int i = 20;
int* p = &i;
如果有定义int*p,则说明p是一个指针变量,p的内容应该是一个内存地址,通过取地址符&可以使得p指向另一个存储单元,p本身要占用一个内存单元;
1.指针的声明和初始化
由于指针是变量,需要在使用之前先定义,定义格式:
指针所指的数据类型 *指针变量名1,2.....
如:
int * p_int;
*
称为解除引用运算符,*
两侧的空格可选,一般来说,C语言倾向于使用这种方式:
int *p;//强调*p是一个int 类型的值
c++倾向使用这种方式:
int* p;//强调p是一个指向int类型数据的指针
指针运算符&和*:&是取地址运算符,*是解除引用运算符,二者都是单目运算符。
2.指针注意事项
- 1.在c++中创建指针时,计算机分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存,如:
int *age;
*age = 21;//bad
由于没有说明age指向哪里,那么21将被随机地放在内存中的一个地址中,从而可能会导致错误的发生。
因此,一定要在对指针使用*
运算符之前,将指针初始化为一个确定的地址。
- 2.在定义指针变量时,可以将其定义为指向任何一种基本数据类型的存储单元,当使用取地址运算符为其赋值时,所指向的数据类型要一致,如:
int i;
float *p;
p=&i;
这样是错误的.
- 3.
*
的含义不同,它可以作为算术运算符,还可以作为定义指针使用,还可以作为指针取内容运算符;比如如下示例中:
int i;
int *p= &i;
*p=i*3;
-
4.指针只是概念上的地址,不必关心它的值是什么,因为对于某个变量来说,内存空间是由系统分配的,在C语言中不能将内存地址赋值给一个指针变量,如:
int *p;p=3000;
这是错误的; -
5.指向相同的数据类型的指针可以相互赋值,如:
int x = 2;
int *pi;
int *pj;
pi=&x;
pj=pi;
这样一来,pj也就指向x了。
3.指针和数组
我们知道,可以通过new来动态申请一个数组,并返回第一个元素的地址:
int* arr = new int[size];
如此一来,指针arr就指向arr[0].
我们又知道,数组是一段连续的存储空间,数组名是该存储空间的首地址:
int arr2[5];
arr2[0]是数组arr2中的第一个元素,所以数组名arr2表示arr2[0]的首地址。
因此在C++中,大多数情况下,指针和数组基本等价,两者可以相互替代。
在如下示例中,可以通过指针来操作数组:
#include <iostream>
using namespace std;
const int Size = 5;
int main()
{
int arr[Size] = {
1,2,3,4,5};
for(int i =0;i< Size;i++)
{
cout << "arr[" << i<< "]:" << *(arr+i) << endl;
}
return 0;
}
然而也有例外,在以下三种情况下,数组名和指针不同:
- 1.数组声明使用数组名来标记存储位置;
- 2.数组名使用
sizeof()
运算符时,返回整个数组的长度; - 3.将地址运算符&用于数组名时,将返回整个数组的地址;
一般情况下,以下语句都是允许的:
int arr[3]