C语言指针操作(九)指针数组和多重指针

指针操作系列文章:

C语言指针操作(一)地址,指针,指针变量是什么

C语言指针操作(二)指针变量作为函数参数

C语言指针操作(三)通过指针引用数组

C语言指针操作(四)用数组名作函数参数

C语言指针操作(五)通过指针引用多维数组

C语言指针操作(六)通过指针引用字符串

C语言指针操作(七)指向函数的指针

C语言指针操作(八)返回指针值的函数

C语言指针操作(九)指针数组和多重指针

C语言指针操作(十)动态内存分配与指向它的指针变量

C语言指针操作(十一)有关指针的小结


指针数组和多重指针详解,以及如何用指向指针数据的指针变量。

目录

一、什么是指针数组

1.1引入

1.2指针数组的定义

3.举例说明

二、指向指针数据的指针变量

2.1引入

2.2举例说明

三、多重指针


一、什么是指针数组

1.1引入

一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。

下面定义一个指针数组:

int* p[4];

由于 [ ] 比 * 优先级高,因此 p 先与 [4] 结合,形成 p[4] 形式,这显然是数组形式,表示 p 数组有 4 个元素。然后再与 p 前面的 “ * ” 结合,“ * ” 表示此数组是指针类型的,每个数组元素(相当于一个指针变量)都可指向一个整型变量。

注意不要写成:

int(*p)[4];			//这是指向一维数组的指针变量

1.2指针数组的定义

定义一维指针数组的一般形式为:

类型名 * 数组名[数组长度];

类型名中应包括符号 “ * ”,如 “ int* ” 表示是指向整型数据的指针类型。

指针数组比较适合用来指向若干个字符串,使字符串处理更加方便灵活。例如,图书馆有若干本书,想把书名放在一个数组中,然后要对这些书目进行排序和查询。按一般方法,字符串本身就是一个字符数组。因此要设计一个二维的字符数组才能存放多个字符串。但在定义二维数组时,需要指定列数,也就是说二维数组中每一行中包含的元素个数(即列数)相等。而实际上各字符串(书名)长度一般是不相等的。如按最长的字符串来定义列数,则会浪费许多内存单元。

可以分别定义一些字符串,然后用指针数组中的元素分别指向各字符串,在 name[0] 中存放字符串 " Follow me " 的首字符的地址。name[1] 中存放字符串 " BASIC " 的首字符的地址……如果想对字符串排序,不必改动字符串的位置,只须改动指针数组中各元素的指向(即改变各元素的值,这些值是各字符串的首地址)。这样,各字符串的长度可以不同,而且移动指针变量的值(地址)要比移动字符串所花的时间少得多。

3.举例说明

举例:将若干字符串按字母顺序(由小到大)输出。

#include <stdio.h>
#include <string.h>
int main()
{
	void sort(char* name[], int n);			//函数声明
	void print(char* name[], int n);		//函数声明
	//定义指针数组,它的元素分别指向5个字符串
	char* name[] = { "Follow me" ,"BASIC" ,"Great Wall" ,"FORTRAN" ,"Computer design" };
	int n = 5;
	sort(name, n);							//调用sort函数,对字符串排序
	print(name, n);							//调用print函数,输出字符串
	return 0;
}

void sort(char* name[], int n)				//定义sort函数
{
	for (int i = 0; i < n - 1; i++)				//用选择法排序
	{
		int  k = i;
		for (int j = i + 1; j < n; j++)
			if (strcmp(name[k], name[j]) > 0)
				k = j;
		if (k != i)
		{
			char* temp;
			temp = name[i];
			name[i] = name[k];
			name[k] = temp;
		}
	}
}

void print(char* name[], int n)		//定义print函数
{

	for (int i = 0; i < n; i++)
	{
		printf("%s\n", name[i]);
	}
}

运行结果:

程序分析:

在 main 函数中定义指针数组 name,它有5个元素,其初值分别是 " Followme "," BASIC ","  Great Wal "," FORTRAN " 和 " Computer design " 这 5 个字符串的首字符的地址。这些字符串是不等长的。

sort 函数的作用是对字符串排序。sort 函数的形参 name 也是指针数组名,接受实参传过来的 name 数组首元素 ( 即 name[0] ) 的地址,因此形参 name 数组和实参 name 数组指的是同一数组。用选择法对字符串排序。strcmp 是系统提供的字符串比较函数,name[k] 和 name[j] 是第 k 个和第 j 个字符串首字符的地址。strcmp(name[k],name[j])的值为:如果 name[k] 所指的字符串大于 name[j] 所指的字符串,则此函数值为正值;若相等,则函数值为0;若小于,则函数值为负值。if 语句的作用是将两个串中 “小” 的那个串的序号( k 或 j 之一)保留在变量 k 中。当执行完内循环 for 语句后,从第 i 串到第 n 串这些字符串中,第 k 串最“小”。若 k != i 就表示最小的串不是第 i 串。故将 name[i] 和 name[k] 对换,也就是将指向第 i 个字符串的数组元素(是指针型元素)的值与指向第 k 个字符串的数组元素的值对换,也就是把它们的指向互换。

