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。

原文地址:http://blog.51cto.com/12810168/2106629

时间: 2024-10-01 19:42:46

C之多维数组和多维指针(三十一)的相关文章

C#一维数组,二维数组,多维数组

所谓的数组,就是相同数据类型的元素的元素按一定顺数排列的集合,就是把有限个类型相同的变量用一名字命名,然后用编号区分他们的变量的集合,这个名字成为数组名,编号称为下标.组成数组的各个变量成为数组的分量,也称为数组的元素,有时也称为下标变量,数组是在程序设计中,为了处理方便,把具有相同类型的若干变量按有序的形式组织起来的一种形式.这些按序排列的同类数据元素的集合成为数组. 数组又分为一维数组,二维数组,多维数组 一维数组用一个整数来索引,多维数组用两个或多个整数来索引. 一.数据类型[] 变量名

二维数组及二维指针的传递及一些思考

二维数组和二位指针在程序知识中是一个难点,往往会将人弄得头昏眼花.总结一下这个难点的相关问题. 二维数组,顾名思义就是数组的数组:二维指针是指针的指针.首先,我们来看看二维数组和二维指针等价的问题. 在<C专家编程>10.3节的小启发里讲的很透彻:(以下这段文字及对比一定要认真分析!) 数组和指针参数是如何被编译器修改的? "数组名被改写成一个指针参数"规则并不是递归定义的.数组的数组会被改写成"数组的指针",而不是"指针的指针":

Objective-C 下用 NSArray 和 NSMutableArray 定义二维数组跟多维数

Objective-C 下用 NSArray 和 NSMutableArray 定义二维数组跟多维数组 目录 问题描述 Objective-C 中的数组对像 NSArray 和 NSMutableArray 简介 二维数组:嵌套两次的 NSMutableArray 多维数组:嵌套多次的 NSMutableArray 问题描述 说实话,不太习惯面向对象编程,所以在操作 Objective-C 中数组对象时,总是忍不住跟 C 中的数组做比较,正好要建立一个二维数组,需要根据二维数组的下标来做相应的设

js-二维数组和多维数组

一.二维数组的表示 myarray[][] 二.二维数组的定义 方法一: var a = new Array(); for(var i=0;i<3;i++){ //一维长度为3 a[i] = new Array(); for(var j=0;j<5;j++){ //二维长度为5 a[i][j] = i+j; } } 方法二: var a = [[1,2,3],[2,3,4]]: 三.赋值 myarr[1][2] = 5; //1表示第二行 :2表示第3列 四.多维数组与二维数组类似

二维数组转化成一维指针

二维数组转化为一维指针来使用本实例用到了随机数,链表生成,遍历,有待扩展 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 #include<math.h> 5 //定义个结构体Emp用来存放员工信息 6 typedef struct Emp 7 { 8 int eno; 9 char *ename; 10 int dno; 11 Emp *next; 12 13 }emp,*pemp

C# 数组、一维数组、二维数组、多维数组、锯齿数组

C#  数组.一维数组.二维数组.多维数组.锯齿数组 一.数组: 如果需要使用同一类型的对象,就可以使用数组,数组是一种数据结构,它可以包含同一类型的多个元素.它的长度是固定的,如长度未知的情况下,请使用集合. 二.一维数组: 声明及初始化: class Program { static void Main(string[] args) { //方法一 int[] num = new int[3];//声明一个长度为3的值类型的数组: num[0] = 3;//为数组赋值: num[1] = 5

【C语言探索之一】二维数组,二维数组名的意义

1.一维数组 一维数组名,代表两个(1)代表整个数组(虽然谭老爷子的书上说不能,但是只是那个情境下) (2)代表首地址 2.二维数组 想到二维数组在指针方面的理解很是麻烦,所以我自己想了一种理解方式,如下图所示 二维数组名的意义感觉很难受,所以自己来探索下其代表些什么 下面是我的代码和结果 可以看到他们四个的值是一模一样的,但是意义不一样的 1.b数组名,他是指向整个数组的指针, 2.*b是数组第一维的首地址,相当于b[0] 3.&b目的是为了看出数组名的地址,最后结果显而易见,他的地址也是这个

“全栈2019”Java第三十一章:二维数组和多维数组详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第三十一章:二维数组和多维数组详解 下一章 "全栈2019"Java第三十二章:增强for循环Foreach语法 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Ja

c++ 动态分配二维数组 new 二维数组

#include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { //建立一个16行5列的数组 int **p = new int*[16];//分配堆内存16个 int* for(int i = 0;i < 16;i++)//分配堆内存给每一个int* p[i] = new int[5]; //给这个数组赋值 int k = 0; f