重走C语言之路(二)
1. 简单程序结构
已经看过一个C语言的Hello World程序了,那么如果要写一个C语言的简单程序,需要满足什么样的基本结构呢?
在C语言当中,程序是由一个或多个函数组成的,并且其中必须包含有main()
函数头和函数体组成函数,而函数头的内容又包括函数名、入参、返回类型
函数体便是{}包裹起的代码块,主要是声明、语句的组合
因此,明白了这些,大概可以构思一下一个基本程序的结构,大概是这样:
// 预处理、声明等
int main()
{
// 若干声明、语句、函数
return 0;
}
程序有一个main()用作入口,其他部分基本都是需要添加的,根据需求补充函数、声明、语句等,组织成有意义的逻辑,必要的时候可能还需要额外添加预处理语句等,在此基础上其他的都是填空,可以由少到多地进行一步步地尝试
2. 程序的可读性
为什么还没怎么开始写,就开始叨叨可读性呢?因为习惯性的东西还是尽早提出来比较好,之后可以不断地在实践中加深
刚开始的时候,我们可能往往只是注重于实现功能本身,但是随着自己越来越熟悉语言,项目代码随之膨胀起来之后,我们会逐渐发现,可读性高的代码真的是太重要了,无论是排查问题、性能优化、重构等都能有条理地展开;而难度的代码会浪费掉你很多时间,而且容易在不注意的地方留下定时炸弹
变量、函数的命名尽可能遵循易读的法则,比如count就比c好,至少能够大概猜一猜这个变量可能是用于计数的
另外,如果实在不方便使用变量、函数名等说清,可以使用注释进行辅助说明,在关键逻辑的语句之前使用注释补充说明,或者标记参考
并且巧妙利用空行和换行也是可读性里重要的一环,相关的语句可以扎堆儿写,利用空行将代码逻辑分成一块块
#include <stdio.h>
int main()
{
// 声明-1部分
int a, b, c;
// 赋值-2部分
a = 1;
b = 2;
c = 3;
// 输出-3部分
printf("");
return 0;
}
像上面这样,几个部分就感觉很清晰,分工明确,很有条理
语句本身就是以;结束,没有必要拖拖拉拉写在一行,每行不宜过长,就像上面那样,简洁明了,如果实在比较长可以考虑以整洁的格式多行呈现,必要时配上相应的注释
printf(
"先输入参数一%d, 再输入参数二%d, 二者求和=%d",
a,
b,
a + b);
3. 程序调试
在真正编写程序的时候,我们往往需要通过调试来检测程序当中可能存在的问题
在项目的规模逐渐膨胀时,逻辑也会更加复杂,许多问题不能够一目了然,可能需要等发现了再去排查修复,掌握一定的调试技巧可以大大提高效率
常见的问题主要分为语法错误、语义错误
语法错误通常能够由编译器帮忙检查出来,因为编写的代码需要满足C语言的语法规范,而语法规范是一个确定的规范,因此当程序编写不规范时,编译器通常可以及时发现,并且标识出问题的位置
比如像这里,缺少分号的问题可以及时被发现
语义错误往往难以排查,至少编译器帮不了你,因为编译器不会知道你写一段程序想要表达什么,它只会机械地检测是否违反既有的语法,因此,语法问题通常更加难以排查
你可以通过自己阅读程序,梳理逻辑,或者使用断点调试功能进行程序的单步执行
具体的内容将会在后面专门展开~~
4. 关键字和保留字
关键字是C语言的词汇,这些词是不能随便拿来用作标识符的,像int表示的是整数类型,for表示的是循环,都有各自专门的用途
| 关键字 | 说明 |
|---|---|
| auto | 声明自动变量 |
| break | 跳出当前循环 |
| case | 开关语句分支 |
| char | 声明字符型变量或函数返回值类型 |
| const | 定义常量,如果一个变量被 const 修饰,那么它的值就不能再被改变 |
| continue | 结束当前循环,开始下一轮循环 |
| default | 开关语句中的"其它"分支 |
| do | 循环语句的循环体 |
| double | 声明双精度浮点型变量或函数返回值类型 |
| else | 条件语句否定分支(与 if 连用) |
| enum | 声明枚举类型 |
| extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
| float | 声明浮点型变量或函数返回值类型 |
| for | 一种循环语句 |
| goto | 无条件跳转语句 |
| if | 条件语句 |
| int | 声明整型变量或函数 |
| long | 声明长整型变量或函数返回值类型 |
| register | 声明寄存器变量 |
| return | 子程序返回语句(可以带参数,也可不带参数) |
| short | 声明短整型变量或函数 |
| signed | 声明有符号类型变量或函数 |
| sizeof | 计算数据类型或变量长度(即所占字节数) |
| static | 声明静态变量 |
| struct | 声明结构体类型 |
| switch | 用于开关语句 |
| typedef | 用以给数据类型取别名 |
| unsigned | 声明无符号类型变量或函数 |
| union | 声明共用体类型 |
| void | 声明函数无返回值或无参数,声明无类型指针 |
| volatile | 说明变量在程序执行中可被隐含地改变 |
| while | 循环语句的循环条件 |
后续在C99标准中又追加了5个关键字
| _Bool | _Complex | _Imaginary | inline | restrict |
C11新增7个关键字
| _Alignas | _Alignof | _Atomic | _Generic | _Noreturn |
| _Static_assert | _Thread_local |
其实经常写写,熟悉了自然能够分辨,没有必要刻意进行记忆
除了关键字不能用于标识符,还有保留字,主要是一些标准库中的函数的名称,也是有特定的用途,尽量避免使用,从而引起一些问题
5. 标识符
既然都已经说到关键字和保留字了,那么就有必要谈谈重要的标识符概念了
标识符其实就是C语言当中用来标识变量、函数、以及一些其他用户自定义项目的名称,主要是给开发者起名字制定的规范
具体的规则就是标识符要以大写或者小写字母、数字、下划线组成,并且不能以数字开头(也要避开关键字和保留字,就像古代起名不能犯皇帝名讳一样)
像mPlan02、_count、a23、last_name这些都是合法的标识符
并且C语言严格区分大小写,map和MAP代表就是完全不同的东西
标识符在编写程序的过程中被大量的使用,如果想要确保程序清晰整洁,在确保标识符合法的情况下,具体的名字如何组织也得好好斟酌