C语言复习(五)——多级指针与多维数组

上一篇博客总结了一级指针与字符串,这篇博客主要总结多级指针与多维数组的重点与难点。

二级指针

二级指针的基础在这里就不再赘述了,二级指针,顾名思义,它就是一个指向指针的指针,它的指向是一个指针。主要简单的总结一下二级指针的用法。
指针的输入输出特性前面简单的介绍过,当指针所指向的内存空间是在主调函数中分配好的,那么指针就做输入,当指针所指向的内存空间是在被调函数中分配好德,那么指针就做输出。接下来几个简单的例子。

一级指针的输入输出特性

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void f(char *a, int number)
{
	int i, j;
	int *p = a;
	for (i = 0; i < number - 1; i++)
	{
		for (j = 0; j < number - i - 1; j++)
		{
			if (*(p + j) > *(p + j + 1))
			{
				int temp = *(p + j);
				*(p + j ) = *(p + j + 1 );
				*(p + j + 1) = temp;
			}
		}
	}
}


//一级指针做输入
int main0(void)
{
	int a[] = { 22,44,12,3,1,4,15,11,8,88 };//典型例子,这里的内存空间可以是在栈区,可以是在堆区,也可以实在全局区;
	int number;
	number = sizeof(a)/sizeof(int);
	f(a, number);
	for (int i = 0; i < number; i++)
	{
		printf("%d ", a[i]);
	}
	system("pause");
	return 0;
}

//一级指针做输出
void f1(char *p,int *len)
{
	int length = strlen(p);
	*len = length;//这里是间接的修改了len的值。
}
int main(void)
{
	char *p = "abcdef";
	int len = 0;
	f1(p,&len);
	printf("%d",len);
	system("pause");
	return 0;
}

上面是一级指针做输入输出的简单例子,代码很简单,接下来我们看二级指针的。

二级指针

首先看一下二级指针做输出


//二级指针做输出
void getM(char **p, int *len)
{
	char *s;
	s = (char *)malloc(100);
	strcpy_s(s,100, "abcdef");
	*p = s;
	*len = strlen(*p);
}

void free_p(char *p)
{
	if (p == NULL)
	{
		return;
	}
	else
	{
		free(p);
		p = NULL;
	}
}
int main(void)
{
	char *p = NULL;
	int leng;
	getM(&p, &leng);
	printf("%s\n", p);
	printf("%d\n", leng);
	free_p(p);
	system("pause");
	return 0;

举的这个例子是在被调用函数中返回堆上的内存空间,常量区是一样的道理,不过很简单,在实际编程中常用的就是堆上的内存空间,例如为结构体申请内存空间。
接下来总结一下二级指针做输入的情况。
二级指针与二维数组有关,这里是一块重点,也是一个难点。

1、指针数组

指针数组,顾名思义,它是一个数组,只不过数组中的每一个元素都是一个指针。

void print_a(char **a, int num)
{
	int i;
	for (i = 0; i < num; i++)
	{
		printf("%s\n", a[i]);
		//printf("%s\n", *(a + i));
	}
}

void sort_a(char **a, int num)
{
	int i, j;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (strcmp(a[j], a[j + 1]) > 0)
			{
				char *temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp; //注意,这里交换的是数组元素:指针;
			}
		}
	}
}


int main(void)
{
	char *a[] = { "aaaaa","bbbb","dddddddd","ee","111111111" };
	int len;
	len = sizeof(a) / sizeof(a[0]);
	printf("排序前:\n");
	print_a(a, len);
	sort_a(a, len);
	printf("排序后:\n");
	print_a(a, len);
	system("pause");
	return 0;
}

上面是一个例子,对一个指针数组排序并且打印。
要记住一点,指针数组里面的每一个元素都是指针。

2、二维数组

首先看一段代码

int main(void)
{
	char a[10][30] = { "aaaaa","bbbb","dddddddd","ee","111111111" };
	char temp[30];
	int num = 5;
	printf("排序前:\n");
	int i,j;
	for (i = 0; i < num; i++)
	{
		printf("%s\n", a[i]);
		//printf("%s\n", *(a + i));
	}
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (strcmp(a[j], a[j + 1]) > 0)
			{
				strcpy_s(temp, 30, a[j]);
				strcpy_s(a[j], 30, a[j + 1]);
				strcpy_s(a[j + 1], 30, temp);//注意,这里交换的是内存空间里的值
			}
		}
	}
	printf("排序后:\n");
	for (i = 0; i < num; i++)
	{
		printf("%s\n", a[i]);
		//printf("%s\n", *(a + i));
	}
	system("pause");
	return 0;
}

当我们想要把打印函数向指针数组那样封装时,我们编译程序,不会出现问题,当我们执行程序的时候,是会抛出异常的。
在这里插入图片描述
问题的本质是:指针的步长不一样,也就是说,指针所指向的内存空间类型不一样。
我们看一下下面这段代码

void print_a2(char a[10][30], int num)
{
	int i;
	for (i = 0; i < num; i++)
	{
		printf("%s\n", a[i]);
		//printf("%s\n", *(a + i));
	}
}

