首页 > 编程笔记 > C语言笔记 阅读:45

C语言一维数组指针的用法(非常详细)

在 C 语言程序中,指针变量可以指向普通变量,也可以指向数组。

【实例】数组指针的初步使用。
#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

可以看到,相邻数组元素的地址值相差 4,而数组元素数据类型为整型,整型数据正好占用4个字节。通过实例可知,地址 60FE84~60FE87 保存 i_arr[0] 的数据,地址 60FE88~60FE8B 保存 i_arr[1] 的数据,同理可知保存 i_arr[2]、i_arr[3]、i_arr[4] 数据的地址,如下图所示。


图 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]地址对应的数据: !

int 型指针变量 p_i 进行 p_i = p_i + 1 运算后,指针变量 p_i 前后的地址值相差 4;而 char 型指针变量 p_ch 进行 p_ch = p_ch + 1 运算后,指针变量 p_ch 前后的地址值相差 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 就成了一个指针数组,而不是二维数组的指针。

一维数组指针的使用

可以用两种方法来访问一维数组的元素:
假设指针变量 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

在这个例子中,通过数组指针变量 p 指向数组 i_arr,每次对其加 1,则指针变量 p 指向下一个数组元素。

相关文章