摘要:目录 15.1 OOP:概述 15.2 定义基类和派生类 15.3:虚函数 15.4:抽象基类 15.5:访问控制与继承 15.6:继承中的类作用域 15.1 OOP:概述 面向对象程序设计的核心思想是: 数据抽象,通过使用数据抽象,我们可以将类的接口与实现分离; 继承,使用继承,可以定义相似的类型
阅读全文
摘要:头文件:#include <stdio.h>,函数setbuf()用于将指定缓冲区与特定的文件流相关联,实现操作缓冲区时直接操作文件流的功能。其原型如下: void setbuf(FILE * stream, char * buf); 【参数】: stream为文件流指针, buf为缓冲区的起始地址
阅读全文
摘要:头文件:#include <stdio.h>,函数setvbuf()用来设定文件流的缓冲区,其原型为: int setvbuf(FILE * stream, char * buf, int type, unsigned size); 参数: stream为文件流指针, buf为缓冲区首地址, typ
阅读全文
摘要:我们平时所见的文件,例如 txt、doc、mp4 等,文 件内容是按照从头到尾的顺序依次存储在磁盘上的,就像排起一条长长的队伍,称为顺序文件。 除了顺序文件,还有索引文件、散列文件等,一般用于特殊领域,例如数据库、高效文件系统等。 顺序文件的存储结构决定了它能够高效读取内容,但不能够随意插入、删除和
阅读全文
摘要:实际开发中,有时候需要先获取文件大小再进行下一步操作。C语言没有提供获取文件大小的函数,要想实现该功能,必须自己编写函数。 ftell()函数 ftell() 函数用来获取文件内部指针(位置指针)距离文件开头的字节数,它的原型为: long int ftell ( FILE * fp ); 先使用
阅读全文
摘要:在C语言中,用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。 定义文件指针的一般形式为: FILE *fp; 这里的FILE,实际上是在stdio.h中定义的一个结构体,该结构体中含有文件名、文件状态和文件当前位置等信息,fopen 返回的就是FILE类
阅读全文
摘要:文件的复制是常用的功能,要求写一段代码,让用户输入要复制的文件以及新建的文件,然后对文件进行复制。能够复制的文件包括文本文件和二进制文件,你可以复制1G的电影,也可以复制1Byte的txt文档。 实现文件复制的主要思路是: 开辟一个缓冲区, 不断从原文件中读取内容到缓冲区, 每读取完一次就将缓冲区中
阅读全文
摘要:前面介绍的文件读写函数都是顺序读写,即读写文件只能从头开始,依次读写各个数据。 但在实际开发中经常需要读写文件的中间部分,要解决这个问题,就得先移动文件内部的位置指针,再进行读写。这种读写方式称为随机读写,也就是说从文件的任意位置开始读写。 实现随机读写的关键是要按要求移动位置指针,这称为文件的定位
阅读全文
摘要:fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似,都是格式化读写函数,两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器,而是磁盘文件。 这两个函数的原型为: int fscanf ( FILE *fp, c
阅读全文
摘要:头文件:#include <stdio.h>,rewind()函数用于, 将文件内部的位置指针重新指向文件的开头, 同时清除和文件流相关的错误和eof标记, 相当于调用fseek(stream, 0, SEEK_SET), 其原型如下: void rewind(FILE * stream); 【参数
阅读全文
摘要:fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread 函数;相应地写入函数为 fwrite。 fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串
阅读全文
摘要:数据类型转换就是将数据(变量、数值、表达式的结果等)从一种类型转换为另一种类型。 自动类型转换 自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。 1) 将一种类型的数据赋值给另外一种类型的变量时就会发生自动类型转换,例如: float f = 1
阅读全文
摘要:C语言是 70 年代的产物,那个时候只有 ASCII,各个国家的字符编码都还未成熟,所以C语言不可能从底层支持 GB2312、GBK、Big5、Shift-JIS 等国家编码,也不可能支持 Unicode 字符集。 稍微有点C语言基本功的读者可能认为C语言使用 ASCII 编码,字符在存储时会转换成
阅读全文
摘要:大部分C语言教材对中文字符的处理讳莫如深,甚至只字不提,导致很多初学者认为C语言只能处理英文,而不支持中文。其实C语言是一门全球化的编程语言,它支持世界上任何一个国家的语言文化,包括中文、日语、韩语等。 中文字符的存储 正确地存储中文字符需要解决两个问题。 1) 足够长的数据类型, char 只能处
阅读全文
摘要:前面我们多次提到了字符串,字符串是多个字符的集合,它们由" "包围,例如"http://www.baidu.com"、"岳麓书院"。字符串中的字符在内存中按照次序、紧挨着排列,整个字符串占用一块连续的内存。 当然,字符串也可以只包含一个字符,例如"A"、"6";不过为了操作方便,我们一般使用专门的字
阅读全文
摘要:小数分为整数部分和小数部分,它们由点号.分隔,例如 0.0、75.0、4.023、0.27、-937.198 、-0.27 等都是合法的小数,这是最常见的小数形式,我们将它称为十进制形式。 此外,小数也可以采用指数形式,例如 7.25×102、0.0368×105、100.22×10-2、-27.3
阅读全文
摘要:fgetc() 和 fputc() 函数每次只能读写一个字符,(个人:一个字节,也就是一个char大小的数据),速度较慢;实际开发中往往是每次读写一个字符串或者一个数据块,这样能明显提高效率。 读字符串函数fgets fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中,它的原型
阅读全文
摘要:在C语言中,读写文件比较灵活, 既可以每次读写一个字符, 也可以读写一个字符串, 甚至是任意字节的数据(数据块)。 本节介绍以字符形式读写文件。 以字符形式读写文件时,每次可以从文件中读取一个字符,或者向文件中写入一个字符。主要使用两个函数:fgetc()和fputc()。 字符读取函数 fgetc
阅读全文
摘要:在学习C语言fopen()函数后,知道它的第二个参数是读取方式字符串。如果字符串中出现'b',则表明是以二进制(binary)方式读取,否则是以文本方式读取。 文本文件和二进制文件的本质区别 文件可以分为两类:二进制文件和字符(文本)文件。 从物理上讲,二进制文件和字符文件没有区别,都是以二进制的形
阅读全文
摘要:在C语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。 打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。 在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。 标准输入文件 stdin(表示键
阅读全文
摘要:我们对文件的概念已经非常熟悉了,比如常见的 Word 文档、txt 文件、源文件等。文件是数据源的一种,最主要的作用是保存数据。 在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。例如, 通常把显示器称为标准输出文件,
阅读全文
摘要:C语言具有操作文件的能力,比如, 打开文件、 读取和追加数据、插入和删除数据、 关闭文件、 删除文件等。 与其他编程语言相比,C语言文件操作的接口相当简单和易学。在C语言中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。 本章内
阅读全文
摘要:在实际编程中,我们经常需要生成随机数,例如, 贪吃蛇游戏中在随机的位置出现食物, 扑克牌游戏中随机发牌。 在C语言中,我们一般使用 <stdlib.h> 头文件中的 rand() 函数来生成随机数,它的用法为: int rand (void); C语言中还有一个 random() 函数可以获取随机数
阅读全文
摘要:我们知道,在程序运行时不会更改的值可以作为常数存储。但是,有时这种做法并不是很理想。例如,假设以下语句出现在计算有关贷款数据的银行程序中: amount = balance * 0.069; 在这个程序中,出现了两个潜在的问题。首先,除原始程序员以外的任何人都不清楚这个 0.069 是什么东西。它看
阅读全文
摘要:所谓键盘监听,就是用户按下某个键时系统做出相应的处理,本章讲到的输入输出函数也是键盘监听函数的一种,例如 getchar()、_getche()、_getch() 等。 下面的代码演示了 _getch() 函数的使用: #include <stdio.h> #include <conio.h> in
阅读全文
摘要:一个安全的程序在用户输入密码时不应该显示密码本身,而应该回显星号或者点号,例如······或******,这在网页、PC软件、ATM机、POS机上经常看到。但是C语言没有提供类似的功能,控制台上只能原样显示用户输入的字符。 我们完全可以模拟密码输入的效果,请先看下面的代码: #include <st
阅读全文
摘要:在前面几节中,我们演示了如何使用 scanf() 来读取各种各样的数据,汇总了 scanf() 可以使用的格式控制符,然后还讲解了缓冲区,从根本上消除了 scanf() 的那些奇怪行为,至此,很多初学者就认为自己已经完全掌握了 scanf()。其实,这只是 scanf() 的基本用法,每个C语言程序
阅读全文
摘要:缓冲区的优点很明显, 它加快了程序的运行速度, 减少了硬件的读写次数, 让整个计算机变得流畅起来; 但是,缓冲区也带来了一些负面影响,经过前面几节的学习相信读者也见识到了。 那么,该如何消除这些负面影响呢?思路其实也很简单,在输入输出之前清空(刷新)缓冲区即可: 对于输出操作,清空缓冲区会使得缓冲区
阅读全文
摘要:上节讲到,scanf() 是从标准输入设备(键盘)读取数据,带有行缓冲区的,这让 scanf() 具有了一些独特的“性格”,例如, 可以连续输入、可以输入多余的数据等。 反过来,scanf() 也出现了一些奇怪的行为,例如,有时候两份数据之间有空格会读取失败,而有时候两份数据之间又必须有空格。 sc
阅读全文
摘要:缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分。也就是说,计算机在内存中预留了一定的存储空间,用来暂时保存输入或输出的数据,这部分预留的空间就叫做缓冲区(缓存)。 有时候,从键盘输入的内容,或者将要输出到显示器上的内容,会暂时进入缓冲区,待时机成熟,再一股脑将缓冲区中的所有内容“
阅读全文
摘要:C语言有多个函数可以从键盘获得用户输入,它们分别是: scanf():和 printf() 类似,scanf() 可以输入多种类型的数据。 getchar()、getche()、getch():这三个函数都用于输入单个字符。 gets():获取一行数据,并作为字符串处理。 scanf() 是最灵活、
阅读全文
摘要:程序是人机交互的媒介,有输出必然也有输入,第三章我们讲解了如何将数据输出到显示器上,本章我们开始讲解如何从键盘输入数据。 在C语言中,有多个函数可以从键盘获得用户输入: scanf():和 printf() 类似,scanf() 可以输入多种类型的数据。 getchar()、getche()、get
阅读全文
摘要:初学编程的读者,肯定很想编写出一个游戏来秀一下,贪吃蛇就是C语言小游戏中经典的一个,本教程的目标也是带着大家做出这款游戏,你可以猛击《C语言贪吃蛇游戏演示和说明》了解更多。 编写游戏的第一步就是搞定光标定位问题,这样你的程序就可以随心所欲、按任意顺序、在任意位置输出了。但是,C语言本身并不支持该功能
阅读全文
摘要:在C语言中,有三个函数可以用来在显示器上输出数据,它们分别是: puts():只能输出字符串,并且输出结束后会自动换行, putchar():只能输出单个字符, printf():可以输出各种类型的数据, printf() 是最灵活、最复杂、最常用的输出函数,完全可以替代 puts() 和 putc
阅读全文
摘要:当我们提到输入时,这意味着要向程序填充一些数据。输入可以是以文件的形式或从命令行中进行。C 语言提供了一系列内置的函数来读取给定的输入,并根据需要填充到程序中。 当我们提到输出时,这意味着要在屏幕上、打印机上或任意文件中显示一些数据。C 语言提供了一系列内置的函数来输出数据到计算机屏幕上和保存数据到
阅读全文
摘要:C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类
阅读全文
摘要:在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据。结构体的定义形式为: struct 结构体名{ 结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。请看下面的一个例子
阅读全文
摘要:本章我们来补充一下前面没有讲到的C语言知识。 这些知识虽然很重要,但是比较零散,不能单独构成一章,也没法划分到其它章节,所以才把这些重要知识汇总在本章集中讲解。 C语言typedef详解 C语言const的用法详解 C语言rand和srand用法详解
阅读全文
摘要:预处理指令是以#号开头的代码行,# 号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字,在关键字和 # 号之间允许存在任意个数的空白字符,整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。 下面是本章涉及到的部分预处理指令: 指令说明 # 空指令,无任何效果
阅读全文
摘要:#error 指令用于在编译期间产生错误信息,并阻止程序的编译,其形式如下: #error error_message 例如,我们的程序针对Linux编写,不保证兼容Windows,那么可以这样做: #ifdef WIN32 #error This programme cannot compile
阅读全文
摘要:假如现在要开发一个C语言程序,让它输出红色的文字,并且要求跨平台,在 Windows 和 Linux 下都能运行,怎么办呢? 这个程序的难点在于,不同平台下控制文字颜色的代码不一样,我们必须要能够识别出不同的平台。 Windows 有专有的宏_WIN32,Linux 有专有的宏__linux__,以
阅读全文
摘要:顾名思义,预定义宏就是已经预先定义好的宏,我们可以直接使用,无需再重新定义。 ANSI C 规定了以下几个预定义宏,它们在各个编译器下都可以使用: __LINE__:当前调用__LINE__这个宏时,处于当前源文件中的第几行; __FILE__:表示当前源文件的名称; __DATE__:表示当前的编
阅读全文
摘要:在宏定义中,有时还会用到#和##两个符号,它们能够对宏参数进行操作。 #用来将宏参数转换为字符串,也就是在宏参数的开头和末尾添加引号。例如有如下宏定义: #define STR(s) #s 那么: printf("%s", STR(www.baidu.com)); printf("%s", STR(
阅读全文
摘要:带参数的宏和函数很相似,但有本质上的区别: 宏展开仅仅是字符串的替换,不会对表达式进行计算;宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存。 而函数是一段可以重复使用的代码,会被编译,会给它分配内存,每次调用函数,就是执行这块内存中的代码。 【示例①】用函数计算平方值。 #includ
阅读全文
摘要:C语言允许宏带有参数。在宏定义中的参数称为“形式参数”,在宏调用中的参数称为“实际参数”,这点和函数有些类似。 对带参数的宏,在展开过程中不仅要进行字符串替换,还要用实参去替换形参。(个人:也就是要进行两个替换,一个是用实参去替换形参,另一个进行宏展开) 带参宏定义的一般形式为: #define 宏
阅读全文
摘要:宏(Macro)是预处理命令的一种,先看一个例子: #include <stdio.h> #define N 100 int main(){ int sum = 20 + N; printf("%d\n", sum); return 0; } 运行结果:120 该示例中的语句int sum = 20
阅读全文
摘要:#include叫做文件包含命令,用来引入对应的头文件(.h文件)。#include 也是C语言预处理命令的一种。 #include 的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。 #include 的用法有两种,如下所
阅读全文
摘要:前面各章中,已经多次使用过#include命令。使用库函数之前,应该用#include引入对应的头文件。这种以#号开头的命令称为预处理命令。 C语言源文件要经过编译、链接才能生成可执行程序: 编译(Compile)会将源文件(.c文件)转换为目标文件。 对于 VC/VS,目标文件后缀为.obj; 对
阅读全文
摘要:C语言预处理命令是什么? C语言#include的用法详解(文件包含命令) C语言宏定义 C语言带参数宏定义 C语言带参宏定义和函数的区别 C语言宏参数的字符串化和宏参数的连接 C语言中几个预定义宏 C语言条件编译详解 C语言#error命令,阻止程序编译 C语言预处理指令总结
阅读全文
摘要:学习完C语言的基本课程,很多老师都会布置一个大作业,让同学们编写出学生信息管理系统。学生信息管理系统可以用来管理班级学生,对学生信息(包括姓名、性别、年龄、成绩等)进行增加、删除、更改、查询等操作。 该系统主要有两种实现方案: 第一种将学生信息直接保存在二进制文件中,当需要查询或者更新时,要能够使用
阅读全文
摘要:我们知道,全局变量和函数的作用域默认是整个程序,也就是所有的源文件,这给程序的模块化开发带来了很大方便,让我们能够在模块 A 中调用模块 B 中定义的变量和函数,而不用把所有的代码都集中到一个模块。 但这有时候也会引发命名冲突的问题,例如在 a.c 中定义了一个变量 n,在 b.c 中又定义了一次,
阅读全文
摘要:头文件包含命令#include的效果与直接复制粘贴头文件内容的效果是一样的,预处理器实际上也是这样做的,它会读取头文件的内容,然后输出到 #include 命令所在的位置。 头文件包含是一个递归(循环)的过程,如果被包含的头文件中还包含了其他的头文件,预处理器会继续将它们也包含进来;这个过程会一直持
阅读全文
摘要:我们常说, 引入编译器自带的头文件(包括标准头文件)用尖括号, 引入程序自定义的头文件用双引号, 例如: #include <stdio.h> //引入标准头文件 #include "myFile.h" //引入自定义的头文件 使用尖括号< >,编译器会到系统路径下查找头文件; 而使用双引号" ",
阅读全文
摘要:源文件通过编译可以生成目标文件(例如 GCC 下的 .o 和 Visual Studio 下的 .obj),并提供一个头文件向外暴露接口,除了保护版权,还可以将散乱的文件打包,便于发布和使用。 实际上我们一般不直接向用户提供目标文件,而是将多个相关的目标文件打包成一个静态链接库(Static Lin
阅读全文
摘要:前面我们在演示多文件编程时创建了 main.c 和 module.c 两个源文件,并在 module.c 中定义了一个函数和一个全局变量,然后在 main.c 中进行了声明。 不过实际开发中很少这样做, 一般是将函数和变量的声明放到头文件, 再在当前源文件中 #include 进来。 如果变量的值是
阅读全文
摘要:所谓引用(Reference),是指对符号的使用。在下面的代码中: int a = 100, b = 200, c; c = a + b; 第一行是符号定义,第二行是符号引用。 目前我们所看到的符号引用,在所有目标文件被链接成可执行文件时,它们的地址都要被找到,如果没有符号定义,链接器就会报符号未定
阅读全文
摘要:我们在编写代码的过程中经常会遇到一种叫做符号重复定义(Multiple Definition)的错误,这是因为在多个源文件中定义了名字相同的全局变量,并且都将它们初始化了。 例如,在 a.c 中定义了全局变量 global: int global = 10; 在 b.c 中又对 global 进行了
阅读全文
摘要:链接(Linking)就是通过符号将各个模块组合成一个独立的程序的过程。 链接的主要内容就是把各个模块之间的相互引用部分处理好,使得各个模块能够正确地衔接。 链接器所做的主要工作跟前面提到的“人工调整地址”本质上没有什么两样,只不过现代的高级语言拥有诸多的特性,使得编译器和链接器更为复杂,功能更为强
阅读全文
摘要:几十年以前,计算机刚刚诞生,人们编写程序时,将所有的代码都写在同一个源文件中,经过长期的积累,程序包含了数百万行的代码,以至于人们无法维护这个程序了。于是人们开始寻找新的方法,迫切地希望将程序源代码分散到多个文件中,一个文件一个模块,以便更好地阅读和维护,这个时候,链接器就粉墨登场了。 一切都是地址
阅读全文
摘要:编译器编译源代码(由于汇编比较简单,这里汇编包含在编译中)后生成的文件叫做目标文件(Object File),例如 Visual Studio 下的.obj,或者 GCC 下的.o。 从文件结构上来讲,目标文件已经是二进制文件,它与可执行文件的组织形式非常类似,只是有些变量和函数的地址还未确定,程序
阅读全文
摘要:对于平常应用程序的开发,很少有人会关注编译和链接的过程,因为我们使用的工具一般都是流行的集成开发环境(IDE),比如 Visual Studio、Dev C++、C-Free 等。这些功能强大的 IDE 通常将编译和链接合并到一起,也就是构建(Build)或运行(Run)。即使在 Linux 下使用
阅读全文
摘要:在前面的教程中,我们都是将所有的代码写到一个源文件里面,对于小程序,代码不过几百行,这或许无可厚非,但当程序膨胀代码到几千行甚至上万行后,就应该考虑将代码分散到多个文件中,否则代码的阅读和维护将成为一件痛苦的事情。 本节我们就来演示一下多文件编程。在下面的例子中,我们创建了两个源文件 main.c
阅读全文
摘要:我们知道,变量是有数据类型的,用以说明它占用多大的内存空间,可以进行什么样的操作。 除了数据类型,变量还有一个属性,称为“存储类别”。存储类别就是变量在内存中的存放区域。在进程的地址空间中,常量区、全局数据区和栈区可以用来存放变量的值。 常量区和全局数据区的内存在程序启动时就已经由操作系统分配好,占
阅读全文
摘要:使用 malloc()、calloc()、realloc() 动态分配的内存,如果没有指针指向它,就无法进行任何操作,这段内存会一直被程序占用,直到程序运行结束由操作系统回收。 请看下面的代码: #include <stdio.h> #include <stdlib.h> int main(){ c
阅读全文
摘要:如果一个指针指向的内存没有访问权限, 或者指向一块已经释放掉的内存, 那么就无法对该指针进行操作,这样的指针称为野指针(Wild Pointer)。 指向没有访问权限的内存 请看下面的代码: #include <stdio.h> int main(){ char *str; gets(str); p
阅读全文
摘要:相对于栈而言,堆这片内存面临着一个稍微复杂的行为模式:在任意时刻,程序可能发出请求,要么申请一段内存,要么释放一段已经申请过的内存,而且申请的大小从几个字节到几个GB都有可能,我们不能假设程序一次申请多少堆空间,因此,堆的管理显得较为复杂。 那么,使用 malloc() 在堆上分配内存到底是如何实现
阅读全文
摘要:在进程的地址空间中,代码区、常量区、全局数据区的内存在程序启动时就已经分配好了,它们大小固定,不能由程序员分配和释放,只能等到程序运行结束由操作系统回收。这称为静态内存分配。 栈区和堆区的内存在程序运行期间可以根据实际需求来分配和释放,不用在程序刚启动时就备足所有内存。这称为动态内存分配。 使用静态
阅读全文
摘要:我们先来看下面的一个例子: #include <stdio.h> int main(){ char str[10] = {0}; gets(str); printf("str: %s\n", str); return 0; } 在 main() 函数内部定义一个字符数组,并通过 gets() 为它赋
阅读全文
摘要:前面我们只是讲解了一个函数的活动记录是什么样子的,相信大家对函数的详细调用过程的认识还不是太清晰,这节我们就以 VS2010 Debug 模式为例来深入分析一下。 请看下面的代码: void func(int a, int b){ int p =12, q = 345; } int main(){
阅读全文
摘要:我们知道,一个C程序由若干个函数组成,C程序的执行实际上就是函数之间的相互调用。请看下面的代码: #include <stdio.h> void funcA(int m, int n){ printf("funcA被调用\n"); } void funcB(float a, float b){ fu
阅读全文
摘要:函数的调用和栈是分不开的,没有栈就没有函数调用,本节就来讲解函数在栈上是如何被调用的。 栈帧/活动记录 当发生函数调用时,会将函数运行需要的信息全部压入栈中,这常常被称为栈帧(Stack Frame)或活动记录(Activate Record)。活动记录一般包括以下几个方面的内容: 1) 函数的返回
阅读全文
摘要:在《C语言程序的内存布局(内存模型)》中我们讲到,程序的虚拟地址空间分为多个区域,栈(Stack)是其中地址较高的一个区域。栈(Stack)可以存放函数参数、局部变量、局部数组等作用范围在函数内部的数据,它的用途就是完成函数的调用。 栈内存由系统自动分配和释放:发生函数调用时就为函数运行时用到的数据
阅读全文