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 段则用来存储系统给每一个可

执行程序自动添加的"初始化"代码,这部分代码功能包括环境变量的准备、命令行参数的

组织和传递等,并且这部分数据被放置在了栈底。

相关推荐
破茧蝴蝶7 小时前
Python分布式爬虫完整教程
开发语言·python
狗凯之家源码网7 小时前
全新 PHP 轻量客服聊天室源码深度评测
开发语言·php·聊天室系统
远离UE47 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience8 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
栈帧之外8 小时前
【C++】STL之set
开发语言·c++
catchadmin9 小时前
免费可商用 PHP 管理后台 CatchAdmin V5.4.1 发布,新增 MCP 支持
开发语言·php
jimy110 小时前
c++的 Type Traits (二、更详细版本)
开发语言·c++
狗凯之家源码网11 小时前
纯 PHP+MySQL 应用市场系统源码实测!
开发语言·mysql·php
dishugj11 小时前
系统架构风险点、敏感点和权衡点的概念和区分
java·开发语言
Zwawa11 小时前
先把轮子转稳,才不会烧心:编码器速度环 PID 怎么接回 PWM
c语言·单片机·嵌入式