news 2026/4/25 15:00:40

c语言更进一步

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
c语言更进一步

递归函数的代码的特点是短小精悍,但是递归函数也有致命的弱点:效率低且容易
使得栈溢出。8M

回调函数用到的最基本的语法是函数指针

实现了典型的回调机制,你定制了一位做任何菜都死命放辣椒
的大厨,然后你在调用前台小妹的同时,将大厨的电话号码也给到她,小妹在需要做饭的时
候,就会根据你提供的参数(大厨的电话)回过去调用(回调!)那位大厨,做好饭后小妹
再细心地捯饬捯饬,端给你吃。

大厨就是一个回调函数——一个不被设计者(你)直接调用,而
是被其他人(小妹)回过来调用的函数。你传递给小妹的电话号码,相当于一个能找到大厨
的指针,被称之为函数指针,回调机制就是靠传递函数指针来告知回调函数的位置的。

9 // 定义一个回调函数,以后内核需要信号响应函数的时候会调用该函数 10 void sighandler(int sig) 11 { 12 printf("sig : %d\n", sig); 13 } 14 15 int main(void) 16 { 17 // 传递函数指针,预先告知内核回调函数 sighandler 的位置 18 signal(SIGINT, sighandler); 19 20 // 将信号 SIGINT 传递给内核,要求内核开始处理信号 SIGINT 21 pid_t myPID = getpid( ); 22 kill(myPID, SIGINT); 23 24 return 0; 25 }

内存这栋大楼的房间数多得惊人!他们的编号从 0x00000000 开始,到 0xFFFFFFFF,
总计达 2的32次方个房间!每一个房间(字节/byte)包含 8 个比特/bit,每个比特可以存放一个
1 或者 0,一图顶万言,附上一张内存的性感照片:

显示的是一个占据了 4 个字节的 int 型数据(值为 0x00000007),每一个字节都有其对应的地址,编译器会将最小的地址 0x0A33FF04 作为整个 int 型数据的地址,这个最小的地址就是所谓的基地址。以后当我们提到一个变量的地址的时候,指的都是基地址。

在 32 位系统中,任何地址都是 4 字节的。

但有些时候,我们也许无法在定义指针的同时,立即给他一个有效的地址,而是在程序
运行到下一个恰当的某个时候再赋值,这期间就有个空档期,此空档期内指针 p 的值将是
一个随机值,而这个随机值是一个地址,如果在此种状况下不小心对指针 p 进行了解引用,
程序就会访问非法内存,导致本程序崩溃甚至更严重的后果,这样的未初始化的指针我们称
之为野指针:

一般而言,对于一个暂时无法让其指向一块合法内存的指针而言,我们最好将其初
始化为“空指针”,即给他赋一个空值(零),让他指向零地址:

NULL 实际上这是一个宏:#define NULL (void *)0,从值上看,NULL 就是地
址 0x0000 0000,从类型上看,空指针是一种通用型指针,关于 void 型指针,有以
下总结:
1,当无法确定一个地址所对应的内存的数据类型时,将该地址类型定为 void 型,
即通用型。比如:
void *p = malloc(8); // 申请了一块未知用途的内存(8 个字节)
2,void 型指针在解引用时,必须转化为某种具体的数据类型指针,否则无法解引
用。比如:
double f = 3.14;
*p = f; // 这是错误的,因为指针 p 是通用类型指针
*(double *)p = f; // 这是正确的,因为进行了相应的类型转化

const 在 C 语言中的主要用法不是用来定义普通变量,而是用来定义指针

内存管理

