C-入门第一课

2.8k 词

欢迎来到C语言,这里是 C 的第一课。先来了解一下最基本的理论吧。

基本单位

语句

C 使用语句执行操作,语句由若干个令牌(通称Token,下同)组成并以分号(半角英文分号)结尾,若干个语句可以拼装成代码块(用一对半角英文花括号包裹,相当于一个聚合语句,发挥和普通语句一样的效果)。

关于Token Token分为一下几类:
  1. 关键字(Keywords),是 C 内部的保留字,不能作为变量名、常量名或其他标识符名称。
  2. 标识符(Identifiers),是程序中变量、函数、数组等的名字,由字母(大写或小写)、数字和下划线组成,但第一个字符必须是字母或下划线。此外, C 对大小写敏感, Languagelanguage 就是不同的标识符。
  3. 常量(Constants),是固定值,在程序执行期间不会改变,包括字面常量和const常量。
  4. 字符串字面量(String Literals),是由双引号括起来的字符序列。
  5. 运算符(Operators),用于执行各种操作,如算术运算、逻辑运算、比较运算等。
  6. 分隔符(Separators),用于分隔语句和表达式。

CToken

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//关键字
for
int
break
goto
static

//标识符
h264
_homo114514
o1o1o1o1

//字面常量
#define HOMO 114514
123456
//const常量
const int CONST = 114514

//字符串字面量
"114514"

//运算符
+-*/ >> << ? > !=

//分隔符
{} [] () ; ,

注释

C 中有两种注释,单行注释和多行注释。单行注释以两个正斜杠//开头,占据从注释开始到当前行结束的所有区域;多行注释在首尾以/* */包裹,可以占据多行也可以占据一行的一小部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//这是单行注释
int a = 6;//这也是单行注释

/*






*/

int b = /* 多行注释也可以像这样只占用一小块,用于插入局部解析之类的 */114514;

a = b //*divisor:*/ c
+ d;
//在C90标准下等效于a = b / c + d;
//在C99下等效于a = b + d;
关于注释 C的注释在编译时会被编译器完全忽略并去除,不会影响代码逻辑。注释是写给人看的,用于注明代码功能,解释代码逻辑等一系列增加代码可读性的操作,还有一个用处是临时关闭一些不需要的语句(直接给某个语句注释调就可以在不删除语句的情况下跳过执行这条语句)。

写好注释是个好习惯,不仅为了自己,也是为了别人。

预处理器

预处理器是一系列以 # 开头的语句,在对代码正文编译之前先行对代码进行处理,然后才正式开始编译。预处理器有自己的语法,因此语句结束不用加分号。详见 预处理器 章节。

函数

函数是 C 的基本单位,拥有唯一的函数签名、包含任务逻辑的代码块和返回值。详见 函数 章节。

函数签名
函数签名指函数的返回值和参数列表,不同名称的函数可以有相同的函数签名。函数的导出符号由函数名、函数签名和编译器共同决定。

封装结构

包含结构体(struct)和共用体(union)。详见 结构体与共用体 章节。

控制结构

包含逻辑控制与循环控制。详见 判断语句循环语句 章节。

程序结构

C 程序起始于具有 int main() 或者 int main(int argc,char** argv) 签名的函数,一个程序必须包含唯一的这样的函数,称为主函数。 C 的源代码只能包含函数声明、函数实现、全局变量/常量声明、结构体/共用体声明、类型名称定义、注释、预处理器指令,其余语句直接写在源文件内是非法的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h> //预处理器

//This is a demo
struct MyStruct{
//结构体声明
int Age;
char Name[64];
};

typedef int INTEGER;//类型名称定义

void Greet(char[] name);//函数声明

int main(){
//函数实现
printf("Hello,World\n");
return 0;
}

printf("111");//非法,会报错

好习惯

人写代码的习惯因人而异,但是会有很多优秀的共性,被成为好习惯。良好的编程习惯不仅有利于自己,也有利于他人。

标识符命名

你自己声明的变量、函数、结构体都需要你去命名。标识符名称对编译器来说只是一个抽象的符号,没有实际意义;但是对人来说,它是代码需要阅读的一部分,直接影响着代码的可读性。在一个程序中,所有标识符都应该遵从统一的命名规则,使用有意义且详细的名称,宁长勿短(除了循环控制变量或用处只有紧挨着几行的临时变量)。

1
2
3
4
5
6
7
8
9
10
//好的命名
void isLeapYear(int year);
int PrintTableWithSeperator();
yearOffset lunarBirthdayDate

//坏命名
a b c aa abc xyz
void calc();
int pt();
void sdfdhgs();

写注释

注释面向代码的阅读者,对编译器没有意义,同样是代码可读性的重要保障。

1
2
3
4
5
6
7
8
9
//这个函数用于计算一年是否为闰年
int isLeapYear(int year/*输入年份*/){
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

//一个十分复杂的函数
void a_complex_function(int age/*年龄*/,char[] name/*姓名*/,char** tags/*标签,一个字符串数组*/){
//pass
}

代码中的空格与空行

C 中空格一般用于分割标识符。其余地方的空格会被忽略。但是任然建议在一些地方加入空格以提高代码可读性(例如运算符两侧)

1
2
3
double a = 1 + 1 * 4 / 5 * 1 % 4
double b=1+1*4/5*1%4
//第一种看起来会更舒服更明确

内存管理

C 中如果需要声明大型变量,需要手动申请空间,否则可能会导致爆栈。申请的空间需要手动释放,以免产生内存泄漏。养成好习惯,申请的内存使用完后一定要及时释放。此外,C语言中有一个十分重要的原则:谁申请的谁回收,无论申请人是函数,程序员,还是编译器(详见 内存管理 章节)。

主函数返回值

C 语言习惯,在程序正常运行完毕时,主函数应该返回0;如果程序运行中遇到异常,需要提前结束主函数,则应该返回-1.

写在最后

这里只是 C 的基本理论,也是学习的第一课。掌握基础知识,培养良好的编程习惯,为了自己,也是为了其他要看代码的人。

留言