第26课 - 多维数组和多维指针
- 指向指针的指针
(1)指针变量的本质是一个变量,在内存中会占用一定的空间,因此可以定义指针来保持指针变量的地址值。
(2)定义指向指针的指针,主要由于指针也同样存在传值调用与传址调用。
eg:
#include<stdio.h>
#include<string.h>
int main()
{
int a = 5;
int* p = NULL;
int* k = NULL;
k = &a;
int** pp = NULL; //指向指针的指针
pp = &p; //pp指向的是一级指针的地址
*pp = &a; //通过*这个钥匙,大考pp这个防盗门,得到的是*p,将a的地址赋值给*//p,也就是指针p指向a 。
printf("%d,%d,%d,%d\n",a,*p,**pp,*k);
return 0;
}
运行结果:5,5,5,5
注:为什么需要指向指针的指针
l 指针的本质也是变量
l 对于指针同样存在传值调用与传址调用
实例分析---多级指针的分析与使用,重置动态空间大小
正常情况下,我们为p在堆上申请了5个空间,但是,在实际的应用中,我们要用的空间,可能大于5,也可能小于5,所以需要重新分配地址空间,我们就编辑这样的一个函数来实现这一个功能。
#include <stdio.h>
#include <malloc.h>
int reset(char**p, int size, int new_size) //第一个参数,是一个指向指针的指针。
{
int ret = 1;
int i = 0;
int len = 0;
char* pt = NULL;
char* tmp = NULL;
char* pp = *p;
if( (p != NULL) && (new_size > 0) )
{
pt = (char*)malloc(new_size);
tmp = pt;
len = (size < new_size) ? size : new_size;
//取新旧地址中最短的
for(i=0; i<len; i++)
{
*tmp++ = *pp++;
}
free(*p);
*p = pt;
}
else
{
ret = 0;
}
return ret;
}
int main()
{
char* p = (char*)malloc(5); //在堆空间上申请5个空间
printf("%0X\n", p);
//我们通过函数改变的是函数外面的一个函数的值,所以我们要进行的是传址操作。
if( reset(&p, 5, 3) )
{
printf("%0X\n", p);
}
return 0;
}
- 二维数组
(1)二维数组名在内存中以一维的方式排布。
(2)二维数组中的第一维是一维数组。
(3)二维数组中的第二维才是具体的值。
(4)二维数组的组名可以看做常量指针。
例程--以一维的方式遍历二维数组
#include <stdio.h>
#include <malloc.h>
void printArray(int a[], int size)
{
int i = 0;
printf("printArray: %d\n", sizeof(a));
for(i=0; i<size; i++)
{
printf("%d\n", a[i]);
}
}
int main()
{
int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
int* p = &a[0][0]; //指针指向的地址
printArray(p, 9);
return 0;
}
运行结果:
printArray: 4
0
1
2
3
4
5
6
7
8
分析:我们发现二维数组可以用一维的方式打印出来,说明二维数组在物理的存储上是以一维也就是线性的方式排布的
下面再分析一个问题:int matrix[2][4]; matrix到底是2行4列,还是4行2列?
答:是两行四列。
- 数组名
(1)一维数组名代表数组首元素的地址。
int a[5] a的类型是int*
(2)二维数组名同样代表数组首元素的地址
int m[2][5] m的类型是int(*)[5],即数组指针
二维数组可以看做一维数组,二维数组中的每个元素都是同类型的一维数组,,此时将二维数组看作一维数组。上面m的类型是数组指针。有如下的例程:
#include <stdio.h>
int main()
{
int a[5][5];
int(*p)[4];
p = a; //指针指向一维数组,也就是大门对应大门。
printf("%d\n", &p[4][2] - &a[4][2]);
}
运行结果:-4
分析:
首先我们知道指针数组p和二维数a的类型是不符合的。安一维数组的排列方式,发现&a[4][2](指向第22个元素)超前&p[4][2](指向第18个元素)四位。因为a[]一组you5个元素,*p一组只有4个元素。
或者这样想,p[4]就是p+4*sizeof(p),它的值是16。a[4就是a+4*sizeof(a)它的值是20。下面它们同样是再偏移两个,一样的。相差4.
下面我们看另一个例子--以指针的方式遍历2维数组:
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{
int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
printf("%d ", *(*(a+i) + j)); //等价于a[i][j]
}
}
printf("\n");
}
运行结果:0 1 2 3 4 5 6 7 8
手把手写代码---如何动态申请二维数组,以二维指针来模拟
#include<stdio.h>
#include<malloc.h> //动态申请,必须要有而定头文件
int** malloc(int row, int col)
{
int** ret = (int**)malloc(sizeof(int**)*row);
int* p = (int*)malloc(sizeof(int)*row*col);
int i = 0;
if(ret&&p)
{
for(i=0; i<row;i++)
{
ret[i] = (p + i*col);
}
}
else
{
free(ret);
free(p);
ret = NULL;
}
return ret;
}
void free2d(int** a)
{
free(a[0]);
free(a);
}
int main()
{
return 0;
}
数组小结
(1)C语言中只有一维数组,而且数组大小必须在编译期就作常数确定。
(2)C语言中一维数组的元素可以是任何类型的数据,包括可以是另一个数组。
(3)C语言中只有数组的大小和数组首元素的地址是编译器直接确定的。