深入探讨C语言中的高级指针操作

news2024/9/22 6:20:34

目录

指针与内存管理的高级技巧

1. 动态数组的重新分配

2. 内存碎片化的处理

3. 内存对齐

函数指针数组与回调函数的高级用法

1. 基本函数指针用法

2. 函数指针数组

3. 回调函数的使用

指针与数据结构的结合

1. 自定义链表


C语言以其强大的底层操作能力和高效的性能著称,而指针则是C语言中最具特色和强大的工具之一。指针不仅仅是指向内存地址的变量,还可以用来进行内存管理、函数回调、数据结构操作等高级编程任务。在这篇博客中,我们将深入探讨指针的高级操作,包括指针与内存管理的高级技巧、函数指针数组与回调函数的高级用法、指针与数据结构的结合(例如自定义链表、树、图结构),以及内存池管理与指针的优化使用。


指针与内存管理的高级技巧

在C语言中,内存管理是非常重要的,特别是在涉及到动态内存分配时。我们通常使用malloccallocreallocfree函数来分配和释放内存。然而,使用指针进行内存管理不仅仅是简单的内存分配与释放。为了有效地管理内存,我们需要了解一些高级技巧。

1. 动态数组的重新分配

假设你正在处理一个动态增长的数组。在初始时,你可能并不知道需要多少内存。这时,可以使用realloc函数来重新分配数组大小。例如:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = malloc(5 * sizeof(int));  // 初始分配5个整数的空间
    if (!arr) {
        perror("Failed to allocate memory");
        return -1;
    }

    // 使用数组的初始内存
    for (int i = 0; i < 5; i++) {
        arr[i] = i;
    }

    // 动态扩展数组至10个元素
    int *temp = realloc(arr, 10 * sizeof(int));
    if (!temp) {
        free(arr);  // realloc失败时,原来的内存块仍然保留,所以要释放
        perror("Failed to reallocate memory");
        return -1;
    }

    arr = temp;  // 重新指向新分配的内存

    for (int i = 5; i < 10; i++) {
        arr[i] = i;
    }

    // 打印数组内容
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }

    free(arr);  // 释放内存
    return 0;
}

在上面的代码中,我们首先分配了一个可以容纳5个整数的数组,后来通过realloc扩展了数组的大小。如果realloc失败,我们需要释放之前分配的内存以避免内存泄漏。

2. 内存碎片化的处理

在长时间运行的程序中,频繁的动态内存分配和释放可能会导致内存碎片化,导致程序运行效率下降。为了减轻内存碎片化的影响,程序员可以采用以下策略:

  • 合并小块内存:在频繁分配和释放小块内存时,可以使用自定义的内存池或内存管理器来合并小块内存,以减少内存碎片化。

  • 内存池管理:内存池是一种预先分配一大块内存,然后根据需要从中分配小块内存的技术。这样可以有效减少内存碎片化。

3. 内存对齐

在某些架构中,内存访问的效率与数据的内存对齐有直接关系。确保数据正确对齐可以提高程序的执行效率。

#include <stdio.h>
#include <stdlib.h>

struct AlignedData {
    int a;
    double b;
} __attribute__((aligned(16)));  // 强制16字节对齐

int main() {
    struct AlignedData *data = malloc(sizeof(struct AlignedData));
    if (!data) {
        perror("Failed to allocate memory");
        return -1;
    }

    printf("Address of data: %p\n", (void*)data);
    free(data);
    return 0;
}

通过__attribute__((aligned(16))),我们可以确保AlignedData结构体在内存中是16字节对齐的。


函数指针数组与回调函数的高级用法

函数指针是指向函数的指针,通过它可以动态地调用函数。函数指针数组是函数指针的集合,通常用于实现回调机制或选择性地调用不同的函数。

1. 基本函数指针用法

让我们先看一个简单的函数指针示例:

#include <stdio.h>

void say_hello() {
    printf("Hello, World!\n");
}

int main() {
    void (*func_ptr)() = say_hello;  // 定义函数指针并指向say_hello
    func_ptr();  // 通过指针调用函数
    return 0;
}

在上面的代码中,func_ptr是一个指向void返回类型且不带参数的函数的指针。我们可以通过func_ptr()调用say_hello函数。

2. 函数指针数组

函数指针数组可以用来存储多个函数指针,方便在需要时调用不同的函数。例如,假设我们有一组数学运算函数,我们可以用函数指针数组来存储它们,并动态调用。

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

int divide(int a, int b) {
    if (b != 0) return a / b;
    else return 0;
}

int main() {
    int (*operations[])(int, int) = {add, subtract, multiply, divide};  // 函数指针数组

    int a = 10, b = 5;
    for (int i = 0; i < 4; i++) {
        printf("Result: %d\n", operations[i](a, b));  // 动态调用不同的函数
    }

    return 0;
}

