news 2026/6/25 12:55:10

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/6/22 20:44:49

解锁跨平台文本编辑新体验:Notepad--全方位解决方案

解锁跨平台文本编辑新体验:Notepad--全方位解决方案 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no/notepad-- 你是否…

作者头像 李华
网站建设 2026/6/19 18:38:28

AMD显卡运行CUDA应用完全指南:从配置到性能优化全攻略

AMD显卡运行CUDA应用完全指南:从配置到性能优化全攻略 【免费下载链接】ZLUDA CUDA on AMD GPUs 项目地址: https://gitcode.com/gh_mirrors/zlu/ZLUDA 你是否拥有AMD显卡却想运行专为NVIDIA设计的CUDA应用?ZLUDA项目正是解决这一痛点的开源工具&…

作者头像 李华
网站建设 2026/6/18 21:38:36

技术探索:如何用ATX-Agent破解Android自动化测试的3大难题

技术探索:如何用ATX-Agent破解Android自动化测试的3大难题 【免费下载链接】atx-agent HTTP Server runs on android devices 项目地址: https://gitcode.com/gh_mirrors/at/atx-agent 一、价值定位:重新定义Android自动化测试的底层逻辑 在移动…

作者头像 李华
网站建设 2026/6/19 15:48:02

Qwen3-VL最佳实践:生产环境中稳定性保障部署策略分享

Qwen3-VL最佳实践:生产环境中稳定性保障部署策略分享 1. 为什么Qwen3-VL值得在生产环境落地? Qwen3-VL不是又一个“参数堆砌”的多模态模型,而是真正面向工程闭环的视觉语言系统。它把“能看、能懂、能操作、能交付”四个环节串成了一条可信…

作者头像 李华
网站建设 2026/6/16 12:42:54

ChatGLM-6B开源价值再挖掘:支持LoRA微调+私有领域知识注入教程

ChatGLM-6B开源价值再挖掘:支持LoRA微调私有领域知识注入教程 1. 为什么说ChatGLM-6B不只是“能用”,而是“值得深挖” 很多人第一次接触ChatGLM-6B,是在CSDN镜像广场点开那个标着“开箱即用”的智能对话服务。输入一句“你好”&#xff0c…

作者头像 李华
网站建设 2026/6/15 20:41:58

小白友好!5分钟跑通Qwen3-Embedding-0.6B调用流程

小白友好!5分钟跑通Qwen3-Embedding-0.6B调用流程 你是不是也遇到过这些情况: 想给自己的知识库加个语义搜索,却卡在嵌入模型部署上? 看到“embedding”“向量”“MTEB榜单”就头大,不知道从哪下手? 试了三…

作者头像 李华