C语言-第26课 - 多维数组和多维指针

时间:2022-08-31 09:10:47

第26课 - 多维数组和多维指针

 

 

  1. 指向指针的指针

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;

}

运行结果:5555

注:为什么需要指向指针的指针

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. 二维数组

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到底是24列,还是42列?

答:是两行四列。

 

  1. 数组名

(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),它的值是16a[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;

}

 

 

数组小结

1C语言中只有一维数组,而且数组大小必须在编译期就作常数确定。

2C语言中一维数组的元素可以是任何类型的数据,包括可以是另一个数组。

3C语言中只有数组的大小和数组首元素的地址是编译器直接确定的。