C语言详细讲解多维数组与多维指针

目录
  • 一、指向指针的指针
  • 二、二维数组与二维指针
  • 三、数组名
  • 四、小结

一、指向指针的指针

指针的本质是变量

指针会占用一定的内存空间

可以定义指针的指针来保存指针变量的地址值

为什么需要指向指针的指针?

  • 指针在本质上也是变量
  • 对于指针也同样存在传值调用与传址调用

下面看一个重置动态空间大小(从 size 到 new_size)的代码:

#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);
    printf("%p\n", p);
    if(reset(&p, 5, 3))
    {
        printf("%p\n", p);
    }

   free(p);

   return 0;
}

输出结果如下:

简单来说逻辑是这样:新申请内存空间,然后复制原来内存空间里面的值到新的内存空间,然后释放之前的内存空间。

二、二维数组与二维指针

  • 二维数组在内存中以一维的方式排布
  • 二维数组中的第一维是一维数组
  • 二维数组中的第二维才是具体的值
  • 二维数组的数组名可看做常量指针

如下:

下面看一个遍历二维数组的示例:

#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];

    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");
    }

    printf("\n");

    printArray(p, 9);

    return 0;
}

输出结果如下:

*(*(a + i) + j) 的问题:

假设int a[2][3]={{1,2,3},{4,5,6}}, b=*(*(a + 1) + 1);

a 是二维数组,表示二维数组 a 的地址,a[0]、a[1]可看作是 2 个一维数组,分别是一维数组 a[0]、a[1] 的地址,a[0] 的值为{1,2,3},a[1] 的值为{4,5,6}。a、a[0]、*a 都是 a[0] 的地址,a + 1、a[1]、*(a + 1)都是 a[1] 的地址。

看下面的例子就明白了:

#include <stdio.h>

int main(void)
{
    int a[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    printf("%p %p %p %p\n", &a[0][0], a, a[0], *a);
    printf("%p %p %p %p %p\n", &a[0][0] + 1, a + 1, a[1], *(a + 1), &a[1][0]);
    printf("%p %p %p %p\n", (a + 1) + 1, a + 1 + 1, &a[1][1], &a[2][0]);
    printf("%d %d\n", *(*(a + 1) + 1), a[1][1]);
    return 0;
}

/*
    &a[0][0], a, a[0], *a 这四个地址值相同,都是指 a[0][0] 的地址
    a + 1, a[1], *(a + 1) 这三个地址值相同,都是指 a[1][0] 的地址
    &a[0][0] + 1 的值与 a + 1 的值不相同,前者表示的是 a[0][1]的地址,后者表示的是 a[1][0] 的地址
    a + 1, a[1], *(a + 1) 的值一样,都是代表 a[1][0] 的地址
    a[1] + 1, *(a + 1) + 1 代表 a[1][1] 的地址
    a + 1 + 1 代表的是 a[2][0] 的地址
    可以这么理解:
    a[1] 和 *(a + 1) 地址相同(二维数组中,a[1]里面存放的值和 a[1] 的地址相同,这与一维数组不同)
    当对 a[1] 和 *(a + 1) 进行操作时,如 a[1] + 1 或者 *(a + 1) + 1,相当于固定第二行,开始进行列的偏移操作
    但是单独对 a 进行操作时,如 a + 1 + 1,这就是行数固定到第三行,取的地址就是 a[2][0]
*/

输出结果如下:

三、数组名

  • —维数组名代表数组首元素的地址,如 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;
}

输出结果如下:

四、小结

  • C 语言中只支持一维数组 C 语言中只支持一维数组
  • C 语言中的数组大小必须在编译期就作为常数确定
  • C 语言中的数组元素可是任何类型的数据
  • C 语言中的数组的元素可以是另一个数组

