编写简单的C语言程序(NOI培训)
编写简单的C语言程序(NOI培训) 刘汝佳 何为“简单”? 百度风格:简单可依赖 简单不等于简陋 我们的目标:用简单、直观、不容易出错的程序来完成任意复杂的功能,而不是把各种“高级的东西”堆砌在一起,然后把包括自己在内的所有人搞糊涂 在编程语言中,不是所有语言特性都是必须的。对于算法程序来说尤其如此。 为什么要学习C语言 应用范围广,是学习C++, Java, C#等语言的基础 功能强大,语法也不算复杂,适合描述算法,也适合用C语言体会设计、编码、调试和测试这些步骤的最佳实践。 学些啥? 语法、语义 常用库函数 从实例中学习 如何设计 如何编码 如何调试 如何测试 C语言的特性 三大特性 源码可移植性(在一定程度上) 可编写底层程序 高效 Unix操作系统就是由C写成。在嵌入式领域应用十分广泛,但也有很多用C写成的字处理程序和数据库系统 程序结构 C语言是面向过程的,因此基本构造块是函数。 函数可以自己写,也可以用标准库里已有的。 函数中包含语句,而语句可以组合成语句块。 从一开始培养编码习惯 简单的”hello world”函数也可以看出编码习惯 注释:要有,但不要过量 空格:大多数token之间需要加空格 缩进:可以2,3,4格或者tab缩进,但要统一 花括号换行:是否单独另加一行均可,但要统一 多语句:尽量不要一行写多条语句;不要用逗号代替花括号 尽量把逻辑复杂的长语句分成简单的多条语句。这样不仅程序更漂亮、易写易读,而且方便测试和调试。不要追求炫的写法,要遵守KISS 类型 基本类型:整数、实数与复数 枚举 无值(void) 派生类型 指针 数组 结构体 联合 函数 整数 如何表示正整数?如何表示负整数?有符号整数和无符号整数有何区别? 为什么会有不同大小范围的整数类型? 如何表示正无穷和负无穷? 整数有哪些常见运算?有什么需要注意的地方? 如何表示高精度整数?如何编写它的运算? 字符:一种特殊的整数 问题:如何改变大小写? 变种:Latin-1,Unicode 实数 如何表示有理数?如何表示无理数(如果可以的话)? 既然实数表示的范围比整数大,那为什么还需要整数类型? 为什么要尽量避免比较实数是否相等? 如何表示正无穷?负无穷?是否有其他特殊的实数? 有哪些常见的实数函数?如何取整? 如何表示高精度实数?如何编写它的运算? 数组 数组里必须是相同的数据类型 数组名代表它的首地址。无法根据这个首地址获取该数组的元素个数 特殊的数组:字符串 数组中的每个元素是一个字符 以特殊字符’\0’ (ASCII码为0) 结尾 结构体 相当于Pascal语言中的记录 数据封装的例子 问题:如果要表示二叉树,结点类型必须自己包含自己? 建议:尽管不推荐使用,指针在某些时候还是必须的。在需要使用指针的场合,尽管只用取地址和取内容运算符,不要对地址本身进行运算。这将大大降低出错的可能 运算符 八类运算符 算术运算 赋值运算 自增自减 比较运算 逻辑运算 位运算 地址运算 其他运算 表达式的副作用 如果在计算一个表达式后,程序的执行环境发生改变,我们说这个表达式有副作用 副作用往往隐藏着陷阱! 副作用的源头 自增自减运算 (不要写出a = a+++ ++a 这样的东西) 能修改数组和结构体的函数 全局变量 问题:你能想到哪些由副作用引起的错误? 语句 空语句 表达式语句:要么是赋值语句,要么有副作用,否则意义不大(尽管合法) 控制流语句 条件分支: if, else. 可以嵌套 循环: for, while, do-while. 可以嵌套 无条件跳转:break, continue, goto 语句可以用花括号复合到一起 问题:可以完全避免goto语句吗? 不要goto语句? 程序设计方法的进步:结构化程序设计 三大基本结构:顺序、分支、循环 合理的设计程序流程图是一个必须熟练掌握的基本功. 推荐在纸上写清楚了,再动手编码 画N-S图 写伪代码,只包含if-else, for, while/do-while, break和continue,不含goto C语言并非严格的结构化编程语言,因此更多的是靠自觉! 函数 函数的定义:参数、返回值、函数体 函数的声明:类似Pascal的forward声明 参数传递方法:传值、通过指针传参 问题:何时需要传参? 输入输出 不同语言的输入输出方法很不一样 C语言:printf, scanf等 C++语言:除了printf和scanf外还可以用流(cin, cout etc) Java语言:流,但输入经常需要自己解析 建议:学会自己解析和生成字符串,而不要只会用系统提供的格式化输入输出函数。 其他内容 预编译指令 包含头文件 宏的应用 动态内存管理 malloc, free 动态结构不一定需要动态分配内存