c程序语言设定定义域,高观点下的C语言入门

2023-10-20 20:10

本文主要是介绍c程序语言设定定义域,高观点下的C语言入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C语言,是大多数科班出身的程序员的第一门语言,也是大多数底层技术爱好者的主要语言。

在计算机领域,底层技术就是核心技术。

C语言刚入门时,其实还是很别扭的,因为它的设计与高中数学教育形成的思维惯式不太一样。

1,相等==和赋值=的区分,

在数学里,一般不需要特别的符号来区分相等和赋值,人们可以根据上下文的语义知道表示的是什么。

x=1的同时也就暗含了x==1,在给人看时不需要特意说明这点。

但在电脑程序里需要区分,因为电脑的理解力比人差得多,也就需要在程序设计时添加更多的细节。

比较x是否等于1,和让x等于1,是两种不同的运算。

必须给电脑明确指出,它才能正确运行。

因此,我们需要两个“不同但又类似”的符号,作为这两个关联场景的运算符,C语言选择了=用于赋值,==用于相等。

不等,则使用了!=,因为ascii码里没有数学上那个不等号,如果使用ascii码之外的符号就会需要额外的输入法软件,这对编程语言是不可接受的。

没有哪个程序员在编程时想切换输入法,除非它要输入非英文字符串。

之所以不让==表示赋值,而让=继续符合人们中学时学的通常语义,是因为赋值比相等在程序里出现的次数更多。

比较运算可以是>、>=、 < 、<= 、!= 、!,==出现的次数其实不多。

但赋值,包含扩展的+=、-=之类的,出现的次数特别多,可以少打一个符号。

对使用频率高的词汇使用较短的编码,是所有语言的惯例。也是符合“信息论”的编码原则的。

“我”,在汉语里的笔画算比较少的,而且结构很醒目。

英语则是I,法语是Je,这种高频次的第一人称代词,一般都是简短+单音节+元音结尾的词。

第三人称的“是”,也是另一个高频词汇,英语是is,法语是est,例如多邻国的名句:C’est une fille anglaise.

汉语是典型分析语,语义表达不依赖动词形式变化,所有人称的“是”都一样,但这个字也笔画简单而结构显眼。

书法好的可以把它写地龙飞凤舞,大气磅礴。

