搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > 东林的扯淡小屋 > C语言课程笔记之没有代码讲个毛线篇

C语言课程笔记之没有代码讲个毛线篇

东林的扯淡小屋 2018-03-01

 

计算机的基本原理

《论可计算数在判定问题中的应用》一文中提出了一种理想的计算机器的数学模型——图灵机,其由一条双向无限延长存储带和一个可以存储当前自身的状态控制器,该控制器并且包含一个读写头,可以读、写、更改存储带上每一格的数字/字母,可以根据读到的字母/数字变换自身的状态,可以沿着存储带一格一格地左移/右移。其规则的确立就对应于各种运算。如果对于特定的问题其是可计算的,即给定符号序列A,如果能找到一个图灵机,得出对应的符号序列B,那么从AB就是可计算的,就可以成功停机,有比较确定的输入输出。这正是完美的黑盒子。

而计算机为什么能计算,而且是以二进制的形式来表示,其主要的数学基础是布尔代数,对应于一定结构的电子电路,可以完成一定的逻辑运算,然后在这些基础上形成复杂的逻辑运算(从基本的与或非,到稍微复杂的复合逻辑运算同或,异或,与非,或非,与或非,再到更为复杂的逻辑运算,本质上都是构造)。而各种运算的基本对象如符号最终可以如同ASCII表以数来表示,而数又可以由二进制的1/0表示,从而在这个基础上进行运算(计算机的开关电路)。最基本的运算,加法运算(1+1=10,1+0=0+1=0,0+0=1)就是使用与门和异或门的组合实现,更具体的实现电路就是相应元件和线路的组合。

在这个基础上这些逻辑电路不断缩小就是如今的芯片(集成电路可将成千上万的真空管或晶体管压在一个单独的微型芯片上),可以进行大规模的复杂运算,如超级计算机性能的一个常用指标就是每秒浮点运算次数(万亿次以上浮点运算/秒)。

如今同样的计算机架构体系是冯诺依曼存储程序式体系,能够根据存储的一系列指令,接收输入、处理数据、存储数据并产生输出。具体的实现从真空管到晶体管到集成电路,计算机不断地发展,如今甚至可能向量子计算机领域进军,毕竟摩尔定律总有完结的时候。量子计算机就是一种全新的科学范式,能够更有效的进行运算。因为多种状态的同时保持运行使得更大量级的运算的并行成为可能,而最后的结果即观测值则是使得其从耦合的状态脱离出来,成为我们可以利用的数据。也就是说在这个过程中其接受2^n个输入数据,同时完成所有2^n次运算,但最后输出2^n个结果,相当于把所有的可能性都遍历了一次。

 

程序运行的基本原理

程序是一种相对于计算电路的一种升维或者说抽象,不需要在具体的运算中重新组合各种基本的电路,而是通过以电信号表示的命令来控制电脑来运行,通过更改命令的执行顺序来改变计算机的具体功能。这就是冯诺依曼存储程序式体系:控制器,运算器,存储器,输入设备,输出设备。具体的工作流程是1在控制器指挥下,从存储器上取出指令;2分析指令,得到计算命令和待操作的数;3从存储器上取出待计算的数放入运算器;4运算器计算结果;5输出到存储器或输出设备。

因此存储器是关键。存储器分为:寄存器(CPU内部,用于存放待操作数和结果);高速缓存(通常在CPU内部,用做数据缓冲区);内存;外存。

好,接下来就是具体的程序语言的学习了。

 

 

计算机本身不能完成任何运算,需要我们告诉计算机如何运算,这就是程序。需要一定的格式才能使得计算机识别我们要干的事,然后通过计算机大规模的快速的运算得出结果,为我所用。因此,我们只有解决一个问题之后(提出算法)才能依靠计算机来帮忙解答问题,这一步就完全是靠计算力的堆积。因为计算机本质上就是一个如同欧几里得几何公理体系的构造,我们需要定义并且遵循已有的定义才能实现可能的运算。

