再议 C 语言中的指针与数组(4)

简介: 再议 C 语言中的指针与数组(4) 一 概述 前面的文章中,回顾了 C 语言中的指针,对指针有了一个比较初步的了解。在本文中,结合数组,再次对指针进行回顾。 二 数组与指针 在 C 语言中,指向数组的指针是比较常见的,也是非常方便和适用的。

再议 C 语言中的指针与数组(4)

一 概述

前面的文章中,回顾了 C 语言中的指针,对指针有了一个比较初步的了解。在本文中,结合数组,再次对指针进行回顾。

二 数组与指针

在 C 语言中,指向数组的指针是比较常见的,也是非常方便和适用的。

2.1 指向数组的指针

# include<stdio.h>

int main(int argc,char *argv[]){
  int a[10] = {1,2,3,4,6,5,7,8,9,0};
  int *p;
  // p = a;
  p = &a[0];
  for (int i = 0; i < 10; i++){
    printf("%d\t",*p);
    p++;
  }
  return 0;
}
// 1       2       3       4       6       5       7       8       9       0

本例中,指针变量 p 指向了数组 a[10],并演示了通过指针遍历数组的常规方法。 我们可以直接通过数组名直接将指针指向该数组的第一个元素,“p = a;” 和 “p = &a[10];”这两行代码在本质上是等价的。需要注意的是:通过这种方式使指针指向整个数组,数组名前面不能再使用运算符 &。 若指针指向数组的某一元素,运算符 & 不能省略。

2.2 指向复合常量的指针

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p = (int []){1,2,3,4,6,5,7,8,9,0};
  for (int i = 0; i < 10; i++){
    printf("%d\t",*p);
    p++;
  }
  return 0;
}
//1       2       3       4       6       5       7       8       9       0

本例声明并初始化了一个没有名称的数组。 通过这种方式,我们不需要先声明一个数组,然后再用指针指向数组的第一个元素。 在某些场景中,这个特性使用起来比较方便。 这是 C99 的一个特性。 另外, 在本例的 for 循环体,声明并初始化了 i, 这也是 C99 的一个特性,需要注意一下。

可以声明匿名数组的长度。

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p = (int [10]){1,2,3,4,6,5,7,8,9,0};
  for (int i = 0; i < 10; i++){
    printf("%d\t",*p);
    p++;
  }
  return 0;
}

2.3 通过指针对数组进行操作

通过指针也可以很方便、高效地对数组进行操作,请看以下例子:

# include<stdio.h>
# define N 10

int main(int argc,char *argv[]){
  int a[N];
  int *p;
  for (p = a; p < a + N; p++){
    printf("Please input a[%d]:",p - a);
    scanf("%d",p);
  }
    for (p = a; p < a + N; p++){
    printf("a[%d] = %d;\t ", p - a, *p);
  }
  printf("\n");
  return 0;
}
/*
Please input a[0]:1
Please input a[1]:2
Please input a[2]:3
Please input a[3]:4
Please input a[4]:5
Please input a[5]:66
Please input a[6]:7
Please input a[7]:7
Please input a[8]:8
Please input a[9]:9
a[0] = 1;        a[1] = 2;       a[2] = 3;       a[3] = 4;       a[4] = 5;       a[5] = 66;      a[6] = 7;       a[7] = 7;       a[8] = 8;       a[9] = 9;
*/

这个例子展示了通过操作指针对数组进行赋值,并通过指针的移动完成对数组的遍历。例子中使用了两个指针相减的方式确定了数组下标。使用指针操作对数组进行赋值或遍历的过程中,在操作开始之前需要将指针复位,指向数组的第一个元素。这个操作必不可少,否则将出错。

2.4 指针与数组在函数定义中的使用

在函数定义时,数组可以使用指针或显示声明来定义形式参数。

# include<stdio.h>

int main(int argc,char *argv[]){
  unsigned int array[] = {3,5,6,7,1,2,0}, len;
  int find_max(unsigned int [], int n);
  len = sizeof array / sizeof array[0];
  printf("%d\n",find_max(array,len));
  return 0;
}

