C语言指针重点难点整理(详解)(包括一维数组,二维数组的元素指针,二维数组的行指针做函数参数,指针数组,行指针数组)

C语言指针重点难点整理(详解)(包括一维数组,二维数组的元素指针,二维数组的行指针做函数参数,指针数组,行指针数组)

笔者学指针之前: 呵呵,听闻指针是C语言的难点,我倒要见识一下,到底有多难

在这里插入图片描述

笔者学完指针之后: 我还是收拾行囊,离开吧!

在这里插入图片描述

但是,在我的内心经过反复的挣扎,终于我决定,我要战胜它,现在,笔者已经大概弄清楚了指针的知识点,今天周末,刚好整理一下指针的一些难以理解的地方,和一些重点的地方(常言道:难以理解的地方往往是重点的地方),下年我分几个部分梳理一下,供各位大佬茶余饭后打发时间,如有不妥之处,还望指出。

一.一维数组的指针做函数参数

来,给皇上把代码呈上来:

void Test_1(int *x,int lenx)
{
 for (int i = 0; i < lenx; i++)
 {
  printf("%-3d ", x[i]);
 }
}


int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 printf("用一维数组的指针作为函数参数来引用数组元素:\n");
 Test_1(a, 10);
 printf("\n");
 return 0;
}
/*
用一维数组的指针作为函数参数来引用数组元素:
1   2   3   4   5   6   7   8   9   10
*/

(1)实参

首先要把一维数组名作为函数的实参,像这样Test_1(a, 10);

(2)形参

函数的形参依据一位数组的类型,一维数组维type型,形参为type *型,像这里的int *x

***这里函数的形参有多种形式,还可以是void Test_1(int x[],int lenx),void Test_1(int x[10],int lenx)

这里虽然写成一维数组的形式,但是其本质上还是一个type *型的指针

(3)数组元素的引用

***注意,可以在函数中直接用x[i]来引用数组元素,但是要想遍历,就必须知道数组长度,这里可以将数组长度一并传递

还可以用*(a+i)来引用一维数组的第i个元素

(4)函数的声明

函数的声明为void Test_1(int *x,int lenx);或者是void Test_1(int x[],int lenx);

二.二维数组的行指针做函数参数(逐行传递行指针)

老规矩,先上DJ,先上DJ:

void Test_2_1(int (*x)[N])
{
 for (int i = 0; i < N; i++)
  printf("%-3d ", (*x)[i]);
 printf("\n");
 }
 
 int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 },
  { 21, 22, 23, 24, 25 } };
 printf("二维数组的行指针作为函数参数(逐行传递行指针):\n");
 for (int i = 0; i < 5; i++)
  Test_2_1(b + i);
  return 0;
}
/*
二维数组的行指针作为函数参数(逐行传递行指针):
1   2   3   4   5
6   7   8   9   10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25
*/

解释一下趴!

在这里插入图片描述

(1)形参

函数的形参,数组为type型,则形参为type (x)[N],这表示该函数的形参为一个type型的行指针,

该行指针指向有N个type型元素的二维数组的一行,N是行指针指向的哪一行的type型元素的个数,

–这里是二维数组的每一行的长度。***形参变量还可以写成与type (*x)[N]等价的形式,type x[][N],type x[5][N]

这两种形式本质上还是行指针

(2)实参

这里实参是这样写的,别的也大同小异b+i,这表示第i行的行指针(下标从0开始算)

(3)数组元素的引用

①用(*x)[i]来访问这一行第i个元素,(*x)[N]是行指针,指向一行,(*x)相当于一个一维数组名,

(*x)[i]访问这一行第i个元素

②*(*x+i)来访问这一行第i个元素,这个表示应该这么理解,(*x)[N]是行指针,可以看作是一个一维数组,

(*x)相当于一维数组名,是这个数组第一个元素的指针,也就是这一行第一个元素的指针,*x+i自然就是这一行第i个元素的指针

