【C 语言】二级指针内存模型 ( 指针数组 | 二维数组 | 自定义二级指针 | 将 一、二 模型数据拷贝到 三 模型中 并 排序 )

简介: 【C 语言】二级指针内存模型 ( 指针数组 | 二维数组 | 自定义二级指针 | 将 一、二 模型数据拷贝到 三 模型中 并 排序 )

文章目录

一、指针数组 和 二维数组 数据 拷贝到 自定义二级指针 中

1、函数形参 设计规则

2、三种内存模型 对应 函数形参 指针退化规则

二、完整代码示例





一、指针数组 和 二维数组 数据 拷贝到 自定义二级指针 中


将 指针数组 和 二维数组 中的数据 拷贝到 自定义二级指针 内存模型中 , 并进行排序 ;



1、函数形参 设计规则


函数形参 设计规则 : 向 函数中 传入 二级指针 , 如果只是 使用 该 二级指针 指向的数据 , 可以 直接传入 二级指针 作为形参 ; 如果 需要 修改 二级指针 的指向 , 则需要 传入 三级指针 ;



2、三种内存模型 对应 函数形参 指针退化规则


① 指针数组 : 指针数组 参数 , 外层是数组 , 内层是指针 , 外层数组 退化成 指针 , 整体退化成 二级指针 ;


 

// 指针数组
    char *p1[] = {"ab", "ef", "cd"};


退化为 :二级指针 ;


char **p1



② 二维数组 : 二维数组 , 最高维退化成 指针 , 整体退化成 数组指针 , 指向数组的指针 ;


// 二维数组
    char p2[3][5] = {"13", "35", "22"};


退化为 : 数组指针 ;


// 数组指针 
char (*p2)[5]


③ 二维指针 : 二维指针 作为参数 不退化 ;


// 二级指针
    char **p3 = NULL;


退化为 :


// 二维指针 
char **p3


代码示例 :


/**
 * @brief copy_data 将 指针数组 和 二维数组 中的数据拷贝到 二维指针 中
 * @param p1 指针数组 参数 , 外层是数组 , 内层是指针 , 外层数组 退化成 指针 , 整体退化成 二级指针
 * @param count1 指针数组 中的 指针变量元素个数
 * @param p2 二维数组 , 最高维退化成 指针 , 整体退化成 数组指针 , 指向数组的指针
 * @param count2 二维数组的 一维数组 个数
 * @param newp 指向 二级指针 的 三级指针
 * @param count3p 指向一个数字的指针 , 该 数字是 二级指针 指向的 一级指针 个数
 * @return
 */
int copy_data(char **p1, int count1, char (*p2)[5], int count2, char ***newp, int *count3p)






二、完整代码示例


完整代码示例 :


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 计算数组 array 大小 */
#define LENGTH(array) (sizeof(array)/sizeof(*array))
/**
 * @brief copy_data 将 指针数组 和 二维数组 中的数据拷贝到 二维指针 中
 * @param p1 指针数组 参数 , 外层是数组 , 内层是指针 , 外层数组 退化成 指针 , 整体退化成 二级指针
 * @param count1 指针数组 中的 指针变量元素个数
 * @param p2 二维数组 , 最高维退化成 指针 , 整体退化成 数组指针 , 指向数组的指针
 * @param count2 二维数组的 一维数组 个数
 * @param newp 指向 二级指针 的 三级指针
 * @param count3p 指向一个数字的指针 , 该 数字是 二级指针 指向的 一级指针 个数
 * @return
 */
int copy_data(char **p1, int count1, char (*p2)[5], int count2, char ***newp, int *count3p)
{
    // 返回值
    int ret = 0;
    // 循环控制变量
    int i = 0, j = 0;
    // 临时长度
    int len = 0;
    // 创建的新的 二级指针 , 用于存放 指针数组 二维指针 中的数据
    char **p3 = NULL;
    // 分配一块内存 , 这块内存中存放 count1 + count2 个一级指针
    p3 = (char **)malloc((count1 + count2) * sizeof(char *));
    // 验证指针合法性
    if (p3 == NULL)
    {
        ret = -1;
        return ret;
    }
    // 遍历将 p1 指针数组 中的数据 拷贝到 二级指针 中
    for (i = 0; i < count1; i++)
    {
        // 指针数组 中指针 指向的 字符串长度
        // 最后的 + 1 是加上 \0 字符
        len = strlen(p1[i]) + 1;
        // 为 指向字符串的 一级指针 在堆内存中分配内存
        p3[i] = (char *)malloc( len * sizeof(char)) ;
        // 如果堆内存分配失败 , 直接退出
        if (p3[i] == NULL)
        {
            return -2;
        }
        // 向堆内存中拷贝 字符串 数据
        strcpy(p3[i], p1[i]);
    }
    // 遍历将 p2 二维数组 中的数据 拷贝到 二级指针 中
    // 之前已经拷贝了 count1 个 , 因此从第 count1 + 1 位置开始拷贝
    // 第 count1 + 1 个的索引从 0 开始 , 其索引是 count1 ;
    for (j = 0; j < count2; j++)
    {
        // 计算 二维数组 中第 j 个一维数组 字符串长度
        // 最后的 + 1 是加上 \0 字符
        len = strlen(p2[j]) + 1;
        // 为 指向字符串的 一级指针 在堆内存中分配内存
        p3[count1 + j] = (char *)malloc(len * sizeof(char));
        // 堆内存分配失败 , 退出
        if (p3[count1 + j] == NULL)
        {
            return -3;
        }
        // 向堆内存中拷贝 字符串 数据
        strcpy(p3[count1 + j], p2[j]);
    }
    // p3 二维指针 中存储的 字符串个数
    len = count1 + count2;
    // 指针 间接赋值 作为 返回值
    *count3p = len; // 二维指针 赋值给 三维指针形参 指向的内存地址
    *newp = p3;     // 字符串个数 赋值
    return 0;
}
/**
 * @brief sort_data 二级指针 指向的 一级指针 数据排序
 * 需要修改 二级指针 指向的一级指针次序
 * 二级指针 不需要修改 , 因此这里传入 二级指针即可
 * 如果需要修改 二级指针 , 则需要传入 三级指针
 * @param p3 二级指针 数据
 * @param num3 二级指针 指向的 一级指针 个数
 * @return
 */