第一,栈内存。
栈内存(以下简称栈)指的是从 0xC000 0000 往下增长的这部分内存区域,之所以
被称为“栈”是因为进程在使用这块内存的时候是严格按照“后进先出”的原则来操作的,
而这种后进先出的逻辑,就被称为栈。
栈的全称是“运行时栈(run-time stack)”,顾名思义栈会随着进程的运行而不断
发生变化:一旦有新的函数被调用,就会立即在栈顶分配一帧内存,专门用于存放该函数内
定义的局部变量(包括所有的形参),当一个函数执行完毕返回之后,他所占用的那帧内存
将被立即释放),在上图中用一根虚线和箭头来表示栈
的这种动态特征。
栈主要就是用来存储进程执行过程中所产生的局部变量的,当然为了可以实现函数的嵌
套调用和返回,栈还必须包含函数切换时当下的代码地址和相关寄存器的值,这个过程被称
为“保存现场”,等被调函数执行结束之后,再“恢复现场”。因此,如果进程嵌套调用了
很多函数,就会导致栈不断增长,但是栈的大小又是有一个最大限度的,这个限度一般是
8MB,超过了这个最大值将会产生所谓的“栈溢出”导致程序崩溃,所以我们在进程中不
宜嵌套调用太深的函数,也不要定义太多太大的局部变量。
第二,堆内存。
堆内存(以下简称堆)是一块自由内存,原因是在这个区域定义和释放变量完全由你来
决定,即所谓的自由区。堆跟栈的最大区别在于堆是不设大小限制的,最大值取决于系统的
物理内存。
堆的全称是“运行时堆(run-time heap)”,跟栈一样,会随着进程的运行而不断
地增大或缩小,由于对堆的操作非常重要,下一小节用来专门讨论堆的相关细节。
第三,数据段。
数据段实际上分为三部分,地址从高到底分别是.bss 段、.data 段和.rodata 段,三个
数据段各司其职:.bss 专门用来存放未初始化的静态数据,它们都将被初始化为 0,.data
段专门存放已经初始化的静态数据,这么初始值从程序文件中拷贝而来,而.rodata 段用来
存放只读数据,即常量,比如进程中所有的字符串、字符常量、整型浮点型常量等。
第四,代码段。
代码段实际上也至少分为两部分:.text 段和.init 段。.text 段用来存放用户程序代码,
也就是包括 main 函数在内的所有用户自定义函数,而.init 段则用来存储系统给每一个可
执行程序自动添加的“初始化”代码,这部分代码功能包括环境变量的准备、命令行参数的
组织和传递等,并且这部分数据被放置在了栈底。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:32:29

KiCad + STM32电源管理电路设计:完整示例解析

以下是对您提供的博文内容进行 深度润色与专业重构后的版本 。我以一位深耕嵌入式硬件设计十年、长期使用 KiCad 进行量产项目开发的工程师视角,重写了全文—— 去模板化、去AI腔、强逻辑、重实战、有温度、带思考痕迹 。全文严格遵循您的所有格式与风格要求&am…

作者头像 李华
网站建设 2026/4/17 23:07:58

Hunyuan-MT-7B长文翻译效果展示:32K token学术论文整篇直译实例

Hunyuan-MT-7B长文翻译效果展示:32K token学术论文整篇直译实例 1. 为什么这篇论文翻译让人眼前一亮? 你有没有试过把一篇28页的英文计算机顶会论文,直接粘贴进翻译工具——结果刚翻到第三段就卡住,再刷新页面,前面译…

作者头像 李华
网站建设 2026/4/23 14:37:19

零基础玩转iOS固件降级:2025年FutureRestore-GUI实战指南

零基础玩转iOS固件降级:2025年FutureRestore-GUI实战指南 【免费下载链接】FutureRestore-GUI A modern GUI for FutureRestore, with added features to make the process easier. 项目地址: https://gitcode.com/gh_mirrors/fu/FutureRestore-GUI FutureRe…

作者头像 李华
网站建设 2026/4/17 18:36:41

Keil MDK下载与环境搭建:手把手入门必看指南

以下是对您提供的博文内容进行 深度润色与工程化重构后的技术文章 。全文已彻底去除AI生成痕迹,语言更贴近一线嵌入式工程师的真实表达风格——有经验沉淀、有踩坑总结、有代码细节、有逻辑脉络,不堆砌术语,不空谈概念,每一句话…

作者头像 李华
网站建设 2026/4/18 10:12:23

Axure RP中文配置完全指南:软件本地化与界面中文化技术方案

Axure RP中文配置完全指南:软件本地化与界面中文化技术方案 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包,不定期更新。支持 Axure 9、Axure 10。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn …

作者头像 李华