C语言学习-第八章 善于利用指针②-通过指针引用数组

1,367

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情

数组元素的指针

一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址

可以用一个指针变量指向一个数组元素。例如:

int a[10] = {1,3,5,7,9,11,13,15,17,19}; // 定义a为包含10个整型数据的数组
int *p; // 定义p为指向整型变量的指针变量
p = &a[0]; // 把a[0]元素的地址赋给指针变量p

引用数组元素可以用下标法,也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占内存少,运行速度快)

数组名代表数组中首元素(即序号为0的元素)的地址。

p = &a[0]; // p的值是a[0]的地址
p = a; // p的值是数组a首元素(即a[0])的地址

在引用数组元素时指针的运算

指针已指向一个数组元素时,可以对指针进行以下运算:

  • 加一个整数 p+1
  • 减一个整数 p-1
  • 自加运算 p++, ++p
  • 自减运算 p--, --p 两个指针相减,如p1-p2(只有p1和p2都指向同一数组中的元素时才有意义

如果指针变量p1和p2都指向同一数组中的元素,如执行p2-p1,结果是p2-p1的值(两个地址之差)除以数组元素的长度直接用p2-p1就可知道它们所指元素的相对距离

两个地址不能相加,如p1+p2是无实际意义的。

通过指针引用数组元素

  • 下标法 a[i]
  • 指针法 *(a+i)或*(p+i)

示例:有一个整型数组a,有10个元素,要求输出数组中的全部元素。

/**
 * 4.有一个整型数组a,有10个元素,要求输出数组中的全部元素。
 * - 下标法
 * - 通过数组名计算数组元素地址,找出元素的值
 * - 用指针变量指向数组元素
 * */
// 下标法
int a[10];
int i;
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
    scanf("%d", &a[i]);
for(i = 0; i < 10; i++)
    printf("%d,", a[i]); // 数组元素用数组名和下标表示
printf("\n");
// 通过数组名计算数组元素地址,找出元素的值
int a[10];
int i;
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
    scanf("%d", &a[i]);
for(i = 0; i < 10; i++)
    printf("%d,", *(a+i)); // 通过数组名和元素序号计算元素地址,再找到该元素
printf("\n");
// 用指针变量指向数组元素
int a[10];
int *p, i;
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
    scanf("%d", &a[i]);
for(p = a; p < a + 10; p++)
    printf("%d,", *p); // 用指针指向当前的数组元素
printf("\n");

image.png

注意:

  • 可以通过改变指针变量的值指向不同的元素

    如果不用p变化的方法而用数组名a变化的方法行不行呢?

    for(p = a; p < a + 10; a++)
      printf("%d,", *p);
    

    是不行的。因为数组名a代表数组首元素的地址,它是一个指针型常量,它的值在程序运行期间是固定不变的。既然a是常量,所以a++是无法实现的

  • 要注意指针变量的当前值

/**
 * 5.通过指针变量输出整型数组a的10个元素
 * 用指针变量p指向数组元素,通过改变指针变量的值,使p先后指向a[0]~a[9]各元素
 * */
int a[10], *p, i;
p = a; // p指向a[0]
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
    scanf("%d", p++); // 输入10个整数给a[0]~a[9]
// 第一个循环结束之后p的指向已经改变了,指向a数组的末尾,下面循环p的起始值不是a[0], 而是a + 10
// ——> 所以第二个循环前需要在赋值一下 p = a;
p = a; // 重新使p指向a[0]
for(i = 0; i < 10; i++, p++)
    printf("%d,", *p); // 想输出a[0]~a[9]
printf("\n");

利用指针引用数组元素,比较方便灵活,有不少技巧。可能会遇到容易使人混淆的情况,分析下面几种情况(设p开始时指向数组a的首元素 即 p = a)

  • ①分析:
p++;
*p;
// p++使p指向下一元素a[1]。若在指向*p,则得到下一个元素a[1]的值
  • *p++; 由于++和*同优先级,结合方向自右向左,因此它等价于 *(p++)。先引用p的值,实现*p的运算,然后在使p自增1,如
for (i = 0; i < 10; i++, p++)
    scanf("%d", *p);
// 等价于
for (i = 0; i < 10; i++)
    scanf("%d", *p++);
// 两者都是先输出*p的值,然后使p值加1.下一次循环时,*p就是下一个元素的值
  • *(p++)与*(++p)作用是否相同?

    不相同。前者是先取*p的值,然后使p加1。后者是先使p加1,再取*p。若p初值为a(即&a[0]), 若输出*(p++),得到a[0]的值,而输出*(++p), 得到a[1]的值。

  • ++(*p)。表示p所指向的元素值加1,如果p=a,则++(*p)相当于++a[0],若a[0]=3, 则执行++(*p)之后a[0]的值为4。注意:是元素a[0]的值加1,而不是指针p的值加1。


  • 指针是什么
  • 指针变量
  • 通过指针引用数组
  • 通过指针引用字符串
  • 指向函数的指针
  • 返回指针值的函数
  • 指针数组和多重指针
  • 动态内存分配与指向它的指针变量
  • 有关指针的小结