指针
是一种数据类型,就像 int和 float,int 装整型数据,float 装浮点型数据,指针装地址型
数据。
C语言中的地址包括位置信息(内存编号,或称纯地址)
和它所指向的数据的类型信息
,或者说它是“带类型的地址”。
指向是什么意思?简而言之,指针变量装哪块地址,它就指向哪一块空间。指针的类型
决定着指针对存储空间的读写方式
,所以首先指针与被指对象的类型要对应
。
内存操作符“ * ”
:一个指针p
指向一个变量的地址,“ *p ”
,就是这个变量本身。p所指向的空间是什么类型( 如int ),那么 *p 就一次操作多大的内存空间( 4字节 ),或者说指针的读写单位就是多大( 4字节 )。
32位系统最大支持 4字节 指针,64位系统最大支持 8字节 指针。是指针所占空间大小,是装的地址值的空间大小,不是指针操作的空间大小。
二维数组有三个类型的地址:
int a[3][4];
&a[0][0] ———— 元素的地址,且等价于a[0](一维数组的名字),数组名字就是首元素的首地址
&a[0] ———— 一维数组的地址,且等价于a,数组名字就是首元素的首地址
&a ———— 二维数组自身的地址
a[i] ———— 二维数组的第i-1个元素,是一个一维数组,也是那个一维数组首元素的首地址
如果 a
是一维数组
,则 a[i]
代表 a 数组下标为i
的元素的存储单元。 a[i] 是一个有确定地址的存储单元
。
但如果 a
是二维数组
,则a[i]
仅为一维数组(名)
,它只是一个地址
,并不代表一个存储单元
,也不代表存储单元中的值(如同一维数组名只是一个指针常量一样)。
二者虽然地址相同
,但指向的数据类型
不同(基类型不同)。
如果用一个指针变量 p 来指向一个二维数组的一维数组
元素,应当这样定义:
int a[3][4] = {{0},{0},{0}};
// int (*p)[4] = a; 等价于 int (*p)[4] = a[0];
int (*p)[4] = a[1];
(*p)
有四个元素,每个元素为整型。也就是 p 所指向的对象是有四个整型元素的数组
,即 p 是指向一维数组
的指针。此时 p 只能指向一个包含 4 个元素的一维数组,不能指向一维数组中的某一元素。
这种情况多用于作函数参数,其他场景使用较少。
计算 a[i][j]
在数组中的相对位置(相对于数组起始位置的位移量/偏移量
)的计算公式为:i*c+j
,其中 c 为二维数组的列数(二维数组大小为 r×c
)
#include <stdio.h>
int main()
{
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
//int* p = a; // 左右类型不一致,非法操作,a==&a[0],为int(*)[4]类型
//int(*p)[4] = a; // p==a==&a[0],*p==a[0]==&a[0][0],**p==a[0][0]
//int* p = a[0]; // p==a[0]==&a[0][0],*p==a[0][0]
//int* p = &a[0][0]; // *p==a[0][0],(i*4+j)为指针偏移量
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
//printf("%-3d", *(*(p + i) + j) ); //int(*p)[4] = a;
//printf("%-3d", *(p + (i*4+j) ) ); //int* p = a[0];
//printf("%-3d", *(p + (i*4+j) ) ); //int* p = &a[0][0];
}
}
return 0;
}
可以对字符指针变量赋值,但不能对数组名赋值
。
char* a; //定义a为字符指针变量
a = "I Love You !" //将字符串的第一个元素的地址赋给a
//等价于char* a = "I Love You !";
使用字符数组时,只能采取定义数组时初始化
或逐个
对元素赋值
的方法,不能
用赋值语句对字符数组中全部元素整体赋值
。
char str[20]; //开辟20个储存字符数据的空间,并且str=str[0]的地址
str[0] = 'I'; //对字符数组元素赋值,合法
str = "I Love You !"; //数组名是地址,是常量,不能被赋值,非法
str[] = "I Love You !"; //不能用赋值语句对字符数组整体赋值,非法
指针变量的值是可以改变
的,而字符数组名代表一个固定的值
(数组首元素的地址),不能
改变。
char* a = "I Love You !";
a = a + 3;
printf("%s", a); // 输出:ove You ! 从a指向的字符开始的字符串
字符数组中的各元素
的值是可以改变的(可以对它们再赋值),但字符指针变量指向的字符串常量
中的内容是不可以被取代的(不能对它们再赋值)如:
char a[] = "China";
char* b = "Chinese";
a[2] = 'r'; //合法,r取代i
b[2] = 'e'; //非法,字符串常量不能改变