C之多维数组和多维指针(三十一)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C之多维数组和多维指针(三十一)相关的知识,希望对你有一定的参考价值。

        我们在之前讲到过指针的本质是变量,当然指针也就会占用一定的内存空间。我们便可以定义指针的指针来保存指针变量的地址值啦,这便是我们所说的二维指针啦。

        那么为什么需要指向指针的指针呢?指针的本质便是变量,对于指针也同样存在传值调用和传址调用。我们来看看一个示例代码,代码如下

#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 = malloc(sizeof(int) * 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);
    
    printf("%p\n", p);
    
    if( reset(&p, 5, 3) )
    {
        printf("%p\n", p);
    }
    
    free(p);
    
    return 0;
}

        我们看到这个函数的功能是重置申请内存空间的大小,在最后打印的是重置前后的指针的地址。如果重置成功,地址便会改变,结果如下

技术分享图片

        那么二维数组究竟是怎样的呢?二维数组在内存中是以一维数组的方式排布的,它的第一维是一维数组。第二维才是具体的值,二维数组的数组名也可看做常量指针。下图更形象的说明了

技术分享图片

        那么我们接下来以代码为例进行分析

#include <stdio.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];
    
    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) ==> a[i]; *(a[i] + j) ==> a[i][j]
        }
        
        printf("\n");
    }
    
    printf("\n");
    
    PrintArray(p, 9);
    
    return 0;
}

        我们看到在程序的第17行定义了二维数组 a,在第18行则定义了指针 p ,指向二维数组的首元素的地址。接下来我们便打印了这个数组,在第35行我们调用 PrintArray 函数打印数组。结果如下

技术分享图片

        我们看到二维数组在内存中也是呈一维分布的。那么一维数组名代表数组首元素的地址,二维数组名同样也代表数组首元素的地址。如:int a[5]  a的类型为 int*int m[2][5] m的类型为 int(*)[5];   

        二维数组名可看做是指向数组的常量指针,它也可以看做是一维数组,只不过数组中的每个元素同样也是同类型的一个数组。我们下来看看如何申请二维数组,代码如下

#include <stdio.h>
#include <malloc.h>

int** malloc2d(int row, int col)
{
    int** ret = NULL;
    
    if( (row > 0) && (col > 0) )
    {
        int* p = NULL;
        
        ret = (int**)malloc(row * sizeof(int*));
        p = (int*)malloc(row * col * sizeof(int));
        
        if( (ret != NULL) && (p != NULL) )
        {
            int i = 0;
            
            for(i=0; i<row; i++)
            {
                ret[i] = p + i * col;
            }
        }
        else
        {
            free(ret);
            free(p);
            
            ret = NULL;
        }
        
    }
    
    return ret;
}

void free2d(int** p)
{
    if( *p != NULL )
    {
        free(*p);
    }
    
    free(p);
}

int main()
{
    int** a = malloc2d(3, 3);
    int i = 0;
    int j = 0;
    
    for(i=0; i<3; i++)
    {
        for(j=0; j<3; j++)
        {
            printf("%d, ", a[i][j]);
        }
        
        printf("\n");
    }
    
    free2d(a);
    
    return 0;
}

        我们在主函数里申请了二维数组 a,打印并释放它。我们来看看结果

技术分享图片

        如我们所愿,二维数组已经申请好了。通过对多维数组和多维指针的学习,总结如下:1、C 与应用中只支持一维数组,并且它的大小必须在编译期就作为常数确定;2、数组里的元素可以是任何类型的数据,甚至可以是另一个数组,这也就是多维数组的本质了。


        欢迎大家一起来学习 C 语言,可以加我QQ:243343083

以上是关于C之多维数组和多维指针(三十一)的主要内容,如果未能解决你的问题,请参考以下文章

C之数组参数和指针参数(三十一)

C 语言数组 ( 多维数组本质 | 步长角度 理解 多维数组本质 )

C 语言数组 ( 多维数组本质 | n 维数组名称本质 是 n-1 级数组指针 )

C多维数组中的指针地址

《C专家编程》数组和指针并不同--多维数组

图解多级指针与“多维”数组