print 函数的作用是输出各字符串。name[0]-name[4]分别是各字符串(按从小到大顺序排好序的各字符串)的首字符的地址(按字符串从小到大顺序,name[0]指向最小的串),用 “ %s ” 格式符输出,就得到这些字符串。

二、指向指针数据的指针变量

2.1引入

在了解了指针数组的基础上,需要了解指向指针数据的指针变量,简称为指向指针的指针。name 是一个指针数组,它的每一个元素是一个指针型的变量,其值为地址。name 既然是一个数组,它的每一元素都应有相应的地址。数组名 name 代表该指针数组首元素的地址。name+i 是 name[i] 的地址。name+i 就是指向指针型数据的指针。还可以设置一个指针变量 p,它指向指针数组的元素。p 就是指向指针型数据的指针变量。

下面定义一个指向指针数据的指针变量:

char** p;

p 的前面有两个 * 号。* 运算符的结合性是从右到左,因此 **p 相当于 *(*p),显然 *p 是指针变量的定义形式。如果没有最前面的 *,那就是定义了一个指向字符数据的指针变量。现在它前面又有一个 * 号,即 char **p。可以把它分为两部分看,即:char* 和( *p ),后面的( *p )表示 p 是指针变量,前面的 char* 表示 p 指向的是 char* 型的数据。也就是说,p 指向一个字符指针变量(这个字符指针变量指向一个字符型数据)。如果引用 *p,就得到 p 所指向的字符指针变量的值,如果有:

name + 2;
printf("%d\n", *p);
printf("%s\n", *p);

第 1 个 printf 函数语句输出 name[2] 的值(它是一个地址),第 2 个 printf 函数语句以字符串形式(%s)输出字符串 " Great Wall ”。

2.2举例说明

举例1:使用指向指针数据的指针变量。

#include <stdio.h>
int main()
{
	char* name[] = { "Follow me" ,"BASIC" ,"Great Wall" ,"FORTRAN" ,"Computer design" };
	char** p;
	for (int i = 0; i < 5; i++)
	{
		p = name + i;
		printf("%s\n", *p);
	}
	return 0;
}

运行结果:

程序分析:

p 是指向 char* 型数据的指针变量,即指向指针的指针。在第 1 次执行 fo r循环体时,赋值语句 “ p=name+i; ” 使 p 指向 name 数组的 0 号元素 name[0],*p 是 name[0] 的值,即第 1 个字符串首字符的地址,用 printf 函数输出第 1 个字符串(格式符为 %s )。执行 5 次循环体,依次输出 5 个字符串。

指针数组的元素也可以不指向字符串,而是指向整型数据或实型数据等。

举例2:有一个指针数组,其元素分别指向一个整型数组的元素,用指向指针数据的指针变量,输出整型数组各元素的值。

#include <stdio.h>
int main()
{
	int a[5] = { 1,3,5,7,9 };
	int* num[5] = { &a[0],&a[1],&a[2],&a[3],&a[4] };
	int** p = num;			//p是指向指针型数据的指针变量,使p指向num[0]
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", **p);
		p++;
		printf("\n");
	}
	return 0;
}

运行结果:

程序分析:

程序中定义 p 是指向指针型数据的指针变量,开始时指向指针数组 num 的首元素 num[0],而num[0],是一个指针型的元素,它指向整型数组 a 的首元素 a[0]。开始时 p 的值是&num[0],*p 是 num[0] 的值,即 &a[0],*(*p) 是 a[0] 的值。因此第 1 个输出的是 a[0] 的值 1。然后执行 p++,p 就指向 num[1],再输出 **p,就是 a[2] 的值 3 了。

三、多重指针

在本章开头已经提到了 “ 间接访问 ” 变量的方式。利用指针变量访问另一个变量就是 “ 间接访问 ” 。如果在一个指针变量中存放一个目标变量的地址,这就是 “ 单级间址 ”,指向指针数据的指针用的是 “ 二级间址 ” 方法。从理论上说,间址方法可以延伸到更多的级,即多重指针。

但实际上在程序中很少有超过二级间址的。级数愈多,愈难理解,容易产生混乱,出错机会也多。

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

juechen333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值