*(*x+i)自然就访问了这一行的第i个元素

(4)函数的声明

void Test_2_1(int (*x)[N]);或者是void Test_2_1(int x[][N]);或者是void Test_2_1(int x[5][N]);

三.二维数组的行指针做函数参数(只传递第0行的指针)

还是来看代码:

void Test_2_2(int(*x)[N])
{
  for (int i = 0; i < 5; i++)
 {
  for (int j = 0; j < N; j++)
  {
   printf("%-3d ", x[i][j]);
  }
  printf("\n");
 }


int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 },
  { 21, 22, 23, 24, 25 } };
  printf("二维数组的行指针作为函数参数(传递第0行的行指针,也就是传递二维数组名):\n");
 Test_2_2(b);
 return 0;
}
/*
二维数组的行
/*
二维数组的行指针作为函数参数(传递第0行的行指针,也就是传递二维数组名):
1   2   3   4   5
6   7   8   9   10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25
*/

(1)形参

只传递第0行的指针,这里的形参的规则跟依次传递每一行的指针规则相同

(2)实参

这里的实参,很显然,是第0行的行指针,这里是b,也就是二维数组名

(3)数组元素的引用

***这里的数组元素引用十分便捷,直接用b[i][j]引用,因为这里系统知道了每行有N个元素

(4)函数的声明

void Test_2_2(int (*x)[N]);或者是void Test_2_2(int x[][N]);或者是void Test_2_2(int x[5][N]);

四.二维数组的元素指针做函数参数

老规矩:

void Test_3(int *p)
{
 for (int i = 0; i < 25; i++)
 {
  printf("%-3d ", p[i]);
  if ((i + 1) % 5 == 0 && i != 0)
   printf("\n");
 }
}

int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 }, 
 { 21, 22, 23, 24, 25 } };
 printf("二维数组的元素指针作为函数参数:\n");
 Test_3(&b[0][0]);
 return 0;
}
/*
二维数组的元素指针作为函数参数:
1   2   3   4   5
6   7   8   9   10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25
*/

(1)形参

形参就是一个type *型的指针就可,和一维数组相同

(2)实参

实参在这里其实有三种形式,Test_3(&b[0][0]);这种形式是用二维数组的元素指针作为函数参数

但是在这里用Test_3(b);,Test_3(b[0]);均可,需要指出的是,这里的两种情况,并不是二维数组的元素指针

作为函数参数,严格的来说,b这是第一行的行指针,b[0]是b[0][0]的指针,本质来说还是指针,是可以传递给p的

但是这里的b是行指针,传递给一个Int型的指针,虽然结果没错,但是充满着不专业

但是因为数组元素是连续储存的,所以说这两种方法都能够访问到数组元素

(3)数组元素的引用

*(p + i),p[i]两种方法均能够对数组元素进行引用

(4)函数的声明

直接就是跟一维数组类似void Test_3(int *p);

五.指针数组

我叫你一声代码,你敢答应吗?
在这里插入图片描述

int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 }, 
 { 21, 22, 23, 24, 25 } };
 printf("指针数组:\n");
 int *p[5] = { b[0], b[1], b[2], b[3], b[4] };
 for (int i = 0; i < 5; i++)
  printf("%d  %-3d\n", p[i], *p[i]);
  return 0;
}
/*
指针数组:
12187356  1
12187376  6
12187396  11
12187416  16
12187436  21
*/

(1)声明

type *p[N];例如int *p[5];表示声明一个有五个指针的指针数组

注意,这里指针数组的声明和行指针要区分开来,行指针声明是int (p)[5];[]的优先级比

一个指向五个int型元素的行指针

(2)赋值

给指针数组赋值。每一个元素都要是指针

六.行指针数组

在这里插入图片描述

