指针与数组的 “ 爱恨情仇 ”——指针进阶(一)

简介: 指针与数组的 “ 爱恨情仇 ”——指针进阶(一)

系列文章目录

指针进阶

指针与数组的 “ 爱恨情仇 ”——指针进阶(一)

前言

“指针”和“数组”这两个词,大家或许都已耳熟能详,数组又常被人称为是一种指针,前边我们也基本了解了数组与指针的关系,那么指针数组与数组指针又有是什么呢?它们又有着怎样“ 爱恨情仇 ”呢?接下来我们将会一一探讨。


数组与指针

在前边我们学习了初阶指针相关知识,主要为以下内容:

1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。

2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。

3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

4. 指针的运算。

那么接下来我们将对指针进行深度解析。

数组与指针的区别

以字符指针为例:

字符指针的一般类型为:char*,常用的使用有以下两种:

1.通过指针修改变量的值

int main()
{
  char ch = 'w';
  char *pc = &ch;
  *pc = 'w';
  return 0;
}

2.通过指针找到字符串

int main()
{
  char* pstr = "hello world.";
  printf("%s\n", pstr);
  return 0;
}

这里可能会有很多人会误以为是将字符串存储到了指针pstr中,然而它的实质含义是将字符串首元素地址存放到指针pstr中,通过字符串首元素的地址,进而找到整个字符串。

我们来看一下以下代码,区别一下数组与指针。

#include <stdio.h>
int main()
{
  char str1[] = "hello world.";
  char str2[] = "hello world.";
  char *str3 = "hello world.";
  char *str4 = "hello world.";
  if(str1 ==str2)
printf("str1 and str2 are same\n");
  else
printf("str1 and str2 are not same\n");
  if(str3 ==str4)
printf("str3 and str4 are same\n");
  else
printf("str3 and str4 are not same\n");
  return 0;
}

答案是什么呢?str1和str2不同,str3和str4相同。为什么呢?

str3和str4指向的是同一个常量字符串,C/C++会把常量字符串存储到单独的一个内存区域(代码区),不同的指针指向同一个字符串的时候,他们实际会指向同一块内存。

而用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。str1和str2是数组首元素的地址,所以所以str1和str2不同,str3和str4相同。

指针数组

什么是指针数组?

我们来类比一下,存放整形数据的数组被称为整形数组,存放字符串的数组被称为字符数组,那指针数组呢?

指针数组是一个存放指针的数组

基本类型:

int* arr1[10]; //整形指针的数组
char *arr2[10]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

前边的类型表示所存储指针指向的类型。

例如:

int main()
{
  int arr1[] = { 1,2,3,4,5 };
  int arr2[] = { 2,4,6,8,0 };
  int arr3[] = { 1,3,5,7,9 };
  int* parr[] = { arr1,arr2,arr3 };
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 5; j++)
    {
      printf("%d ", *(parr[i] + j));
    }
    printf("\n");
  }
  return 0;
}

arr1,arr2,arr3指的都是数组首元素地址,指针数组存放的就是地址,通过观察我们也可以发现,在打印元素时访问数组元素很像二维数组,而 *(parr[i] + j)不仅可以写成parr[i][j]二维数组的形式,还可以写成*( *(parr+i) + j)由此我们可以看出,*(parr+i)等价于parr[i],从这里也可以看出数组与指针有很大的相似之处,但它们确是两个不同的概念。

数组指针

前边我们知道指针数组的本质是数组,那数组指针的本质是什么呢?

数组指针本质上是指针,是指向数组的指针。

我们来看一下下面的代码:

int *p1[10];
int (*p2)[10];

哪个是数组指针,哪个又是指针数组?

它们有很多的相似之处,不同点就在于p2使用括号,使得p2优先与*结合。

int (*p)[10];

解释:p先和*结合,说明p是一个指针变量,[10]代表指向的是一个大小为10的数组,数组类型为int类型。

所以p2是一个指针,指向一个数组,叫数组指针。

这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合.

思考:

那指向一个整形指针数组(一维)的指针应该怎么写呢?

int* (*p)[10];

(*p)左边的类型就是指针p所指向的数组类型。

指针数组的使用

我们已经了解了数组指针基本概念,那要怎么使用呢?

例如以下代码:

#include <stdio.h>
int main()
{
  int arr[10] = {1,2,3,4,5,6,7,8,9,0};
  int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
  return 0;
}

数组指针存放的应该是数组的地址,但是我们很少这样去写代码。

数组指针一般很少与一维数组结合使用,因为基本没有意义,大多数的情况都是和二维及二维以上的数组搭配使用。

那我们要怎么用呢?

以下列代码为例:

我们来对比以下。

void print_arr1(int arr[3][5], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
}
void print_arr2(int(*arr)[5], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
}
int main()
{
  int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
  print_arr1(arr, 3, 5);
  print_arr2(arr, 3, 5);
  return 0;
}

两种方法很相似,但是前边我们知道,数组在传参时传的是数组首元素地址,那二维数组是怎么传参的呢?传过去的又是什么呢?

我们可以这样理解,arr[3][5]是一个存放一维数组的数组,一个二维数组里存放了3个一维数组,每个一维数组大小是5。

那么数组名arr,又表示首元素的地址

二维数组的首元素就是是二维数组的第一行(可以理解为第一个数组)

所以这里传递的arr,其实相当于第一行的地址(也就是一维数组的地址)

既然是地址那我们就可以用,数组指针来接收。

我们介绍了这么多,我来帮大家回忆和巩固以下:

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

第一个是数组,一个存放整形的数组。

第二个是一个指针数组,一个存放指针的数组,int* 是它所存放的数据类型。

第三个是一个数组指针,一个指向数组的指针,int   [10],是数组的类型,*与parr2结合说明parr2是一个指针。

那第四个又是什么呢?

结合本文所介绍的内容来想一想。

先不看[10]int (*parr3)[5]是一个数组指针类型,那加上[10]又说明parr3是一个数组,所以,它是一个存放数组指针的数组


总结

通过本文的介绍,相信大家已经对指针和数组有了更深入的了解。希望这篇博客能够对你的学习和工作有所帮助。

相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
38 3
|
29天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
1月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
1月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
1月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
50 2
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
39 1
|
2月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
2月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。