一般来说具体的解决步骤是开辟一片存储空间如数组,然后就是相关变量的定义和存储空间的分配(记得初始化),然后就是具体的算法即解决步骤,具体可以由顺序,分支,循环组成如for(i = 0; i < 45; i++){if(number[i]> max)max = number[i];来查找最大值,最后就可以有一定的输出即我们想要的结果了。

在结构化程序设计中,总是按照“先粗后细,先抽象后具体”的办法,对所要描述的解决方案进行穷尽分解(不断细化,颗粒度不断变小,如同微积分分解到无穷小量),直到分解为顺序、分支、循环三种结构。写程序时,可以先写出程序轮廓,而后再补变量定义等细节。而到了最后,我们其实就是在输入输出之间构建一定的映射,即函数,但这种函数是能够解决特定问题的。在这种函数的构造过程,我们必须考虑各个边界条件,对应于编程的详细过程描述(在for循环中考虑各种if),实际上就是顺序、分支、循环三种结构的选择性组合。而当我们完成任务后,可以考虑进一步的优化,如减少搜索空间。

结构化程序设计的基本思想:程序由若干个“模块”组成;模块之内“高内聚”;模块之间“低耦合”

 

 

 

 

 

 

如果我们需要创造一门“程序设计语言”,必须有一套计算机能够识别的关键词并且能够转换为相应的指令,而且我们的输入如数据类型和操作符号也需要其能够识别并且转换。还有最重要的逻辑表达句式。理论上程序设计语言需要顺序,分支,循环三种语句来表示各种复杂的逻辑。C. Bohm & G. Jacopini, "FlowDiagrams, Turing Machines and Languages with Only Two Formation Rules,"Communications of the ACM, vol9(5) May 1966, pp 366-371

这实际上就是我们编译器的内容。计算机什么都不明白,只有我们进行定义之后才能理解如各种变量,数据类型,运算符等等。

先学通一门程序设计语言,再开始设计一门网络专用的程序设计语言。(雄心壮志,然而停留想象。需要专注的努力,少年,编译器呀)

本质上我们的目标是进行程序的开发,为了实现这个宏观的目标,我们需要进行一系列的分解,最好到底层。这就是语言开发环境、数据类型、表达式与运算符、输入输出函数、分支顺序循环控制结构、数组和字符数组等等程序语言的基础。然后在这个基础上进行有选择的组合,形成一定的模块,如函数、变量、指针、结构体、命令的使用;甚至进行存储管理、链表、栈和队列、位运算、文件操作技术和图像处理。最终能够实现具有一定功能的项目设计。这个过程和我们的日常写作是一致的,我们甚至可以设想将来我们能够以自然语言来编程,以后就是如同法术的言咒。当然这需要我们整合到更高层次的系统中。因为我们目前的各种开发都是基于相似的环境中的。因此我们必须基于一定的开发环境,这是底层的建筑。

然后是各种数据类型,及在这个基础的各种表达式。其中对数据的各种处理可以产生一定的有意义的计算。

随着层次的递增,我们需要用到更多层次耦合的高维量,即各种组合形成的函数,而且还有各种基本函数的调用。然后也是各种高级的结果,如指针等等自耦合的结果可以根据高维的结构。

 

 

 

 

 

 

 

C语言的关键词:auto :声明自动变量

short :声明短整型变量或函数

int声明整型变量或函数

long :声明长整型变量或函数

float:声明浮点型变量或函数

double :声明双精度变量或函数

char :声明字符型变量或函数

struct:声明结构体变量或函数

union:声明共用数据类型

enum :声明枚举类型

typedef:用以给数据类型取别名

const :声明只读变量

unsigned:声明无符号类型变量或函数

signed:声明有符号类型变量或函数

extern:声明变量是在其他文件正声明

register:声明寄存器变量

static :声明静态变量

volatile:说明变量在程序执行中可被隐含地改变

void :声明函数无返回值或无参数,声明无类型指针

if:条件语句

else :条件语句否定分支(与 if 连用)

switch :用于开关语句case:开关语句分支

for:一种循环语句

do :循环语句的循环体

while :循环语句的循环条件

goto:无条件跳转语句

continue:结束当前循环,开始下一轮循环

break:跳出当前循环

default:开关语句中的“其他”分支

sizeof:计算数据类型长度

return :子程序返回语句(可以带参数,也可不带参数)循环条件

c语言数据类型:

基本类型 1、整形类型:int,short int,long int,long long int(C99),char,bool2、浮点类型:float,double,双精度浮点型(float_complex,double_complex,longlong_comples)

二、枚举类型 enum

三、空类型 void

四、派生类型

1、指针类型 *

2、数组类型 []

3、结构体类型 struct

4、共用体类型 union

5、函数类型

C++ 语言的运算符

求字节数运算符: sizeof

下标运算符 [ ]

赋值运算符 =

算术运算符 * %

关系运算符 < > == >= <= !=

逻辑运算符 ! && ||

条件运算符 ? :

逗号运算符

位运算符 >> | ^ &

指针运算符 * &

强制类型转换运算符: ( 类型)

分量运算符.→

 

 

 

 

 

 

 

 

 

 

 

 

面向对象的编程其实是一种数学的思想,其实程序设计的各种定义也是残酷数学的公理化体系的构建过程,我们通过在计算机中建立一定的抽象对象,然后在这个层次进行处理,然后可以通过一定的转换关系来映射到现实世界,从而能够对现实世界城市一定的指导。我们通过对对象的定义ABCDEFG,然后通过一定的语句来构建不同对象之间的关系,尽可能地模仿现实,然后通过计算机的运算能力来推测各种关系可能的发展,理论上能够建立这种映射关系,我们只是需要如同雕塑一样施加不同的处理限制,即我们的程序设计语言等等。而基于对象的关系是一种更高维度的运算对象,可以通过多维度的耦合来构建网络的结构。因为不同对象的关系遍历可以对应于任何事物,即如同线性代数中基底的线性组合可以表示空间的每一个点(而且可以表示为不同的维度,可以如同微积分构建不同维度的关系,即求导),可以将复杂的结构分解为简单的基本结构。

以上需要的具体实现就需要我们对程序设计语言的良好应用,通过对各种成分的有意义的组合形成一定的有意义的高维结构,从而能够映射到计算机层次进行一定的运算。在这个过程中,会不断形成模块化的封装模块,最终形成复杂的高维结构,如软件。

 

简单的语法是我们沟通机器世界的基础,这是我们这个时代的魔法,我们需要把握这些技巧才能将外置的机器的力量转化为我们的一部分,本质上这是人类发展摩尔定律的层次突破。尤其是c语言,其各种底层操作使我们能够更好地理解计算机的运行,当然这是我们的基础,然后我们可以选择其他的高级语言继续进阶。

C语言的各种概念其实很底层,我们可以运用生活中具有一定相似性的具体事物来部分指代以方便理解,当然我是习惯于在底层进行理解然后应用于现实来实现以辅助理解,如数组可以引出团队的组织结构,网络的邻接节点的关系来指代线性链表,结构体来指代复杂事物的各种抽象含义。

理解各种概念,编程实践,结构化的思想,学习的深入。

基于语言的程序本质上是解决问题的办法和步骤,通过合理的定义,可以对一定的抽象对象进行运算,这是通过计算机按照一定指令运行的0/1操作,通过一定的状态改变在大规模运算的层次涌现出特定的性质,即计算。这种改变是如同量子的性质,是很确定的。

 

 

变量的思想,对现实事物的抽象化表示;关键词的快速识别;有限的逻辑形式,分支循环顺序,可以选择性表达为实际上所有的逻辑,如同傅里叶变换对空间的遍历;数据类型,结构,运算符;

以上的选择性组合就可以形成各种高维结构,只要有良好定义的变量,和一定的逻辑组合形式等等就可以形成与现实有确定性联系即表达式的目的是解决一定的问题。因为足够抽象层次的运算可以代表现实情况,然后对现实的可能发展做出指导。算法是生产力。这是我们要达成我们想要的医学的建模所必需的。

结构化的设计思想,将复杂结构分解为不同的模块,这与微积分的无穷小量的分解、线性无关基底的线性组合的思想是一致的。而且机器语言到汇编语言到高级语言的抽象层次的降低过程也是相似的。

 

 

算法的实现是我们的理想实现的基础:分析实际问题解析实现过程描述程序算法选择编译环境编写源代码指令调试运行程序给出结果

构建计算环境构建计算对象构建计算方法(面向过程面向对象)验证算法实现

程序=数据结构+算法+设计方法+编程工具+语言环境

 

 

 

C程序设计的基本结构--源程序文件:预编译命令(标准库的头文件#include”stdio.h”),函数(定义说明和命令执行)

确定问题的可计算性建立问题的数学模型设计算法和数据结构选择计算机语言来编写调试运行分析结果

我们需要首先对问题的解决方法有明确的了解,然后在逐步描述的过程中满足算法的要求。因此算法的分析和设计是首先需要考虑的。将具体的问题解决方案分解为最基本的顺序,分支,循环三种结构。按照由大到小,由粗到精,由抽象到具体的方法分析、编写程序,其具体的结构是1程序由若干个“模块”组成;2模块之内“高内聚”;3模块之间“低耦合”

 

 

程序设计语言的基本成分:数据成分,运算成分,控制成分,传输成分。

1数据的使用需要对变量进行定义,即分配一定的内存空间来存储数据,然后可以使用(记得初始化)如int max = 0;。不同的数据类型的定义会有不同长度的内存空间的分配。

正整数以原码存储,负整数以补码表示(原码取反+1

2运算之间具有一定的优先级区别,逻辑非(! )高于算术运算符高于关系运算符高于“&&和“||”高于赋值运算符。表达式由运算符、操作数和括号组成等所组成。

3Flow Diagrams, Turing Machines and Languages with OnlyTwo Formation Rules。从理论上证明了:任何具有单入口单出口的程序都可以用三种基本结构即顺序结构,分支结构,循环结构表达。结构化编程的一个特征。

 

 

 

数组,数据结构是算法发挥理论的一组必不可少的工具;在一定程度上这是一种封装式的抽象,数组用于存放一系列数据类型相同的数据;当处理对象是连续时,可利用数据与下标间的对应关系,解决问题;数组是相对于键盘输入输出更有效的数据存储方式,进一步的就是以特定格式存储的文件。

字符数组是存储字符串的数据结构

 

函数:数学概念的函数的等价应用,都是基于集合论的关系映射构建,其定义域对应于作用范围,是输入;值域就对应于输出;具体的函数表达式就是程序;

函数的原型=返回值类型+函数名+参数类型。

函数是c语言程序的基本部分,函数的调用可以形成复杂的嵌套结构;这种关系可以参考具体的公式推理的各种代入化解等等操作。这种复杂的叠套可以对应于现实的各种变化。数组名也可以做函数参数。

函数的执行是分配新的内存空间进行运算,然后把各种参数和返回值传递;

全局变量和局部变量的作用域不同。

最后我们可以根据函数的输入对应于特定的输出这种性质来应用,即解决各种可能的问题。首先是定义变量,然后以一定的结构进行组织实现一定的输入输出,甚至可以以函数这种抽象的结果来表示,然后在这个基础构建更复杂的结构,可以解决具体问题。

函数的递归是一种代码的重用,直到满足一定的条件从而停止这个递归过程。可以参考数学归纳法对数学命题的证明来理解这个过程,数学的证明就对应于具体问题的求解。事实上,先定义再运算本来就是一般数学命题的基本方式。

函数可以嵌套调用,但不可以嵌套定义。函数之间可以形成复杂的嵌套结构,当函数之内形成嵌套结构,就如同罗素的理发师悖论(类似于调用自身函数产生矛盾),看似是一个矛盾,但哥德尔定理指出没有一种公理系统可以导出数论中的所有真实命题,除非该系统本身存在悖论(存在一个不可判定的命题,S~S都成立,动态的死循环),这就使得我们在这种悖论式的假设下形成可以导出所有真实命题的系统,这对应于具体问题的求解。因此函数的调用递归具有解决问题的强大能力。而实际上,计算机解决问题就是基于希尔伯特的形式主义思想,通过符号逻辑的方法来进行数学语句的公式表述,并用形式的程序表示推理,最后演变为我们熟知的图灵机。

1递推是从初始值出发,找到第n次操作与第n-1次操作的关系,一直推广其适用范围;递归则是一种逆过程,把复杂的问题减而治之,不断收缩求解的范围,直到初始值,然后可以使用递推的方式求解我们感兴趣的问题。

2模拟连续发生的动作,斐波那契数列求解就是这样的连续算法求解。这实际上就是算法的具体执行过程,具体的操作以及不同次操作之间的关系,还有最重要的边界条件;

3自动分析,假设存在解决问题的函数,然后分析如何解决问题,通过弄明白最简单情况下其解决问题的方法,然后递推。

 

 

 

 

 

 

 

指针

数组这种数据结构的使用和变量相似,也可以作为各种叠套结构的一部分,可以利用指针变量引用数组元素。在这个基础上可以对应于字符串和高维数组。最后可以对应于一定的函数,即使用指针作为函数的参数或者函数返回值。

数组名相当于指向数组第一个元素的指针;&E 相当于把E的管辖范围上升了一个级别;*E 相当于把E的管辖范围下降了一个级别。

 

 

 

 

 

 

 

 

结构体(新的数据类型),使用一组变量来描述同一事物,将一个高维的事物分解为低维的不同事物,类似于使用不同属性来描述一个对象。如学生找过对象可以以其ID号,姓名,性别,分数,住址等等变量来描述,理论上这些属性越多,可以确定的对象就越精确。将结构体视为普通数据类型的一种升维,那么基本数据类型的各种性质如叠套,如作为参数用于传递到函数等等都是可以的。

首先是构造一个新的数据类型即结构体:struct 变量{各种属性},然后定义结构体变量,其方式与一般的变量定义相似,

 

数据结构的要素包括数据的逻辑结构(呈现在用户面前的数据形式),存储结构和数据运算,其中逻辑结构可以分为线性结构,有线性表、栈、队列、串和数组,非线性结构有树结构和图结构;存储结构分为顺序结构、链式结构、索引结构和散列结构;数据运算有插入、修改、查找和排序运算。

数据是能够输入并且能够被计算机处理的符号的集合,是信息的符号表示形式。其元素是数据的基本单位及数据项。数据结构是带结构的数据元素的集合。

逻辑结构:线性,树形和图形,都是节点之间的关系,一对一,一对多和多对多。(开始节点和前驱节点和末端节点的分类)B=(D,R)

抽象数据类型=逻辑结构+抽象运算,本质上在描述问题,能够在这个基础上求解问题,也就是算法。

算法有输入和输出,具有有穷性,确定性和可行性等等性质;而好算法还需要具备正确性,可读性,健壮性,通用性,以及满足效率和存储量需求等等性质。

效率是指有效地使用计算资源来满足需求,即占据有限的CPU计算资源从而用时短,存储资源少即耗费内存少。我们使用复杂度来衡量其效率,即基本运算次数。执行时间等于控制结构(顺序,分支,循环)和原操作(固有数据类型的操作,加减乘除等等)的时间与运算次数的相乘。

算法的施加复杂度表示法T(n)=O(fn),表示时间复杂度的量级,是执行时间随问题规模n的增长率。

 

递归和循环,基于矩阵即数据的运算;

搜索,树的剪枝;

多层次的嵌套,如同多重神经网络;本质上是并行运算

 

模糊计算,不强求完全的准确性,只希望在有限的计算资源得到不那么差的结果

 

 

 

 

 


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《C语言课程笔记之没有代码讲个毛线篇》的版权归原作者「东林的扯淡小屋」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注东林的扯淡小屋微信公众号

东林的扯淡小屋微信公众号:yudonglinCHEDAN

东林的扯淡小屋

手机扫描上方二维码即可关注东林的扯淡小屋微信公众号

东林的扯淡小屋最新文章

精品公众号随机推荐