到此这篇关于C语言详细讲解多维数组与多维指针的文章就介绍到这了,更多相关C语言 多维数组内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言深入分析数组指针和指针数组的应用

    目录 一.数组类型 二.定义数据类型 三.数组指针 四.指针数组 五.小结 一.数组类型 C语言中的数组有自己特定的类型 数组的类型由元素类型和数组大小共同决定 例:int array[5] 的类型为 int[5] 二.定义数据类型 C语言中通过 typedef 为数组类型重命名:typedef type(name)[size]; 数组类型: typedef int(AINT5)[5]; typedef float(AFLOAT10)[10]; 数组定义: AINT5 iArray; AFLOA

  • C语言零基础讲解指针和数组

    目录 一.指针和数组分析-上 1.数组的本质 2.指针的运算 3.指针的比较 4.小结 二.指针与数组分析-下 1.数组的访问方式 2.下标形式 VS 指针形式 3.a 和 &a 的区别 4.数组参数 5.小结 一.指针和数组分析-上 1.数组的本质 数组是一段连续的内存空间 数组的空间大小为 sizeof(array_type) * array_size 数组名可看做指向数组第一个元素的常量指针 下面看一段代码: #include <stdio.h> int main() { int

  • C语言函数指针详解

    目录 Introduction 函数指针 Function Pointers Exercise 1:qsort中的函数指针 Exercise 2: 总结 Introduction 上一个lab的主要内容为__data pointer__(指向数据的指针)可能在Linux系统中造成的__segmentation fault__.本次lab将考虑__function pointer__(指向函数/代码的指针)可能造成的错误:segfault或其他exceptions. 函数指针 Function P

  • C语言全方位讲解指针与地址和数组函数堆空间的关系

    目录 一.一种特殊的变量-指针 二.深入理解指针与地址 三.指针与数组(上) 四.指针与数组(下) 五.指针与函数 六.指针与堆空间 七.指针专题经典问题剖析 一.一种特殊的变量-指针 指针是C语言中的变量 因为是变量,所以用于保存具体值 特殊之处,指针保存的值是内存中的地址 内存地址是什么? 内存是计算机中的存储部件,每个存储单元有固定唯一的编号 内存中存储单元的编号即内存地址 需要弄清楚的事实 程序中的一切元素都存在于内存中,因此,可通过内存地址访问程序元素. 内存示例 获取地址 C语言中通

  • C语言函数的参数使用指针

    在c语言中实参和形参之间的数据传输是单向的"值传递"方式,也就是实参可以影响形参,而形参不能影响实参.指针变量作为参数也不例外,但是可以改变实参指针变量所指向的变量的值. #include <stdio.h> void swap1(int x,int y),swap2(int *px,int *py),swap3(int *px,int *py); int main(void) { int a=1,b=2; int *pa=&a,*pb=&b; swap1(

  • C语言详细讲解多维数组与多维指针

    目录 一.指向指针的指针 二.二维数组与二维指针 三.数组名 四.小结 一.指向指针的指针 指针的本质是变量 指针会占用一定的内存空间 可以定义指针的指针来保存指针变量的地址值 为什么需要指向指针的指针? 指针在本质上也是变量 对于指针也同样存在传值调用与传址调用 下面看一个重置动态空间大小(从 size 到 new_size)的代码: #include <stdio.h> #include <malloc.h> int reset(char** p, int size, int

  • C语言 详细讲解数组参数与指针参数

    目录 一.C语言中的数组参数退化为指针的意义 二.二维数组参数 三.等价关系 四.被忽视的知识点 五.小结 一.C语言中的数组参数退化为指针的意义 C 语言中只会以值拷贝的方式传递参数 当向函数传递数组时: 将整个数组拷贝一份传入函数        × 将数组名看做常量指针传数组首元素地址    √ C 语言以高效作为最初设计目标: a) 参数传递的时候如果拷贝整个数组执行效率将大大下降. b) 参数位于栈上,太大的数组拷贝将导致栈溢出. 二.二维数组参数 二维数组参数同样存在退化的问题 二维数

  • C语言详细讲解指针数组的用法

    目录 1. 指针数组定义方法 2. 指针的指针(二级指针) 3. 字符串和指针 4. 数组指针 定义方法 数组指针的用法 1. 指针数组定义方法 格式: 类型说明符 *数组名[ 元素个数 ] int *p[10]; // 定义了一个整型指针数组p,有10个元素,都是int *类型的变量 指针数组的分类: 同指针类型的分类,见上一篇 大多数情况下,指针数组都用来保存多个字符串. #include <stdio.h> int main() { char *name[5] = {"Hell

  • C语言详细讲解树状数组与线段树

    目录 树状数组 动态求连续区间和 数星星 线段树 动态求连续区间和 数列区间最大值 树状数组 动态求连续区间和 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和. 输入格式第一行包含两个整数 n 和 m,分别表示数的个数和操作次数. 第二行包含 n 个整数,表示完整数列. 接下来 m 行,每行包含三个整数 k,a,b (k=0,表示求子数列[a,b]的和:k=1,表示第 a 个数加 b). 数列从 1 开始计数. 输出格式输出若干行数字,表示 k

  • C语言详细讲解二分查找用法

    目录 [力扣题号]704.二分查找 力扣题目链接 示例 1: 输入: nums = [-1,0,3,5,9,12], target = 9     输出: 4       解释: 9 出现在 nums 中并且下标为 4 示例 2: 输入: nums = [-1,0,3,5,9,12], target = 2     输出: -1        解释: 2 不存在 nums 中因此返回 -1 提示: 你可以假设 nums中的所有元素是不重复的. n将在[1, 10000]之间. nums的每个元素

  • C语言详细讲解strcpy strcat strcmp函数的模拟实现

    目录 一.模拟实现strcpy函数 二.模拟实现strcat函数 三.模拟实现strcmp函数 四.小结 一.模拟实现strcpy函数 strcpy函数是字符串拷贝函数,就是将源字符串拷贝到目标空间中. char * strcpy ( char * destination, const char * source );//库函数中的声明 将源(source)指向的c字符串复制到目标(destination)指向的数组中,包括终止的空字符(并在该点停止). 为避免溢出,目标(destination

  • C语言详细讲解通过递归实现扫雷的展开

    目录 用户选择菜单 棋盘初始化 布置雷(随机布置) 打印棋盘 玩家下棋 棋盘展开 展开部分思维导图 展开函数最后一个else return 作用 周围雷个数判断 用户选择菜单 void menu() { printf("****************************\n"); printf("******** 1.play **********\n"); printf("******** 0.exit **********\n"); p

  • Android详细讲解谷歌推出的官方二维码扫描库

    相信二维码扫描现在大家都已经不稀奇了,几乎所有的App里都会支持这个功能. 这里我要问大家一个问题,你们都是如何在自己的App中加入二维码扫描功能的呢? 相信会有一大部分朋友说,使用的是ZXing或者ZBar这种开源库. 但是不知道大家有没有思考过,二维码功能这么常见,为什么Google却没有提供一个官方的二维码扫描库呢? 反正我是没思考过.有需求,找开源,这可能已经成了很多Android开发者的常态化思维. 但令我没想到的是,官方的二维码扫描库,它真的要来了. 由于我是Google的GDE,有

  • C语言 详细讲解逻辑运算符的使用

    目录 一.&& 与 II 分析 二.!分析 三.小结 一.&& 与 II 分析 下面的程序运行结束后,i, j,k 的值分别为多少? #include <stdio.h> int main() { int i = 0; int j = 0; int k = 0; ++i || ++j && ++k; printf("i = %d\n", i); printf("j = %d\n", j); printf(&

  • C语言详细讲解位运算符的使用

    目录 一.位运算符分析 二.小贴士 三.位运算与逻辑运算 四.小结 一.位运算符分析 C语言中的位运算符 位运算符直接对 bit 位进行操作,其效率最高. & 按位与 | 按位或 ^ 按位异或 ~ 取反 << 左移 >> 右移 左移和右移注意点 左操作数必须为整数类型 char 和 short 被隐式转换为 int 后进行移位操作 右操作数的范围必须为:[0,31] 左移运算符<< 将运算数的二进制位左移 规则:高位丢弃,低位补0 右移运算符>> 把

随机推荐