这里,我们定义了一个包含四个函数指针的数组operations,通过遍历该数组,我们可以调用不同的运算函数。

3. 回调函数的使用

回调函数是指作为参数传递给另一个函数,并在该函数内部被调用的函数。回调函数在实现异步操作、事件驱动编程、信号处理等方面非常有用。

#include <stdio.h>

void callback_example(void (*callback)()) {
    printf("Executing callback...\n");
    callback();  // 调用回调函数
}

void say_hello() {
    printf("Hello from callback!\n");
}

int main() {
    callback_example(say_hello);  // 将函数指针作为参数传递
    return 0;
}

在上面的例子中,callback_example函数接受一个函数指针作为参数,并在其内部调用该函数。这种技术可以用于通知、信号处理或在特定条件下执行的延迟操作。


指针与数据结构的结合

指针与动态数据结构的结合是C语言中非常强大的功能。我们可以使用指针创建灵活的数据结构,如链表、树和图等。

1. 自定义链表

链表是一种常见的数据结构,使用指针来管理节点之间的连接。下面是一个简单的单向链表实现:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

Node* create_node(int data) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    if (!new_node) {
        perror("Failed to allocate memory");
        exit(-1);
    }
    new_node->data = data;
    new_node->next = NULL;
    return new_node;
}

void append(Node** head_ref, int new_data) {
    Node* new_node = create_node(new_data);
    Node* last = *head_ref;

    if (*head_ref == NULL) {
        *head_ref = new_node;
        return;
    }

    while (last->next != NULL) {
        last = last->next;
    }

    last->next = new_node;
}

