上一篇博客总结了一级指针与字符串,这篇博客主要总结多级指针与多维数组的重点与难点。
二级指针
二级指针的基础在这里就不再赘述了,二级指针,顾名思义,它就是一个指向指针的指针,它的指向是一个指针。主要简单的总结一下二级指针的用法。
指针的输入输出特性前面简单的介绍过,当指针所指向的内存空间是在主调函数中分配好的,那么指针就做输入,当指针所指向的内存空间是在被调函数中分配好德,那么指针就做输出。接下来几个简单的例子。
一级指针的输入输出特性
#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;
}
多维指针就简单的总结到这里。数组明天在总结,如果有什么错误的地方,请多多指正。欢迎给我私信哦。