回到C语言,另外,如果赋值使用了==,那么频次不低的+=就变成了+==,三个字符不但会给词法解析带来额外负担,还会让程序员多打一个字符:(

程序员都是懒人,否则他们就不会把重复的活儿给电脑做了:(

+=在循环语句里用于变量的自增,使用频率仅低于++。

2,从0开始计数,

这也是很不符合惯例的设计。

人们数数是从1开始,0在数学史上出现也是较晚的,比1晚的多。

但是在二维数组中,如果从1开始计数,那么2行16列的数组,16是第1行最后1个元素,17是第2行第1个元素。

可是,16/16=1余0,17/16=1余1,它们的数组索引与它们与数组大小的除法结果就不一致了:

“商+1”才是行号,但余数是0时商又不需要+1,这在编程时会额外消耗程序员的脑力,而且这种计算细节很容易出错。

另外,就是索引值与元素在数组中的实际偏移量不一致。

第1个元素与数组首地址的偏移量是0,而不是1,&a[1]对应的是a+1 - 1 = a+0。

就跟公元1世纪不是1xx年,而是xx年一样,算起来别扭又烧脑。

如果让索引号和偏移量一致,那么0号位的内存就浪费了。

这在内存稀缺的上世纪70年代,是不可接受的。

最后,为了让数组索引与除法/和模运算%的结果一致,就从0开始计数了。

模运算%的结果一致叫做“同余”,线性同余方程组的求解,最早可以追溯到中国古代数学著作“孙子算经”。

宋代大数学家秦九韶在“数学九章”中把这个解法叫做“大衍求一术”,现代的抽象代数里叫做“中国剩余定理”。

秦九韶的解法,同时也是这个定理的“构造性证明”。

构造性证明,比存在性和唯一性的证明要牛,因为它同时给出了求解步骤。

中国古代在代数学领域还是很牛的:(

几何学上可能古希腊牛一些,毕竟欧几里德比较牛,“几何原本”,“古希腊三大难题”。

但古希腊三大“几何”难题,最后都是靠“代数”否决的:(

3,变量,

变量的出现伴随着方程的诞生,可以追溯到一元一次方程的出现,久得估计没法考证了。

秦九韶解线性同余方程组的中国剩余定理,肯定比这个晚了至少上千年。

方程确定的是隐函数,函数确定的自然是显函数。

4,函数,

C语言的函数和数学上的函数有点区别,它是一个处理某个功能的代码模块,可以被另一个函数调用。

它也和数学上的函数一样有参数(自变量),也有返回值(结果),这可能是它也叫做函数的原因。

它也是从参数空间(定义域)到返回值空间(值域)的一一映射:在代码没有BUG的情况下同样的参数该算出同样的结果来。

调用时需要传参数,参数和返回值在不需要的时候也可以没有,void f()这种。

整个程序的入口函数就是main函数,它被操作系统加载程序时调用,Linux的这个API是execve()。

5,指针,

指针,是C语言的压轴章节。

这章之后,就是文件读写的API了,严格来说不属于编程语言范畴,而是属于IO库的范畴。

“去书架上把C primer plus借来”。

书架就是“指针”,是C primer plus这本书存放的位置。

C primer plus就是指针的内容,即书架上存的是什么。

内存就是计算机的“书架”,内存里的值就是这个“书架”上的“书”。

对于电脑来说要尽量细化,所以给内存按字节编号,指针就是这类编号。

还可以给书里的章节编号,那么书架就是二级指针,书是一级指针,章节是指针的内容。

地址,在日常生活中也是常见的。

寄快递需要有地址和收货人,去某地址找某个收货人,把快件交给他之后,他的总体重量增加了1公斤,就是*p += 1。

6,递归,

递归,就是利用“函数栈”保存上下文状态的迭代。

递归比迭代难理解,但在编程上比迭代容易实现,因为它不需要手动保存上下文状态。

按照数学归纳法,当k = 0的时候条件成立,当k = n的时候也成立,当k=n+1的时候也成立,计算k = 10的结果。

从k=0开始,根据迭代公式,一直迭代到k=10,每一步都要保存k跌代到哪里了,结果是什么。

k和结果就是上下文,手动管理它们的存放就是迭代,把它们写在函数参数里,让程序在函数调用的过程里自动管理,就是递归。

参数,也是函数的局部变量,局部变量的管理由编译器实现,实际上简化了程序员的工作难度。

二叉树遍历时,开一个动态数组,不断把遍历到的节点按遍历顺序存进去,同时记录哪个分支遍历过了,哪个分支没有遍历,迭代到哪里了,实际是比较麻烦的。

但是,用函数栈来存储状态,就只需要改变每次迭代的参数就可以了,代码就简单得多。

递归难理解,可能在于它是反向迭代,大多数场景下的都是从10跌代到0,截至条件与日常经验是反过来的。

倒着数数,相对比较别扭。

7,字符和字节,

单字节并不足以表示全球主要语言的所有常用字符,char作为1个字节的变量同时表示字符,是ascii码时代的遗迹。

那个时候字符和字节的语义是一致的。

unicode的出现比较晚,所以C后来又添加了wchar类型,但char已经在各种代码里用惯了。

char既当字符变量,又当单字节变量,char*还作为缓冲区的指针,又当作字符串,差别只在于结尾0。

然后就有了著名的缓冲区溢出漏洞:(

不在字符串的string类型中记录长度,而是靠结尾的哨兵0,最后不得不搞出了各种snprintf函数。

每次strcpy、sprintf时都要在心里默算缓冲区够不够。

优点就是vsnprintf()函数的实现比较简单,因为字符和整数可以直接运算,

x % 10 + ‘0’就是数字要打印的字符。

char和char*字符串的使用,在C里是特别容易出BUG的地方。

本来,字符应该是无符号的,但是在char同时充当了有符号的单字节整数的情况下,就导致了char型的0x80在编译器扩展时成了负数。

unsigned char型的0x80是正的。

char在与int计算时需要注意它的最高位是0还是1,因为编译器会做符号扩展。

b23926a30f657f6b503a1dddc6dbf4fb.png

举报/反馈

这篇关于c程序语言设定定义域,高观点下的C语言入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/249456

相关文章

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