指针和一维数组
一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既可以指向变量,当然也可以指向数组元素。所谓数组元素的指针就是数组元素的地址。
eg:
int a[6]; //定义一个整数数组a,它有6个元素
int *p; //定义一个整型的指针变量 *p
//下述表达等价
p=&a[0]; //将元素a[0]的地址赋给指针p,使p指向a[0]
p=a //数组名代表数组第一个元素,所以该式与p=&a[0]等价
如果p的初始值是&a[0],则需要注意:
①p+i和a+i就是a[i]的地址,或者说,它们指向a数组的第i个元素(如果p已经指向数组中的一个元素了,则p+1指向下一个元素)
②*(p+i)或*(a+i)是p+i或a+i所指向的数组元素的值
③指向数组元素的指针变量也可以带下标,如p[i]和*(p+i)等价
指针和二维数组
首先,定义一个二维数组:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}
- 上述的二维数组是由3个一维数组构成的,即a数组包含3行:a[0]行,a[1]行,a[2]行,每个一维数组又包含4个数组元素,由此可见二维数组是“数组的数组”
- a是数组名,代表二维数组首元素的地址,现在的首元素不是一个整型变量,而是由四个整型元素所组成的一维数组,因此a代表的是首行的起始地址(即第0行的起始地址,&a[0]),a+1代表a[1]行的首地址,即&a[1]
- C++规定了数组名代表数组首元素的地址,所以a[0],a[1],a[2]就是一维数组名,所以a[0]相当于&a[0][0],a[1]相当于&a[1][0],a[2]相当于&a[2][0]
- 0行1列元素的地址可以直接写为&a[0][1],用指针表示为a[0]+1,所以i行j列的元素的地址用指针表示为a[i]+j
- i行j列元素的值用指针表示为*(a[i]+j)或者 *( *(a+i)+j)
字符指针和字符数组
char str[]="I love C++"; //用字符数组存放一个字符串
char *str="I love C++"; //用字符指针指向一个字符串
上述两种方式打印的str结果是一样的。
那他们有什么不同呢?
- 存储方式的不同
char str1[]="hello";
char str2[]="hello";
“hello"是一个常量,保存在常量存储区,所以str1并不是数组"hello"的首地址,它只是一个变量,保存在栈中,str2也是在栈中申请了额外的空间保存"hello”,所以这里str1不等于str2。
const char str3[]="hello";
const char str4[]="hello";
使用const定义的变量一般是不分配内存的,而是保存在符号表中。但是对于const数组来讲,系统不确定符号表是否有足够的空间来存放const数组,所以还是为const数组分配内存的,因此str3和str4都各自分配了内存,因而不相等。
const char* str5[]="hello";
const char* str6[]="hello";
这里str5和str6都是指针,保存在符号表上,指向的是常量存储区中的"hello",所以str5=str6。
- 赋值方式不同
对字符指针变量可采用下面的方式赋值,但是字符数组不行,对字符数组只能对各个元素赋值
const char* array;
array="I love C++"; //合法
//下列表述不合法
char str[10];
str="I love C++";
- 指针变量的值是可以改变的,但是字符数组名是不能改变的
const char *array="welcome to C++";
array=array+1; //此时array打印结果为"elcome to C++"
指针数组和数组指针
指针数组:即存储指针的数组,首先它是一个数组,数组的元素都是指针,数组占多少字节由数组本身决定。
数组指针:即指向数组的指针,首先它是一个指针,它指向一个数组。
- 指针数组定义
int *p1[10]
:首先,[]的优先级比 * 要高,所以p1先与[]结合,构成一个数组定义,数组名为p1。其次,“ int * ”修饰的是数组内容,也就是说,指针数组中的每一个元素相当于一个指针变量,它的值都是地址。 - 数组指针定义
int (*p2)[10]
:这里()的优先级比[]高,*和p2构成一个指针定义,指针变量名为p2,int修饰的是数组的内容,即数组的每个元素,数组在这里并没有名字,是个匿名数组。所以p2是一个指针,指向一个包含10个int类型数据的数组。
指向指针的指针
指针可以指向一份普通的数据,也可以指向一份指针类型的数据。
eg:
int a=10;
int *p1=&a;
int **p2=&p1
他们的关系如下:
const指针
const关键字指定了一个不可修改的变量,但并不是常量,它可以使编译器帮助用户定义的某些变量不被意外修改。
(1)指针包含的地址是常量,不能被修改,但可以修改指针指向的数据
eg:
int x=30;
int* const p=&x;
*p=33; //指向的数据可以更改
int y=28;
p=&y; //不能更改地址
(2)指针指向的数据为常量,不能修改,但可以修改指针包含的地址,即指针可以指向其他地方
int x=50;
const int* p=&x;
int y=25;
p=&y; //可以更改指针的地址
*p=20; //不能更改指针指向的数据
注:通过上述一二可以看出,当const在 * 前时,其修饰的是指针指向的内容,但指针本身是可变的,当const在 * 后面时,其修饰的是指针本身,但其指向的内容是可变的。
(3)指针包含的地址以及它指向的值都是常量,不能修改
eg:
int x=12;
const int* const p=&x; //此时都不能修改