int find_max(unsigned int a[], int n){
  int max = 0;
  for (int i = 0; i < n; i++){
    if ( a[i] > max)
       max = a[i];
  }
  return max;
}
// 7

# include<stdio.h>

int main(int argc,char *argv[]){
  unsigned int array[] = {3,5,6,7,1,2,0}, len;
  int find_max(unsigned int [], int n);
// int find_max(unsigned int *, int n);
  len = sizeof array / sizeof array[0];
  printf("%d\n",find_max(array,len));
  return 0;
}

int find_max(unsigned int *a, int n){
  int max = 0;
  for (int i = 0; i < n; i++){
    if ( a[i] > max)
       max = a[i];
  }
  return max;
}
// 7

在以上2段代码中,写法不一样,但执行效果却一致。事实上数组作为形参时,是以指针进行传递的。也就是说,对于形参而言,声明为数组与声明为指针是一样的,但是对于变量来说,声明为数组与声明为指针是不一样的。指定长度的数组会导致编译器预留指定数据类型长度的空间,申明为指针会导致编译器为指针变量分配空间。

2.5 多维数组与指针

使用指针遍历多维数组:

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p, array[2][3] = {{12,43,11},{10,56,89}};
  for (p = &array[0][0]; p <= &array[1][2]; p++)
    printf("array[%d][%d]: %d\n",(p - &array[0][0])/3, (p - &array[0][0])%3, *p);
  return 0;
}
/*
array[0][0]: 12
array[0][1]: 43
array[0][2]: 11
array[1][0]: 10
array[1][1]: 56
array[1][2]: 89
*/

以上代码等价于:

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p, array[2][3] = {{12,43,11},{10,56,89}};
  for (p = array[0]; p <= &array[1][2]; p++)
    printf("array[%d][%d]: %d\n",(p - &array[0][0])/3, (p - &array[0][0])%3, *p);
  return 0;
}

对比以上两端代码,乍一看,并没有什么差异!举着个例子的重点在第四行的 “p = &array0” 和 “p = array[0]”。通过这两行代码,不难看出:二维数组中,指针 p 不是指向 array0 的指针,而是指向 array[0] 的指针。

多维数组是不能以数组名直接作为指针指向的对象,需要稍微做一些调整才能使用数组名作为指针。在 C 语言中,多维数组实际上就是以一维数组来进行处理的。结合上面的例子,C 语言把 array 当作一维数组来进行处理,而这个一维数组的美一个元素又是一个一维数组。由此,可以推广到多维数组。

那么,在多维数组内是否可以直接以数组名为作为指针呢?请看以下例子:

# include<stdio.h>
# define ROWS 2
# define COLS 3

int main(int argc,char *argv[]){
  int *p, array[ROWS][COLS] = {{12,43,11},{10,56,89}};
    for (p = *array; p < *array + (ROWS * COLS); p++)
      printf("array[%d][%d]: %d\n",(p - *array) / COLS, (p - *array) % COLS, *p);
  return 0;
}
/*
array[0][0]: 12
array[0][1]: 43
array[0][2]: 11
array[1][0]: 10
array[1][1]: 56
array[1][2]: 89
*/

在这一代码片段中,将指针变量 p 指向一个指针类型的数组。也就是说,指针变量 p 指向了一个数组,这个数组的全部元素均为指针。简而言之,指针变量 p 是指向指针数组的指针。

三 总结

3.1 在 C 语言中,指针与数组关系密切,既有联系又有区别。在实际的使用过程中要特别谨慎。

3.2 指针是 C 语言中的精华。作为一名 C 语言学习者,指针虽然比较坑,但是这个是无法逃避的,必须花大量的时间与精力去学习与理解。

3.3 指针常常会与数组发生关联,对指针的理解必须透彻。

3.4 鉴于笔者水平,文中可能存在若干谬误,希望大家能帮忙指出,谢谢!

相关文章
|
25天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
31 3
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
51 0
|
12天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
38 4
|
24天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
32 2
|
5天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
34 1
|
2月前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
40 6
|
2月前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
20 2
|
2月前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
2月前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。