指针进阶II · 指针数组和数组指针

简介: 指针数组和数组指针

  大家好,我是安然无虞。  

文章目录






一、指针数组

指针数组,顾名思义就是存放指针的数组

看看下面这些类型的数组

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

下面给出一道指针数组的小例题:

#include<stdio.h>
int main()
{
  char* arr[] = { "abcdef", "qwer", "zhangsan" };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%s\n", arr[i]);
  }
  return 0;
}

很简单,这里就不过多阐述了。

补充易错点

&数组名和数组名:


之前有提到过这部分概念,所以在这里就不过多赘述了,直接给出下面结论:&数组名表示取出整个数组的地址;数组名表示数组首元素的地址。,因为 &数组名+1 跳过整个数组,数组名+1 却仅仅跳过一个首元素(这里细细体会一下)。


二、数组指针

问:数组指针是数组还是指针?

答案:数组指针是指针,是能够指向数组的指针。

试分析以下代码:

int* p1[10];//p1是存放10个整型指针的数组
int(*p2)[10];//p2先和'*'结合,说明p2是一个指针,指向的是一个数组,数组有10个元素,每个元素类型是int,所以p2是一个数组指针


这里的话我就直接把答案给出来了,不过需要注意的是:[ ] 的优先级要高于 * 的,所以在写数组指针的时候必须加上 () 来保证 p2 先和 * 结合。


为了强化理解上述概念,做了如下补充:

char arr[5];
char(*pa)[5] = &arr;//pa先和*结合,说明pa是一个指针,看到'[]'说明指向一个数组,数组有5个元素,每个元素类型是char,所以pa的类型就是char(*)[5]
int* parr[6];
int*(*pa)[6] = &parr;//pa类型是int*(*)[6]

到这里还是得探讨一下,数组名arr 和&数组名&arr 的本质是什么?

int arr[10];
//arr类型是int*(整型指针)
//&arr类型是int(*)[10](数组指针)

既然数组指针指的是数组,那么数组指针中存放的就是数组的地址。

问:数组指针是怎么使用的呢?

请看下列代码:

#include<stdio.h>
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");
  }
}
//*(arr+i)相当于二维数组第i行的数组名(可以这么去理解:*和&相抵消)
//数组名相当于数组首元素的地址,其实也就是第i行第一个元素的地址
//*(*(arr + i) + j)
//(arr + i) 相当于 第i行数组的地址
//*(arr + i) 相当于 第i行数组名,也就是第i行首元素的地址
//(*(arr + i) + j) 相当于 第i行第j列元素的地址
//*(*(arr + i) + j) 相当于 第i行第j列的元素
int main()
{
  int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
  print_arr1(arr, 3, 5);
  print_arr2(arr, 3, 5);
  //数组名arr表示首元素的地址
  //但是二维数组的首元素跟一维数组不同,二维数组的首元素是第一行
  //所以这里传递的arr,其实相当于第一行的地址,属于一维数组的地址
  //所以可以用数组指针接收
  return 0;
}

学完数组指针和指针数组,分析下列代码:

int arr[5];//arr是一个数组,数组有5个元素,每个元素是int类型
int* parr1[10];//parr1是一个数组,数组有10个元素,每个元素类型是int*
int(*parr2)[10];//parr2是一个指针,指向一个含有10个元素,元素类型是int的数组,所以parr2是一个数组指针
int(*parr3[10])[5];
//parr3先和[]结合,说明parr3是一个数组,数组有10个元素,每个元素的类型是int(*)[5]的指针,该指针指向一个含有10个整型元素的数组
//所以parr3是一个数组指针数组

好,说到这里再啰嗦一下,对数组指针做一个总结:

int arr[10];
int* p = arr;
int(*p2)[10] = &arr;//取出的是整个数组的地址,既然是数组的地址
//就应该放到数组指针里面去,所以p2就是一个数组指针
//对p,p2进行分析:
//p中存放的是首元素的地址
//p+1跳过一个int
//*p访问一个int数据-4个字节,*p等价于首元素
//p2存放的是arr数组的地址
//p2+1跳过整个数组
//*p2访问的是arr数组,*p等价于arr(可以理解为&和*抵消了)
//那么*p2就是数组名了,所以*p2本质就是arr数组首元素的地址
//p <=> *p2 <=> arr
//p+1 <=> *p2 + 1


补充易错点

我们在写代码的时候难免要把【数组】或者【指针】传递给函数,那么函数的参数应该怎么设计呢?

一维数组传参

#include<stdio.h>
void test(int arr[]);//ok - 数组传参时,形参部分不会真的创建一个数组,写成数组是为了方便我们理解,写成指针才是本质
void test(int arr[10]);//ok
void test(int* arr);//ok
void test2(int* arr[20]);//ok
void test2(int** arr);//ok
int main()
{
  int arr[10] = { 0 };
  int* arr2[20] = { 0 };
  test(arr);//数组名相当于首元素的地址
  test2(arr2);
  return 0;
}

一维数组传参比较简单,在这里的话就不过多赘述了,下面看看二维数组传参

二维数组传参

#include<stdio.h>
void test(int arr[3][5]);//ok
void test(int arr[][]);//这种写法是错误的,因为二维数组传参行可以省略,但是列不能省略
//因为列表示一行有几个元素,如果不知道一行有几个元素,那么这一行访问完了,不知道下一行在哪(细品)
void test(int arr[][5]);//ok
void test(int* arr);//这种写法是错误的,形参部分应该用数组指针接收
void test(int* arr[5]);//这种写法是错误的,误写成指针数组了
void test(int(*arr)[5]);//ok
void test(int** arr);//错错错
int main()
{
  int arr[3][5] = { 0 };
  test(arr);//数组名表示首元素的地址,二维数组的首元素是第一行,所以二维数组的数组名表示的是第一行的地址
  //故而形参部分需要用数组指针接收
  return 0;
}

一级指针传参

#include<stdio.h>
//一般实参是一级指针的时候,形参写成一级指针即可,不需要写成数组的形式
void print(int* arr, int n)
{
  int i = 0;
  for (i = 0; i < n; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9 };
  int* p = arr;
  int sz = sizeof(arr) / sizeof(arr[0]);
  //一级指针p,传给函数
  print(p, sz);
  return 0;
}

思考题:

当一个函数的形参是一级指针的时候,函数能接受什么参数?

比如下面的test函数:

void test2(char** p);

问:test函数能接收什么参数?

大家一定要想清楚,如果给你这么一个函数,我们可以把什么样的参数给它传过去,因为这点很重要!

请看:

int a = 10;
int* ptr = &a;
int arr[10] = {0};
test(&a);
test(ptr);
test(arr);

二级指针传参

#include<stdio.h>
void test(int** ptr)
{
  printf("num = %d\n", **ptr);
}
int main()
{
  int n = 10;
  int* p = &n;
  int** pp = &p;
  test(&p);
  test(pp);
  return 0;
}

思考题:

当一个函数的形参是二级指针的时候,函数能接受什么参数?

比如下面的test2函数:

void test2(char** p);

请看:

char ch = 'w';
char* pc = &ch;
char** ppc = &pc;
char* arr[10] = {0};
test(&pc);
test(ppc);
test(arr);


三、遇见安然遇见你,不负代码不负卿。


相关文章
|
17天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
30 3
|
16天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
28 2
|
24天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
29 1
|
1月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
1月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
19 1
|
1月前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
18 0
|
1月前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
3月前
|
搜索推荐 C语言
指针与数组
指针与数组
59 9