void print_list(Node *node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

int main() {
    Node* head = NULL;

    append(&head, 1);
    append(&head, 2);
    append(&head, 3);

    print_list(head);

    // 记得释放内存!
    return 0;
}

在这个实现中,我们定义了一个Node结构体,包含了数据和指向下一个节点的指针。append函数用于在链表末尾添加新节点,print_list函数则遍历并打印链

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【信创】Linux下EFI引导配置工具efibootmgr _ 统信 _ 麒麟 _ 方德

往期好文&#xff1a;deepin V23 Release 安装与功能介绍&#xff01;&#xff01;&#xff01; Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在信创操作系统上使用EFI引导管理器配置工具efibootmgr命令详解的文章。efibootmgr是一个在基于UEFI的系统中管理EF…

AI数字员工技能全开,招生、培训、写教案,样样都行

只需要几个AI数字员工&#xff0c;就可以协助您办一所高质量的学校。 教务管理、教师培训、招生咨询、家校沟通、学生评价、资料整理、学习伴侣、写教案、总结、学生评语等。 这些都可以用AI数字员工来完成。 比如&#xff0c;AI培训专员给教师做制度培训、教学培训&#xf…

裴蜀定理相关结论

裴蜀定理: axbygcd(a,b) 必定有解 1. 有无限个数凑不出来 有无限个数凑不出来 2. 最大凑不出的数字 在 的条件下&#xff0c;最大凑不出的数为 推广&#xff1a;若数字数目大于2&#xff0c;gcd仍然为1&#xff0c;最大凑不出来的数字一定小于上面的结论值&#xff0c;即局…

计算机网络——TCP协议与UDP协议详解(上)

一、前言 1.1 再次理解传输层 传输层是计算机网络中的一层&#xff0c;位于网络层和应用层之间。它主要负责在网络中的两个端系统之间提供可靠的、端到端的数据传输服务。简单理解&#xff0c;传输层就是负责在源主机和目标主机之间提供端到端的数据传输。 传输层的两个主要协…

EasyRecovery 16/17数据恢复软件2024最新永久破解版激活码注册码分享

EasyRecovery &#xff08;易恢复中国&#xff09;是由全球著名数据厂商Ontrack 出品的一款数据文件恢复软件。支持恢复不同存储介质数据&#xff1a;硬盘、光盘、U盘/移动硬盘、数码相机、Raid文件恢复等&#xff0c;能恢复包括文档、表格、图片、音视频等各种文件。 开发背…

鸿蒙开发5.0【基于ArkUI的验证码】实现

场景描述 场景一&#xff1a;基于自定义键盘的验证码实现&#xff0c;进入页面后直接输入验证码&#xff0c;第一个验证码输入完后可自动跳到下一个&#xff0c;拉起的键盘是自定义数字键盘&#xff0c;验证码的输入框带选中效果。 场景二&#xff1a;基于系统键盘的验证码实…

顶顶通呼叫中心中间件-一句话识别语音识别安装步骤

顶顶通呼叫中心中间件-一句话模型安装步骤&#xff0c;对接mod_vad。一句话识别&#xff08;http接口提交录音文件识别&#xff09; 一、安装一句话模型 一句话识别&#xff08;http接口提交录音文件识别&#xff09;&#xff0c;比如对接mod_vad(老电话机器人接口) curl -s…

C#中的多线程案例

使用Task写一个进度条 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.For…

【有手就行】:从无到有在win10上用docker搭建svn服务器

前言 之所以要搭建svn服务器&#xff0c;是因为在用docker打包项目时方便&#xff0c;如果没有svn就需要手动拷贝项目到容器内&#xff0c;用svn直接update就可以轻松拿到最新代码&#xff0c;岂不快哉 准备工作 1、先安装docker&#xff0c;请移步 docker安装 2、选择svn-s…

【每日力扣中医养生】力扣2608. 图中的最短环

2608. 图中的最短环 文章目录 【每日力扣&中医养生】力扣2608. 图中的最短环题目描述示例示例 1示例 2 输入输出说明解题思路Python代码复杂度分析总结 【每日力扣&中医养生】力扣2608. 图中的最短环 《黄帝内经》阴阳应象大论篇第五&#xff0c;提到“秋伤于湿&…

Leetcode 209,713,3 滑动窗口 C++实现

Leetcode 209. 长度最小的子数组 问题&#xff1a;给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c…

redis 遍渐进式历

1.scan cursor [match pattern] [coutn] [type]:以渐进式的方式进行建的遍历 cursor:是光标 指向当前遍历的位置 设置成0表示当前从0开始获取 math parttern &#xff1a;和keys命令一样的 keys * count: 限制一次遍历能够获取到多少个 元素默认是10 type :这次遍历只想获取…

数据库原理--关系模型简述

目录 一、关系模型研究什么 二、关系模型的三要素 三、关系模型与关系数据库语言的关系 一、关系模型研究什么 一个关系(relation)就是一个表(Table),关系模型就是处理Table的&#xff0c;它由三个部分组成: 描述DB各种数据的基本结构(Table/Relation)描述Table与Table之间…

Docker安装Redis集群记录

redis集群整体的安装效果 备注&#xff1a;本机docker容器的宿主机ip为192.168.0.200&#xff0c;下面的配置全部基于当前IP进行配置&#xff1b; 1 docker镜像下载使用的国内地址 vi /etc/docker/daemon.json{"registry-mirrors": ["https://ustc-edu-cn.mir…

苹果手机怎么还原删除的照片?4个【独门秘籍】都在这里了

苹果手机的拍照功能深受广大用户的喜爱&#xff0c;大家出行旅游也大都选择苹果手机拍照记录&#xff0c;因此手机相册也就成为用户们的【生活回忆录】。但是&#xff0c;我们总是会因为各种各样的原因导致相册里的照片消失不见&#xff0c;对此&#xff0c;我们要怎么还原删除…

《计算机组成原理》(第3版)课后习题答案

第1篇 概 论 1&#xff0e;什么是计算机系统、计算机硬件和计算机软件&#xff1f;硬件和软件哪个更重要&#xff1f; 答&#xff1a;计算机系统&#xff1a;由计算机硬件和软件两部分组成&#xff0c;计算机系统具有接收和存储信息、按程序快速计算和判断并输出处理结果等功…

武汉流星汇聚:亚马逊迎来中国力量,中国卖家推动跨境电商繁荣

随着全球化进程的加速和跨境电商的蓬勃发展&#xff0c;中国卖家正以前所未有的速度和规模涌入亚马逊这一全球领先的电商平台。他们的入驻不仅为亚马逊平台注入了新的活力与多样性&#xff0c;更在全球范围内产生了深远的积极影响与变革。 中国作为世界工厂&#xff0c;拥有庞…

一段式端到端vs两段式端到端,到底哪个好

在智能汽车领域&#xff0c;端到端自动驾驶技术正迅速成为行业焦点&#xff0c;不同的玩家实现路径也有差别。目前主流的端到端智驾方案有两类&#xff1a;一段式和两段式&#xff0c;针对这两种方案优缺点的讨论&#xff0c;也从未停止过。 “两段式”端到端和“一段式”端到端…

遥感之地理农业分区

在前面的文章有介绍关于中国区域进行分区研究的思路&#xff1a; 中国生态地理区划更新和优化 全国一米全要素分类数据集如何得到的&#xff1f;原文赏析&#xff01; 根据不同的研究角度对中国区域进行分区&#xff0c;其结果只是细节不一样&#xff0c;大部分还是差不多的&a…

基于Django框架的图书管理系统,前台采用Bootstrap框架UI,后台EasyUI框架UI

程序开发软件&#xff1a;Pycharm 数据库&#xff1a;mysql 采用技术&#xff1a; Django(一个MVT框架&#xff0c;类似Java的SSM框架) 人生苦短&#xff0c;我用Python&#xff0c;咱们今天就来分享一个用Python语言开发的基于Django框架的图书管理系统吧。项目前台和后台界…