int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 },
  { 21, 22, 23, 24, 25 } };
  printf("行指针数组:\n");
 int(*p1[5])[5] = { b, b + 1, b + 2, b + 3, b + 4 };
 for (int i = 0; i < 5; i++)
 {
  printf("%d   ", p[i]);
  for (int j = 0; j < 5;j++)
   printf("%-3d ", p[i][j]);
  printf("\n");
 }
 return 0;
}
/*
行指针数组:
12187356   1   2   3   4   5
12187376   6   7   8   9   10
12187396   11  12  13  14  15
12187416   16  17  18  19  20
12187436   21  22  23  24  25
*/

(1)声明

type (*p[M])[N];这里声明了一个数组名为p,共有M个元素,

每个元素都是指向一行有N个int型元素的一维数组,注意M,N的含义不要弄反了

即p[0],p[1],p[2],p[3],p[4]均是行指针,均指向一行,p[i]指向第i行,*p[i]指向第i行的第一个元素
*p[i]+j指向b[i][j]

(2)赋值

给行指针数组赋值。每一个元素都要是行指针

(3)引用

行指针可以带下标使用,p[i][j]代表b[i][j],和*(*p[i]+j)等价

好啦,六个我觉得是重难点的分享完了,下面把这六个部分合在一起来的代码放在下面:
#define _CRT_SECURE_NO_WARNINGS 1
#define N 5
#include<stdio.h>

void Test_1(int *x,int lenx)
{
 for (int i = 0; i < lenx; i++)
 {
  printf("%-3d ", x[i]);
 }
}

void Test_2_1(int (*x)[N])
{
 for (int i = 0; i < N; i++)
  printf("%-3d ", (*x)[i]);
 printf("\n");
}

void Test_2_2(int(*x)[N])
{
 for (int i = 0; i < 5; i++)
 {
  for (int j = 0; j < N; j++)
  {
   printf("%-3d ", x[i][j]);
  }
  printf("\n");
 }
}

void Test_3(int *p)
{
 for (int i = 0; i < 25; i++)
 {
  printf("%-3d ", p[i]);
  if ((i + 1) % 5 == 0 && i != 0)
   printf("\n");
 }
}

int main()
{
 int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int b[5][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, 
 { 11, 12, 13, 14, 15 }, { 16, 17, 18, 19, 20 }, 
 { 21, 22, 23, 24, 25 } };

printf("用一维数组的指针作为函数参数来引用数组元素:\n");
 Test_1(a, 10);
 printf("\n");

 printf("二维数组的行指针作为函数参数(逐行传递行指针):\n");
 for (int i = 0; i < 5; i++)
  Test_2_1(b + i);

 printf("二维数组的行指针作为函数参数(传递第0行的行指针,也就是传递二维数组名):\n");
 Test_2_2(b);

 printf("二维数组的元素指针作为函数参数:\n");
 Test_3(&b[0][0]);

 printf("指针数组:\n");
 int *p[5] = { b[0], b[1], b[2], b[3], b[4] };
 for (int i = 0; i < 5; i++)
  printf("%d  %-3d\n", p[i], *p[i]);

 printf("行指针数组:\n");
 int(*p1[5])[5] = { b, b + 1, b + 2, b + 3, b + 4 };
 for (int i = 0; i < 5; i++)
 {
  printf("%d   ", p[i]);
  for (int j = 0; j < 5;j++)
   printf("%-3d ", p[i][j]);
  printf("\n");
 }

return 0;
}
/*
1   2   3   4   5
6   7   8   9   10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25
指针数组:
12187356  1
12187376  6
12187396  11
12187416  16
12187436  21
行指针数组:
12187356   1   2   3   4   5
12187376   6   7   8   9   10
12187396   11  12  13  14  15
12187416   16  17  18  19  20
12187436   21  22  23  24  25
请按任意键继续. . .
*/

最后,特殊时期
在这里插入图片描述
原创不易,嘿嘿
在这里插入图片描述

发布了4 篇原创文章 · 获赞 85 · 访问量 3761

猜你喜欢

转载自blog.csdn.net/ztlzlzl/article/details/104597173