C
全部有关C语言的相关知识与问题
非主流的豆瓣
记录自己学习的知识点,困惑,以及历程;
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
9-15不带头节点的单链表的相关操作与实现
#include<stdlib.h>#include<stdio.h>#include<string.h>#define DBG(...) fprintf(stderr,"DBG(%s,%s(),%d):",__FILE__,__FUNCTION__,__LINE__); fprintf(stderr,__VA_ARGS__)//创建单链表的节点typedef struct Node{ int data; //数据域 struct No原创 2020-10-25 14:48:49 · 246 阅读 · 0 评论 -
10-3 像编译器一样思考吧
10.3.1 语法是什么?语法就是编译器的习性(1)编译器反应在编程中就是语法。你对编译器的了解程度就反应在你对语法的理解程度。语法(规则)的理解是永无止境的。就像下象棋,规则很简单,关键就在于你对规则的灵活运用。你越善于运用规则,那么你就越强。学会一门语言后,应该进行项目实践,然后在项目实践中去体会C语言的语法规则。譬如:int i; !!i;解析:!在C语言中是逻辑取反的意思,逻辑取反意思就是0取反就是1,不是0的数取反就是0.问题:让你用C语言编程实现:如果一个数i是0则返回0,如果不是原创 2020-10-23 16:56:25 · 854 阅读 · 2 评论 -
10-2 程序员、编译器、CPU之间的三角恋
10.2.1 CPU只认识二进制机器指令(1)CPU是最终干活的,而CPU只认识只接受二进制。10.2.2 人类喜欢符号而不是二进制(1)人类的大脑本身不喜欢二进制而喜欢符号、文字。(2)人类和机器之间天生有代沟,于是乎编程不容易。10.2.3 连接人(程序员)与机器(CPU)的桥梁:编译器(1)编译器降低了编程难度。编译器的代表就是编程语言,每一种编程语言都有对应的编译器,这个编译器的作用就是把这种语言的源文件编译成可执行程序。(2)关键是:有了编译器(高级语言)之后,我们程序员就不再盯着原创 2020-10-23 16:56:07 · 721 阅读 · 1 评论 -
10-1 编程工作的演进史
十、程序员和编译器之间的暧昧10.1.1 CPU需要的只是1和0组成的二进制数据(1)不管编程怎么变,最终编程得到的可执行二进制程序都是给CPU运行的。CPU需要的只是按照CPU设计时的规律(机器指令)排布的一串二进制1和0组成的数字(机器码),CPU根本不关心这些二进制是怎么来的。(2)这些二进制可能是一个很厉害的程序员直接用1和0拼出来的,也可以是用汇编语言编写最终编译得到的;也可以是用C语言编写最终编译得到的;也可以是用Java、C#、php、bash等语言编写然后解释得到的;(3)编程工作的原创 2020-10-22 13:33:48 · 179 阅读 · 0 评论 -
9-14 多线程简介
9.15.1 操作系统下的并行执行机制(1)并行就是说多个任务同时被执行。并行分微观上的并行和宏观上的并行。(2)宏观上的并行就是从长时间段(相对于人来说)来看,多个任务是同时进行的;微观上的并行就是真的在并行执行。(3)操作系统要求实现宏观上的并行。宏观上的并行有2种情况:第一种是微观上的串行,第二种是微观上的并行。(4)理论上来说,单核CPU本身只有一个核心,同时只能执行一条指令,这种CPU只能实现宏观上的并行,微观上一定是串行的。微观上的并行要求多核心CPU。多核CPU中的多个核心可以同时微观原创 2020-10-22 13:20:26 · 143 阅读 · 0 评论 -
9-13什么是状态机
9.13.1 有限状态机(1)常说的状态机是有限状态机FSM。FSM指的是有有限个状态(一般是一个状态变量的值),这个机器同时能够从外部接收信号和信息输入,机器在接收到外部输入的信号后会综合考虑当前自己的状态和用户输入的信息,然后机器做出动作:跳转到另一个状态。(2)考虑状态机的关键点:当前状态、当前输入、下一个状态;9.13.2 两种状态机:Moore型和Mealy型(1)Moore型状态机:输出只与当前状态有关(与输入信号无关)。相对简单,考虑状态机的下一个状态时只需要考虑它的当前状态就行了。原创 2020-10-22 13:20:10 · 438 阅读 · 0 评论 -
9-12 内核链表的基本算法和使用简介
9.12.1 内核链表的节点创建、删除、遍历等这个自己去看内核源代码;9.12.2 内核链表的使用实践(1)问题:内核链表只有纯链表,没有数据区域,怎么使用?(2)设计的使用方法是将内核链表作为将来整个数据结构的结构体的一个成员内嵌进去。struct driver{ char name[20]; //驱动名称 int id; //驱动id编号 struct driver_info info; //驱动信息 struct list_head head; //内嵌原创 2020-10-22 13:19:34 · 122 阅读 · 0 评论 -
9-11 Linux内核链表
9.11.1 前述链表数据区域的局限性(1)之前定义数据区域时直接int data;我们认为我们的链表中需要存储的是一个int类型的数。但是实际上现实编程中链表中的节点不可能这么简单,而是多种多样的。(2)一般实际项目中的链表,节点中存储的数据其实是一个或者多个结构体+一些基础类型变量,这个结构体中包含若干个成员,这些成员加起来构成了我们的节点数据区域。9.11.2 一般性解决思路:数据区封装为一个结构体(1)因为链表实际解决的问题是多种多样的,所以内部数据区域的结构体构成也是多种多样的。这样也导原创 2020-10-22 13:19:17 · 123 阅读 · 0 评论 -
9-10 双链表的算法之删除节点
//删除节点int delete_node(struct node *pHeader,int data){ struct node *p = pHeader; while(NULL != p->pNext) { p = p->pNext; //判断当前节点是不是我们要删除的那个节点 if(data == p->data) { //是尾节点 if(NULL == p->pNext) {原创 2020-10-22 13:18:59 · 262 阅读 · 0 评论 -
9-9 双链表的算法之遍历节点
(1)双链表是单链表的一个父集。双链表中如果完全无视pPrev指针,则双链表就变成了单链表。这就决定了双链表的正向遍历(后向遍历)和单链表是完全相同的。(2)双链表中因为多了pPrev指针,因此双链表还可以前向遍历(从链表的尾节点向前面依次遍历直到头节点)。但是前向遍历的意义并不大,主要是因为很少有当前到了尾节点需要前向遍历的情况。(3)总结:双链表是对单链表的一种有成本的扩展,但是这个扩展在有些时候意义不大,在另一些时候意义就比较大。因此在实践用途中要根据业务要求选择适合的链表。//后向遍历voi原创 2020-10-22 13:18:36 · 282 阅读 · 0 评论 -
9-8 双链表的算法之插入节点
9.8.1 尾部插入//将新节点插入到链表的尾部void insert_tail(struct node *pHeader,struct node *newNode){ //第一步先走到链表的尾节点 struct node *p = pHeader; while(NULL != p->pNext) { p = p->pNext; } //第二步:将新节点插入到原来的尾节点的后面 p->pNext = newNode; newNode->p原创 2020-10-22 13:18:12 · 307 阅读 · 0 评论 -
9-7 双链表的引入和基本实现
9.7.1 单链表的局限性(1)单链表是对数组的一个扩展,解决了数组的大小比较死板不容易扩展的问题。使用堆内存来存储数据,将数据分散到各个节点之间,其各个节点在内存中可以不相连,节点之间通过指针进行单向连接。链表中的各个节点内存不相连,有利于利用碎片化的内存。(2)单链表各个节点之间只有一个指针单向连接,这样实现有一些局限性。局限性主要体现在单链表只能经由指针单向移动(一旦指针移动过某个节点就无法再回来,如果要再次操作这个节点除非从头指针开始再次遍历一次),因此单链表的某些操作就比较麻烦(算法就比较有局原创 2020-10-22 13:17:37 · 172 阅读 · 0 评论 -
9-6 单链表的算法之逆序
9.6.1 什么是链表的逆序(1)链表的逆序又叫反向,意思就是把链表中所有的有效节点在链表中的顺序给反过来。9.6.2 单链表逆序算法分析(1)当我们对一个数据结构进行一个操作时,我们就需要一套算法。这就是数据结构和算法的关系。(2)我总结:算法有2个层次。第一个层次是数学和逻辑上的算法;第二个层次是用编程语言来实现算法。(这就启示我们要去锻炼自己的逻辑思维,要想到怎么去解决这个问题,有解决问题的思路,第二个就是锻炼我们的编程功底,能用代码去实现这个解决问题的思路)。(3)从逻辑上来讲,链表的逆序原创 2020-10-22 13:17:14 · 462 阅读 · 0 评论 -
9-5 单链表的算法之删除节点
9.5.1 为什么要删除节点(1)一直在强调,链表到底用来干嘛的?(2)有时候链表节点中的数据不想要了,因此要删掉这个节点。9.5.2 删除节点的2个步骤(1)第一步:找到要删除的节点;第二步:删除这个节点;9.5.3 如何找到待删除的节点(1)通过遍历来查找节点。从头指针+头节点开始,顺着链表依次将各个节点拿出来,按照一定的方法比对,找到我们要删除的那个节点。9.5.4 如何删除一个节点(1)待删除的节点不是尾节点的情况:首先把待删除的节点的前一个节点的pNext指针指向待删除的节点的后一原创 2020-10-21 22:08:06 · 696 阅读 · 0 评论 -
9-4 单链表的算法之遍历节点
9.4.1 什么是遍历(1)遍历就是把单链表中的各个节点挨个拿出来,就叫遍历。(2)遍历的要点:一是不能遗漏,二是不能重复,追求效率。9.4.2 如何遍历单链表(1)分析一个数据结构如何遍历,关键是分析这个数据结构本身的特点。然后根据本身特点来制定它的遍历算法。(2)单链表的特点就是由很多个节点组成,头指针+头节点为整个链表的起始,最后一个节点的特征是它内部的pNext指针值为NULL。从起始到结尾中间由各个节点内部的pNext指针来挂接,由起始到结尾的路径有且只有一条。单链表的这些特点就决定了它原创 2020-10-21 21:54:45 · 1275 阅读 · 0 评论 -
9-3 单链表的算法之插入节点
9.3.1 继续上节,访问链表中各个节点的数据(1)只能用头指针,不能用各个节点自己的指针。因为在实际当中我们保存链表的时候是不会保存各个节点的指针的,只能通过头指针来访问链表节点。(2)前一个节点内部的pNext指针能帮助我们找到下一个节点。9.3.2 将创建节点的代码封装成一个函数(1)封装时的关键点就是函数的接口(函数参数和返回值)的设计。//作用:创建一个链表节点//返回值:指针,指针指向我们本函数新创建的一个节点的首地址struct node * create_node(int da原创 2020-10-21 21:24:23 · 556 阅读 · 0 评论 -
9-2 单链表的实现
9.2.1 单链表的节点构成(1)链表是由节点组成的,节点中包含:有效数据和指针。(2)定义的struct node只是一个结构体,本身并没有变量生成,也不占用内存。结构体定义相当于为链表节点定义了一个模板,但是还没有一个节点,将来在实际创建链表时需要一个节点时用这个模板来复制一个即可。9.2.2 堆内存的申请和使用(1)链表的内存要求比较灵活,不能用栈,也不能用data数据段。只能用堆内存。(2)使用堆内存来创建一个链表节点的步骤:1、申请堆内存,大小为一个节点的大小(检查申请结果是否正确);原创 2020-10-21 21:05:59 · 354 阅读 · 0 评论 -
9-1 链表的引入
九、链表&状态机&多线程9.1.1 从数组的缺陷说起(1)数组有2个缺陷,一个是数组中所有元素的类型必须一致;第二个是数组的元素个数必须事先指定并且一旦指定之后不能更改。(2)如何解决数组的2个缺陷:数组的第一个缺陷靠结构体去解决。结构体允许其中的元素的类型不相同,因此解决了数组的第一个缺陷。所以说结构体是因为数组不能解决某些问题所以才发明的。(3)如何解决数组的第二个缺陷?我们希望数组的大小能够实时扩展。譬如我刚开始定了一个元素个数是10,后来程序运行时觉得不够因此动态扩展为20.原创 2020-10-21 21:05:28 · 148 阅读 · 0 评论 -
8-8程序调试的debug宏
8.8.1 程序调试的常见方案:单步调试、裸机LED调试、打印信息、log文件(1)利用调试器进行单步调试(譬如IDE中,Jlink)适用于新手,最大的好处就是直观,能够帮助找到问题。缺点是限制性大、速度慢。(2)裸机使用LED、蜂鸣器等硬件调试,适合单片机裸机程序;(3)printf函数打印调试,比较常用,作为程序员必须学会打印调试。好处是具有普遍性,几乎在所有的情况下都能用。(4)log文件(日志文件)是系统运行过程中在特定的时候打印一些调试信息,日志文件记录下来这些调试信息以后以供后续查找追查原创 2020-10-21 21:05:00 · 252 阅读 · 0 评论 -
8-6 运算中的临时匿名变量
8.6.1 C语言和汇编的区别(汇编完全对应机器操作,C对应逻辑操作)(1)C语言叫高级语言,汇编语言叫低级语言。(2)低级语言的意思是汇编语言和机器操作相对应,汇编语言只是CPU的机器码的助记符,用汇编语言写程序必须拥有机器的思维。因为不同的CPU设计时指令集差异很大,因此用汇编编程的差异很大。(3)高级语言(C语言)它对低级语言进行了封装(C语言的编译器来完成的),给程序员提供了一个靠近人类思维的一些语法特征,人类不用过于考虑机器原理,而可以按照自己的逻辑原理来进行编程。譬如数组、结构体、指针…原创 2020-10-21 21:04:12 · 812 阅读 · 0 评论 -
8-5C语言中的NULL
8.5.1 NULL在C/C++中的标准定义(1)NULL不是C语言关键字,本质上是一个宏定义;(2)NULL的标准定义:#ifdef _cplusplus //条件编译#define NULL 0#else#define NULL (void *)0 //这里对应C语言的情况#endif解释:C++的编译环境中,编译器预先定义了一个宏_cplusplus,程序中可以用条件编译来判断当前的编译环境是C++还是C的。NULL的本质解析:NULL的本质是0,但是这个原创 2020-10-21 21:03:44 · 412 阅读 · 0 评论 -
8-7顺序结构
8.7.1 最浅显的顺序结构:三种结构之一(1)代码执行的时候如果没有遇到判断跳转或者循环,默认是顺序执行的。执行完上一句则开始执行下一句。(2)顺序结构说明CPU的工作状态,就是以时间轴来顺序执行所有的代码语句直到停机。8.7.2 选择和循环结构内部的顺序结构(1)譬如if(){},在{}内部是if的代码段,在代码段内部还是按照顺序结构来执行的。(2)switch case内部也一样,也是按照顺序结构执行的。(3)while,for内部也是按照顺序结构来执行的。8.7.3 编译过程中的顺序结原创 2020-10-21 21:04:37 · 153 阅读 · 0 评论 -
8-4void类型的本质
8.4.1 C语言属强类型语言(1)编程语言分2种:强类型语言和弱类型语言。强类型语言中所有的变量都有自己固定的类型,这个类型有固定的内存占用,有固定的解析方法;弱类型语言中没有类型的概念,所有变量全都是一个类型(一般都是字符串的),程序在用的时候再根据需要来处理变量。(2)C语言就是典型的强类型语言,C语言中所有的变量都有明确的类型。因为C语言中的一个变量都要对应内存中的一段内存,编译器需要这个变量的类型来确定这个变量占用内存的字节数和这一段内存的解析方法。8.4.2 数据类型的本质含义(1)数据原创 2020-10-21 21:03:14 · 160 阅读 · 0 评论 -
8-3 argc、argv与main函数的传参
8.3.1 谁给main函数传参(1)调用main函数所在的程序的它的父进程给main函数传参,并且接收main的返回值。8.3.2 为什么需要给main函数传参(1)首先,main函数不传参是可以的,也就是说父进程调用子程序并且给子程序传参不是必须的。int main(void)这种形式就表示我们认为不必要给main传参。(2)有时候我们希望程序有一种灵活性,所以选择在执行程序时通过传参来控制程序中的运行,达到不需要重新编译程序就可以改变程序运行结果的效果。8.3.3 表面上:给main传参是原创 2020-10-20 22:20:32 · 234 阅读 · 0 评论 -
8-2 main函数返回给谁?
8.2.1 函数为什么需要返回值?(1)函数在设计的时候设计了参数和返回值,参数是函数的输入,返回值是函数的输出。(2)因为函数需要对外输出数据(实际上是函数运行的一些结果值),因此需要返回值。(3)形式上来说,函数被另一个函数所调用,返回值作为函数式的值返回给调用这个函数的地方。总结:函数的返回值就是给调用它的人返回一个值。8.2.2 main函数被谁调用(1)main函数是特殊的,首先这个名字是特殊的。因为C语言规定了main函数是整个程序的入口。其它的函数只有直接或间接被main函数所调用原创 2020-10-20 21:47:32 · 497 阅读 · 0 评论 -
8-1 操作系统究竟是个什么玩意?
八、一些杂散但值得讨论的问题8.1.1 像人类社会一样的计算机软件系统(有些人只埋头干活,有些人只做管理)(1)人类社会最开始时人人都干活,这时候没有专业分工,所有人都直接做产生价值的工作。当时是合适的,因为当时生产力低下,人口稀少。这就像裸机程序一样(裸机程序的特点是:代码量小,功能简单、所有代码都和直接目的有关,没有服务性代码)。(2)后来人口增加生产力提高,有一部分人脱离了直接产生价值的体力劳动专职指挥(诞生了阶级)。本质上来说是合理的,因为资源得到了更大限度的使用,优化了配置,提升了整体效率。原创 2020-10-20 21:38:08 · 252 阅读 · 0 评论 -
7-7 最后的总结
(1)普通(自动)局部变量分配在栈上,作用域为代码块作用域,生命周期是临时的,链接属性为无连接。定义时如果未显示初始化则其值随机,变量地址由运行时在栈上分配得到,多次执行时地址不一定相同,函数不能返回该类变量的地址(指针)作为返回值。(2)静态局部变量分配在数据段/bss段(显式初始化为非0则在数据段,显式初始化为0或未显式初始化则在bss段),作用域为代码块作用域(人为规定的),生命周期为永久(天然的),链接属性为无连接(天然的)。定义时如果未显式初始化则其值为0(天然的),变量地址由运行时环境在加载程原创 2020-10-20 21:29:23 · 124 阅读 · 0 评论 -
7-6 链接属性
7.6.1 C语言程序的组织架构:多个C文件+多个h文件(1)庞大、完成的一个C语言程序(譬如Linux内核、uboot)由多个C文件和多个h文件组成的。(2)程序的生成过程就是:编译 + 链接;编译是为了将函数/变量等变成.o二进制的机器码格式,链接是为了将各个独立分开的二进制的函数链接起来形成一个整体的二进制可执行程序。7.6.2 编译以文件为单位、链接以工程为单位(1)编译器工作时是将所有源文件依次读进来,单个为单位进行编译的。(2)链接的时候实际上是把第一步编译生成的单个的.o文件整体的输原创 2020-10-20 21:23:27 · 348 阅读 · 0 评论 -
7-5 变量的生命周期
7.5.1 研究变量生命周期的意义(1)研究变量的生命周期,有助于理解变量的行为特征。注意:单独来看某一个知识点是没有什么意义的,但是将很多的知识点综合起来,就有意义了。所以有了一定的基础之后去做项目是一个很好的提高的方式,通过项目去学习这其中涉及到的各种知识点,又可以了解这些知识点在项目中是如何使用的,所以做项目时,一定要多去查阅资料,多去总结归纳,对不懂的知识点拆开来一个一个认真去研究。最后综合到项目里面来综合起来学习。7.5.2 栈变量的生命周期(1)局部变量(栈变量)存储在栈上,生命周期是临原创 2020-10-20 21:14:56 · 288 阅读 · 0 评论 -
7-4 作用域详解
7.4.1 局部变量的代码作用域(1)代码块基本可以理解为一对大括号{}括起来的部分。(2)代码块不等于函数,因为if,while,for都有{}。所以代码块是 <= 函数的。(3)局部变量的作用域是代码块作用域,也就是说一个局部变量可以被访问和使用的范围仅限于定义这个局部变量的代码块中定义式之后的部分。7.4.2 函数名和全局变量的文件作用域(1)文件作用域的意思就是全局的访问权限,也就是说在整个.c文件中都可以访问这些东西。这就是平时所说的局部和全局,全局就是文件作用域。(2)详细准确原创 2020-10-20 21:08:13 · 200 阅读 · 0 评论 -
7-3 存储类相关的关键字
7.3.1 auto(1)auto关键字在C语言中只有一个作用,那就是修饰局部变量。(2)auto修饰局部变量,表示这个局部变量是自动局部变量,自动局部变量分配在栈上。(既然在栈上,说明它如果不初始化那么值就是随机的,脏的…)(3)平时定义局部变量时就是定义auto的,只是省略auto关键字而已。可见,auto的局部变量其实就是默认定义的普通的局部变量。7.3.2 static(1)static关键字在C语言中有2种用法,而且这两种用法彼此没有任何关联、完全是独立的。其实当年本应该多发明一个关键字原创 2020-10-20 20:59:53 · 231 阅读 · 0 评论 -
7-2Linux下C程序的内存映像
7.2.1 代码段&只读数据段(1)对应着程序中的代码(函数),代码段在Linux中又叫文本段(.text)(2)只读数据段就是程序运行期间只能读不能写的数据,const修饰的常量有可能是存在只读数据段的(但是不一定,const常量的实现方法在不同平台是不一样的)7.2.2 数据段&bss段(1)数据段存:1、显式初始化为非0的全局变量;2、显式初始化为非0的static局部变量(2)bss段存:1、显式初始化为0或者未显式初始化的全局变量;2、显式初始化为0或未显式初始化的sta原创 2020-10-20 20:47:29 · 265 阅读 · 0 评论 -
7-1 概念解析
七、存储类&作用域&生命周期&链接属性7.1.1 存储类(1)存储类就是存储类型,也就是描述C语言中变量在何种地方存储。(2)内存有多种管理方法:栈、堆、数据段、bss段、text段…一个变量的存储类属性就是描述这个变量存储在何种内存段中。(3)譬如:局部变量分配在栈上,所以它的存储类就是栈;显式初始化为非0的全局变量分配在数据段,显式初始化为0和没有显式初始化(默认为0)的全局变量分配在bss段。7.1.2 作用域(1)作用域是描述这个变量起作用的代码范围。(2)基本原创 2020-10-20 20:39:03 · 302 阅读 · 1 评论 -
6-10自己制作静态连接库&动态链接库并使用
6.10.1制作静态链接库并使用(1)第一步:自己制作静态链接库首先使用gcc -c只编译不链接,生成.o文件;然后使用ar工具进行打包成.a的归档文件。库名不能随便乱起,一般是lib+库名称,后缀名是.a表示是一个归档文件注意:制作出来了静态库之后,发布时需要发布.a文件和.h文件//Makefile:all: gcc pointer8.c -o pointer8.o -c ar -rc libpointer8.a pointer8.o(2)第二步:使用静态链接库把.a和.h都放在我原创 2020-10-19 22:54:13 · 184 阅读 · 0 评论 -
6-9数学库函数
6.9.1 math.h(1)真正的数学运算的函数定义在:/usr/include/x86-linux-gnu/bits/mathcalls.h(2)使用数学库函数的时候,只需要包含math.h即可。6.9.2 计算开平方(1)库函数:double sqrt(double x);undefined reference to ‘sqrt’ collect2: error: ld returned l exit status分析:这个链接错误的意思是:sqrt函数声明(声明就在mat原创 2020-10-19 22:33:15 · 376 阅读 · 0 评论 -
6-8 字符串函数
6.8.1 什么是字符串(1)字符串就是由多个字符在内存中连续分布组成的字符结构。字符串的特点是指定了开头(字符串的指针)和结尾(结尾固定为字符’\0’),而没有指定长度(长度由开头地址和结尾地址相减得到)6.8.2 为什么要讲字符串处理函数(1)函数库为什么要包含字符串处理函数?因为字符串处理的需求是客观的,所以从很早开始人们就在写很多关于字符串处理的函数,然后逐渐形成了现在的字符串处理函数库。(2)面试笔记时,常用字符串处理函数也是经常考到的点。6.8.3 常用字符串处理函数(1、需要下功夫去原创 2020-10-19 22:28:42 · 252 阅读 · 0 评论 -
6-7 函数库
6.7.1 什么是函数库?(1)函数库就是一些事先写好的函数的集合。(2)函数是模块化的,因此可以被复用。我们写好了一个函数,可以被反复使用。也可以A写好了一个函数然后共享出来,当B有相同的需求时就不需自己写直接用A写好的这个函数即可。6.7.2 函数库的由来(1)最开始是没有函数库的,每个人写程序都要从零开始自己写。时间长了慢慢的早期的程序员就积累下来了一些有用的函数。(2)早期的程序员经常参加行业聚会,在聚会上大家互相交换各自的函数库。(3)后来程序员中的一些大神就提出把大家各自的函数库收拢原创 2020-10-19 22:24:48 · 417 阅读 · 1 评论 -
6-6 递归函数
6.6.1 什么是递归函数(1)递归函数就是函数中调用了自己本身这个函数的函数。(2)递归函数和循环的区别。递归不等于循环;(3)递归函数解决问题的典型就是:求阶乘,求Fibonacci数列#include <stdio.h> //用递归函数来计算阶乘int jiecheng(int n); int main(void){ int a = 5; printf("%d的阶乘是%d\n",a,jiecheng(a)); return 0;}int jiecheng(原创 2020-10-19 22:15:15 · 220 阅读 · 0 评论 -
6-5 函数的基本使用
6.5.1 函数三要素:定义、声明、调用(1)函数的定义就是函数体、函数声明就是函数原型、函数调用就是使用函数;(2)函数定义是函数的根本,函数定义中的函数名表示了这个函数在内存中的首地址,所以可以用函数名来调用执行这个函数(实质是指针解引用访问);函数定义中的函数体是函数的执行关键,函数将来执行时主要就是执行函数体。所以一个函数没有定义就是无基之塔。(3)函数声明的主要作用是告诉编译器函数的原型;(4)函数调用就是调用执行一个函数。6.5.2 函数原型和作用(1)函数原型就是函数的声明,说白了原创 2020-10-19 22:08:24 · 191 阅读 · 0 评论 -
6-4 函数的本质
6.4.1 C语言为什么会有函数(1)整个程序分成多个文件(源文件),一个文件分成多个函数,一个函数分成多个语句,这就是整个程序的组织形式。这样组织的好处在于:分化问题、便于编写程序、便于分工。(2)函数的出现是人(程序员和架构师)的需要,而不是机器(编译器、CPU)的需要。(3)函数的目的就是实现模块化编程。说白了就是为了提供程序的可移植性。6.4.2 函数书写的一般原则第一,遵循一定格式;函数的返回类型、函数名、参数列表等。第二,一个函数只做一件事;函数不能太长,也不宜太短。原则是一个函数只原创 2020-10-19 22:02:25 · 281 阅读 · 0 评论
分享