C语言一维数组指针的用法(非常详细)
在 C 语言程序中,指针变量可以指向普通变量,也可以指向数组。
【实例】数组指针的初步使用。
指针变量指向数组的方法有两种:
这两种方法的代码分别如下:
【实例】数组元素地址分析。

图 1 数组元素地址
对地址进行乘和除是没有意义的,下面将讨论对地址进行加减运算。
若已知指针变量 p 指向一个数组,则可以进行以下运算。
加一个整数,如:
减一个整数,如:
自加运算,如:
自减运算,如:
两个指针相减,如:
指针变量 p 指向一个数组元素,则 p+1 指向同一个数组中的下一个元素,p−1 指向同一个数组中的上一个元素。
在执行 p+1 操作时,不是指针变量 p 中的地址值加 1,而是指针变量 p 中的绝对地址值加指针变量 p 的类型所占的字节数。此处指针变量 p 为整型变量对应移动 4 个字节,执行 p−1 操作与 p+1 操作同理。
【实例】数组元素的地址运算。
对数组的数组名进行取地址(&)操作,其类型为整个数组类型。对数组进行取地址操作,其类型为整个数组,因此,&ch_arr 的类型是
假设指针变量 p 指向数组 arr[0],则 *(p+i)、*(arr+i)、arr[i] 三者是等价的,均表示 arr[i] 的实际值。[] 是变址运算符,arr[i] 实际上按照 arr+i 计算地址,然后找出地址中对应的值。
【实例】通过数组指针变量遍历数组。
【实例】数组指针的初步使用。
#include <stdio.h> int main () { int i_arr[5] = {1,2,3,4,5}; //定义数组 int *p_i; //定义指针变量 p_i = i_arr; //将数组i_arr的首地址赋给指针变量p_i printf("i_arr[0]的地址:%p\n",&i_arr[0]); printf("p_i中保存的地址:%p\n",p_i); return 0; }编译运行,结果如下:
i_arr[0]的地址:0060FE88 p_i中保存的地址:0060FE88由两个输出结果中相同的地址可知,数组名并不代表整个数组,只代表数组首个元素的地址。在此次程序运行过程中,数组的首地址不会发生改变,即数组名为常量。“p_i = i_arr;”的作用是“把 i_arr 数组的首元素地址赋给指针变量 p_i”,等同于“把 i_arr[0] 的地址赋给指针变量 p_i”。
指针变量指向数组的方法有两种:
- 一种是将数组名赋给指针变量;
- 另一种是将数组的首元素取地址后赋给指针变量。
这两种方法的代码分别如下:
p_i = i_arr; p_i = &i_arr[0];
【实例】数组元素地址分析。
#include <stdio.h> int main () { int i_arr[5] = {1,2,3,4,5}; int *p_i_a = &i_arr[0]; //为了方便,地址使用十六进制数输出 printf("i_arr[0]的地址:%x\n",p_i_a); p_i_a = &i_arr[1]; printf("i_arr[1]的地址:%x\n",p_i_a); p_i_a = &i_arr[2]; printf("i_arr[2]的地址:%x\n",p_i_a); p_i_a = &i_arr[3]; printf("i_arr[3]的地址:%x\n",p_i_a); p_i_a = &i_arr[4]; printf("i_arr[4]的地址:%x\n",p_i_a); int *p_i_b = &i_arr[0]; printf("p_i_b中保存的地址:%x\n",p_i_b); p_i_b++; printf("p_i_b中保存的地址:%x\n",p_i_b); p_i_b += 1; //即p_i_ b = p_i_ b + 1 printf("p_i_b中保存的地址:%x\n",p_i_b); return 0; }编译运行,结果如下:
i_arr[0]的地址:60FE84
i_arr[1]的地址:60fe88
i_arr[2]的地址:60FE8C
i_arr[3]的地址:60FE90
i_arr[4]的地址:60FE94
p_i_b中保存的地址:60FE84
p_i_b中保存的地址:60FE88
p_i_b中保存的地址:60FE8C