int sort_data(char **p3, int len)
{
    // 循环控制变量
    int i = 0, j = 0;
    // 交换 字符串 时的临时变量
    char *p = NULL;
    // 验证指针合法性
    if(p3 == NULL)
    {
        return -1;
    }
    // p3 指向的 若干 字符串 之间的排序
    for (i = 0; i < len; i++)
    {
        for (j = i + 1; j < len; j++)
        {
            if ( strcmp(p3[i], p3[j]) > 0 )
            {
                // 交换 i, j 位置的 一级指针
                p = p3[i];
                p3[i] = p3[j];
                p3[j] = p;
            }
        }
    }
    return 0;
}
/**
 * @brief sort_data 二级指针 指向的 一级指针 数据排序
 * 需要修改 二级指针 指向的一级指针次序
 * 二级指针 不需要修改 , 因此这里传入 二级指针即可
 * 如果需要修改 二级指针 , 则需要传入 三级指针
 * @param p3 二级指针 数据
 * @param num3 二级指针 指向的 一级指针 个数
 * @return
 */
int print_data(char **p3, int len)
{
    // 循环控制变量
    int i = 0;
    // 交换 字符串 时的临时变量
    char *p = NULL;
    // 验证指针合法性
    if(p3 == NULL)
    {
        return -1;
    }
    // p3 指向的 若干 字符串 之间的排序
    for (i = 0; i < len; i++)
    {
        printf("%s\n", p3[i]);
    }
    return 0;
}
/**
 * @brief 主函数入口
 * @return
 */
int main(int argc, char* argv[], char**env)
{
    // 指针数组
    char *p1[] = {"ab", "ef", "cd"};
    // 二维数组
    char p2[3][5] = {"13", "35", "22"};
    // 二级指针
    char **p3 = NULL;
    // 存储 p3 指向的一级指针个数
    int len3 = 0;
    // 将 指针数组 二维数组 数据 拷贝到 二级指针 中
    copy_data(p1, 3, p2, 3, &p3, &len3);
    // 拷贝之后的结果
    print_data(p3, len3);
    // 数据排序
    sort_data(p3, len3);
    // 打印排序之后的结果
    printf("\nSort :\n");
    print_data(p3, len3);
    // 命令行不要退出
    system("pause");
    return 0;
}



执行结果 :


ab
ef
cd
13
35
22
Sort :
13
22
35
ab
cd
ef
请按任意键继续. . .

image.png

目录
相关文章
|
4月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
267 15
|
9月前
|
存储 人工智能 Java
一文彻底搞定C语言中的二维数组
本文详细介绍了C语言中的多维数组,包括二维和三维数组的定义、初始化方式、内存布局及遍历方法。通过具体示例讲解了多种赋值技巧,并强调了数组在内存中按行存放的特点。希望这些内容能帮助你在编程路上不断成长!君志所向,一往无前!
445 1
一文彻底搞定C语言中的二维数组
|
8月前
|
分布式计算 算法 Java
|
11月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
368 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
10月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】按从小到大排序三个数(头歌实践教学平台习题)【合集】
本任务要求从键盘输入三个数,并按从小到大的顺序排序后输出。主要内容包括: - **任务描述**:实现三个数的排序并输出。 - **编程要求**:根据提示在编辑器中补充代码。 - **相关知识**: - 选择结构(if、if-else、switch) - 主要语句类型(条件语句) - 比较操作与交换操作 - **测试说明**:提供两组测试数据及预期输出。 - **通关代码**:完整代码示例。 - **测试结果**:展示测试通过的结果。 通过本任务,你将掌握基本的选择结构和排序算法的应用。祝你成功!
127 4
|
12月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
1003 13
|
12月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
359 12
|
11月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
377 6
|
12月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
270 6
|
12月前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
下一篇
开通oss服务