void sort_a2(char a[10][30], int num)
{
	int i, j;
	char temp[30];
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (strcmp(a[j], a[j + 1]) > 0)
			{
				strcpy_s(temp, 30, a[j]);
				strcpy_s(a[j], 30, a[j + 1]);
				strcpy_s(a[j + 1], 30, temp);
			}
		}
	}
}
int main(void)
{
	char a[10][30] = { "aaaaa","bbbb","dddddddd","ee","111111111" };
	int num = 5;
	printf("排序前:\n");
	print_a2(a, num);
	sort_a2(a, num);
	printf("排序后:\n");
	print_a2(a, num);
	system("pause");
	return 0;
}

这段代码可以正常运行,主要是把函数的形参改变了,里面存在一个多级指针的退化问题。

3

接下来要自己写一段程序,要实现如下功能:
1、定义一个二级指针
2、这个指针要指向一个指针数组
3、这个数组里面存储的每一个元素都是一个指针。
4、每一个指针都要指向一个字符串。
5、对这个数组进行排序。
代码如下;

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	char **p = NULL;
	int number = 5;
	p = (char **)malloc(sizeof(char *)*number);
	int i,j;
	char *temp;
	for (i = 0; i < number; i++)
	{
		p[i] = (char *)malloc(sizeof(char)*100);
		sprintf_s(p[i], 100, "%d%d%d", i + 1, i + 1, i + 1);
	}

	//排序之前:
	for (i = 0; i < number; i++)
	{
		printf("%s\n", p[i]);
	}
	//交换指针排序
	for (i = 0; i < number - 1; i++)
	{
		for (j = 0; j < number - i - 1; j++)
		{
			if (strcmp(p[j], p[j + 1]) < 0)
			{
				temp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = temp;
			}
		}
	}
	// 交换内存空间里的值排序
	for (i = 0; i < number - 1; i++)
	{
		for (j = 0; j < number - i - 1; j++)
		{
			if (strcmp(p[j], p[j + 1]) < 0)
			{
				strcpy_s(tmp, 100, p[j]);
				strcpy_s(p[j], 100, p[j + 1]);
				strcpy_s(p[j+1], 100, tmp);
			}
		}
	}
	//排序之后:
	printf("\n");
	for (i = 0; i < number; i++)
	{
		printf("%s\n", p[i]);
	}
	system("pause");
	//释放内存
	for(i=0; i<num; i++)
	{
		if (p[i] != NULL)
		{
			free(p[i]);
			p[i] = NULL;
		}
	}

	if (p!=NULL) 
	{
		free(p);
	}
	return 0;
}

接下来对函数进行封装。

char **getM(int num)
{
	char **p = NULL;
	p = (char **)malloc(sizeof(char *)*num);
	int i;
	for (i = 0; i < num; i++)
	{
		p[i] = (char *)malloc(sizeof(char) * 100);
		sprintf_s(p[i], 100, "%d%d%d", i + 1, i + 1, i + 1);
	}
	return p;
}

void print_M(char **p, int num)
{
	for (int i = 0; i < num; i++)
	{
		printf("%s\n", p[i]);
	}
}

void sort_M(char **p, int num)
{
	int i, j;
	char *temp;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - i - 1; j++)
		{
			if (strcmp(p[j], p[j + 1]) < 0)
			{
				temp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = temp;
			}
		}
	}
}
void free_M(char **p,int num)
{
	if (p == NULL)
	{
		return;
	}
	for (int i = 0; i < num; i++)
	{
		if (p[i] != NULL)
		{
			free(p[i]);
			p[i] = NULL;
		}
	}

	if (p != NULL)
	{
		free(p);
	}

}
int main(void)
{
	char **p = NULL;
	int num = 5;
	p = getM(num);
	printf("排序前:\n");
	print_M(p,num);
	sort_M(p, num);
	printf("排序后:\n");
	print_M(p, num);
	//释放内存
	free_M(p,num);
	system("pause");
	return 0;
}

释放内存的时候注意一下先后顺序。
下面是我画的一个简单的内存模型示意图,图画的丑,字也写的丑,在这里插入图片描述勿怪,有什么问题私聊我。

多级指针

函数调用时,我们可以用n级指针(形参)来改变n-1指针(实参)的值。
接下来举一个上面的例子:

char **getM(int num)
{
	char **p = NULL;
	p = (char **)malloc(sizeof(char *)*num);
	int i;
	for (i = 0; i < num; i++)
	{
		p[i] = (char *)malloc(sizeof(char) * 100);
		sprintf_s(p[i], 100, "%d%d%d", i + 1, i + 1, i + 1);
	}
	return p;
}

这个函数把二级指针返回了回来,如果我们不想用返回值呢。
我们可以这样做

int getM(char ***p,int num)
{
	char **temp = NULL;
	temp = (char **)malloc(sizeof(char *)*num);
	int i;
	for (i = 0; i < num; i++)
	{
		temp[i] = (char *)malloc(sizeof(char) * 100);
		sprintf_s(temp[i], 100, "%d%d%d", i + 1, i + 1, i + 1);
	}
	*p = temp;
	return 0;
}

多维指针就简单的总结到这里。数组明天在总结,如果有什么错误的地方,请多多指正。欢迎给我私信哦。

发布了31 篇原创文章 · 获赞 8 · 访问量 3684

猜你喜欢

转载自blog.csdn.net/qq_42689353/article/details/104372675