图 1 数组元素地址
指针运算
指针就是地址,地址在本质上是整数,所以对地址可以进行赋值运算。在一定条件下,还可以对地址进行算术运算。对地址进行乘和除是没有意义的,下面将讨论对地址进行加减运算。
若已知指针变量 p 指向一个数组,则可以进行以下运算。
加一个整数,如:
p=p+1; //或者p+=1;
减一个整数,如:
p=p-1; //或者p-=1;
自加运算,如:
p++; //或者++p;
自减运算,如:
p--; //或者--p;
两个指针相减,如:
p=p_2-p_1; //当p_1和p_2都指向同一个数组中的元素时才有意义
指针变量 p 指向一个数组元素,则 p+1 指向同一个数组中的下一个元素,p−1 指向同一个数组中的上一个元素。
在执行 p+1 操作时,不是指针变量 p 中的地址值加 1,而是指针变量 p 中的绝对地址值加指针变量 p 的类型所占的字节数。此处指针变量 p 为整型变量对应移动 4 个字节,执行 p−1 操作与 p+1 操作同理。
【实例】数组元素的地址运算。
#include <stdio.h> int main () { int i_arr[3] = {1,2,3}; char ch_arr[3] = {'!','@','#'}; int *p_i = &i_arr[0]; char *p_ch = &ch_arr[0]; //对数组的数组名进行取地址(&)操作,其类型为整个数组类型 //p_ch_arr的3个值为数组ch_arr 3个元素的地址 char (*p_ch_arr)[3] = &ch_arr; printf("p_i中保存的地址: %x\n",p_i); p_i = p_i + 1; printf("p_i + 1后,p_i保存的地址: %x\n",p_i); printf("p_ch中保存的地址: %x\n",p_ch); p_ch = p_ch + 1; printf("p_ch+1后,保存的地址: %x\n",p_ch); printf("p_ch+1后,地址对应的数据: %c\n",*p_ch); printf("p_ch_arr[0]地址: %x\n",p_ch_arr[0]); printf("p_ch_arr[0]地址对应的数据: %c\n",*p_ch_arr[0]); return 0; }编译运行,结果如下:
p_i中保存的地址: 60FE8c
p_i+1后,p_i保存的地址: 60FE90
p_ch中保存的地址: 60FE89
p_ch+1后,保存的地址: 60FE8A
p_ch+1后,地址对应的数据: @
p_ch_arr[0]地址: 60FE89
p_ch_arr[0]地址对应的数据: !
p_i = p_i + 1
运算后,指针变量 p_i 前后的地址值相差 4;而 char 型指针变量 p_ch 进行 p_ch = p_ch + 1
运算后,指针变量 p_ch 前后的地址值相差 1。由此可知:
-
p_i + n 的地址实际上是
p_i = p_i + n×4
(指针变量 p_i 为 int 型,int 型变量所占字节数为 4); -
p_ch + n 的地址实际上是
p_ch + n×1
(指针变量 p_ch 为 char 型,char 型变量所占字节数为 1)。
对数组的数组名进行取地址(&)操作,其类型为整个数组类型。对数组进行取地址操作,其类型为整个数组,因此,&ch_arr 的类型是
char (*)[3]
。所以正确的赋值方式如下:char (*p_ch_arr)[3] = &ch_arr;在代码中,[ ] 的优先级高于 *,() 是必须要加。如果只写作
int *p_ch_arr [3]
,那么应该理解为 int *( p_ch_arr [3])
,p_ch_arr 就成了一个指针数组,而不是二维数组的指针。一维数组指针的使用
可以用两种方法来访问一维数组的元素:- 下标法:使用下标 arr[i] 的形式访问数组元素。
- 指针法:使用 *(arr+i) 的形式访问数组元素;当指针变量 p 指向数组时,用 *(p+i) 的形式访问数组元素。
假设指针变量 p 指向数组 arr[0],则 *(p+i)、*(arr+i)、arr[i] 三者是等价的,均表示 arr[i] 的实际值。[] 是变址运算符,arr[i] 实际上按照 arr+i 计算地址,然后找出地址中对应的值。
【实例】通过数组指针变量遍历数组。
#include <stdio.h> #define LOOP 3 int main() { int i_arr[] = {1, 2, 3}; int i, *p_i = i_arr; for(i = 0; i < LOOP; i++) { printf("%d 即 %d 即 %d\n", *p_i++, i_arr[i], *(i_arr+i)); } return 0; }编译运行,结果如下:
1 即 1 即 1
2 即 2 即 2
3 即 3 即 3