C语言常见概念
C语言
人和人交流使用自然语言(如汉语、英语、日语),人和计算机交流则需要计算机语言。现有的计算机语言有上千种,程序员通过这些语言编写程序来向计算机下达指令。
C语言是其中的一种,并且历经多年仍然在计算机语言排行榜上名列前茅。除 C 语言外,像 C++、Java、Go、Python 等也是常见的计算机语言。
C语言历史
C 语言的诞生与 UNIX 操作系统密切相关。其发展历程大致如下:
1969 年 Ken Thompson 在 BCPL 的基础上发明了 B 语言 用于移植 UNIX 内核。
1972 年 Dennis Ritchie 与 Brian Kernighan 在 B 语言的基础上重新设计出一种更高级的语言,命名为 C 语言。
1973 年整个 UNIX 系统都使用 C 重写,这种语言迅速流传并成为编写操作系统和系统软件的主力。
1988 年 ANSI 发布 C 语言标准化。
直到今天,C 语言仍然广泛使用。
编译器
编译和链接
C语言是一门编译型计算机语言,C语言源代码都是文本文件,文本文件本身无法执行,必须通过编译器翻译和链接器的链接,生成二进制的可执行文件,可执行文件才能执行。
C语言代码是放在 .c 为后缀的文件中,要得到最终运行的可执行程序,中间要经过编译和链接 2 个过程。
C语言把 .c 为后缀的文件称为源文件,把 .h 为后缀的文件称为头文件。
一个工程一般都会有多个源文件组成,如下演示了源程序经过编译器和链接器处理的过程:
每个源文件(
.c)单独经过编译器处理生成对应的目标文件(.obj为后缀的文件)。多个目标文件和库文件经过链接器处理生成对应的可执行程序(
.exe文件)。
编译器对比
C语言是一门编译型的计算机语言,需要依赖编译器将计算机语言转换成机器能够执行的机器指令。
- VS2022 集成了MSVC,安装报包较大一些,安装简单,无需多余配置,使用起来非常方便。
- XCode 集成了clang,苹果电脑上的开发工具。
- DevC++ 集成了gcc,小巧,但是工具过于简单,对于代码风格的养成不好,一些竞赛使用。
- Clion 是默认使用 CMake,编译器是可以配置的,但工具是收费。
集成开发环境(IDE)用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。
示例程序
如下为一个简单的 C 程序,它在屏幕上输出一行文本:
#include <stdio.h>
int main()
{
printf("hello C\n");
return 0;
}
运行时,程序会从 main 函数开始执行,调用标准库函数 printf 打印字符串 hello C,最后通过 return 0 返回。
main函数
每个 C 程序必须有且只有一个 main 函数。无论源代码中包含多少其他函数,程序都是从 main 开始执行的,因此它被称为程序的入口,也被叫做主函数。
main函数前面的int表示它会返回一个整型值,通常在函数尾部通过return 0;表示程序正常结束。- 项目中只能存在一个
main,否则链接阶段会报多个入口点的错误。
库函数
printf
printf 属于 C 标准库中的输入/输出函数,用于将信息打印到标准输出设备,使用时需要包含 stdio.h 头文件。
#include <stdio.h>
printf 使用占位符来控制格式,例如 %d 表示打印整型、%c 表示打印字符、%lf 表示打印 double 类型。打印字符串可以使用 %s 或直接将字符串常量放在参数中。
printf("hello C\n");
库函数
为了不再重复实现常见的代码,让程序员提升开发效率,C语言标准规定了一组函数同的编译器厂商根据标准进行实现,库,这些函数也被称为库函数。在这个基础上一些编译器厂商可能会额外扩展提供部分函数(这些函数其他编译器不一定支持)。
一个系列的库函数一般会声明在同一个头文件中,所以库函数的使用,要包含对应的头文件。C库函数。
关键字
C 语言保留了一批具有特殊含义的符号,它们称为关键字或保留字。
- 关键字都有特殊的意义,是保留给C语言使用的。
- 程序员不能把关键字用于自定义标识符名称。
- 关键字不能自己创建。
C89 标准规定了 32 个关键字,包含:
| 关键字 | 关键字 | 关键字 | 关键字 |
|---|---|---|---|
auto | break | case | char |
const | continue | default | do |
double | else | enum | extern |
float | for | goto | if |
int | long | register | return |
short | signed | sizeof | static |
struct | switch | typedef | union |
unsigned | void | volatile | while |
C99 引入了 inline、restrict、_Bool、_Complex、_Imaginary 等关键字,但使用最多的仍是上表中的 32 个,更多可参考C语言关键字。
ASCII编码
键盘能够输入各种符号,例如 a、q、@、# 等,这些单个符号称为字符。在 C 语言中,字符用单引号包围,例如 'a'、'b'、'@'。
计算机内部所有数据都以二进制形式存储,为了统一字符的二进制表示,美国国家标准学会(ANSI)制订了 ASCII 编码,C 语言采用 ASCII 表对字符编码。
| dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 00 | 00 | NUL(空) | 32 | 040 | 20 | (空格) | 64 | 100 | 40 | @ | 96 | 140 | 60 | ` |
| 1 | 01 | 01 | SOH(标题开始) | 33 | 041 | 21 | ! | 65 | 101 | 41 | A | 97 | 141 | 61 | a |
| 2 | 02 | 02 | STX(正文开始) | 34 | 042 | 22 | " | 66 | 102 | 42 | B | 98 | 142 | 62 | b |
| 3 | 03 | 03 | ETX(正文结束) | 35 | 043 | 23 | # | 67 | 103 | 43 | C | 99 | 143 | 63 | c |
| 4 | 04 | 04 | EOT(传送结束) | 36 | 044 | 24 | $ | 68 | 104 | 44 | D | 100 | 144 | 64 | d |
| 5 | 05 | 05 | ENQ(询问) | 37 | 045 | 25 | % | 69 | 105 | 45 | E | 101 | 145 | 65 | e |
| 6 | 06 | 06 | ACK(确认) | 38 | 046 | 26 | & | 70 | 106 | 46 | F | 102 | 146 | 66 | f |
| 7 | 07 | 07 | BEL(响铃) | 39 | 047 | 27 | ' | 71 | 107 | 47 | G | 103 | 147 | 67 | g |
| 8 | 08 | 08 | BS(退格) | 40 | 050 | 28 | ( | 72 | 110 | 48 | H | 104 | 150 | 68 | h |
| 9 | 09 | 09 | HT(横向制表) | 41 | 051 | 29 | ) | 73 | 111 | 49 | I | 105 | 151 | 69 | i |
| 10 | 0a | 0A | LF(换行) | 42 | 052 | 2a | * | 74 | 112 | 4a | J | 106 | 152 | 6a | j |
| 11 | 0b | 0B | VT(纵向制表) | 43 | 053 | 2b | + | 75 | 113 | 4b | K | 107 | 153 | 6b | k |
| 12 | 0c | 0C | FF(换页) | 44 | 054 | 2c | , | 76 | 114 | 4c | L | 108 | 154 | 6c | l |
| 13 | 0d | 0D | CR(回车) | 45 | 055 | 2d | - | 77 | 115 | 4d | M | 109 | 155 | 6d | m |
| 14 | 0e | 0E | SO(移入) | 46 | 056 | 2e | . | 78 | 116 | 4e | N | 110 | 156 | 6e | n |
| 15 | 0f | 0F | SI(移出) | 47 | 057 | 2f | / | 79 | 117 | 4f | O | 111 | 157 | 6f | o |
| 16 | 10 | 10 | DLE(退出数据链) | 48 | 060 | 30 | 0 | 80 | 120 | 50 | P | 112 | 160 | 70 | p |
| 17 | 11 | 11 | DC1(设备控制1) | 49 | 061 | 31 | 1 | 81 | 121 | 51 | Q | 113 | 161 | 71 | q |
| 18 | 12 | 12 | DC2(设备控制2) | 50 | 062 | 32 | 2 | 82 | 122 | 52 | R | 114 | 162 | 72 | r |
| 19 | 13 | 13 | DC3(设备控制3) | 51 | 063 | 33 | 3 | 83 | 123 | 53 | S | 115 | 163 | 73 | s |
| 20 | 14 | 14 | DC4(设备控制4) | 52 | 064 | 34 | 4 | 84 | 124 | 54 | T | 116 | 164 | 74 | t |
| 21 | 15 | 15 | NAK(反确认) | 53 | 065 | 35 | 5 | 85 | 125 | 55 | U | 117 | 165 | 75 | u |
| 22 | 16 | 16 | SYN(同步空闲) | 54 | 066 | 36 | 6 | 86 | 126 | 56 | V | 118 | 166 | 76 | v |
| 23 | 17 | 17 | ETB(传输块结束) | 55 | 067 | 37 | 7 | 87 | 127 | 57 | W | 119 | 167 | 77 | w |
| 24 | 18 | 18 | CAN(取消) | 56 | 070 | 38 | 8 | 88 | 130 | 58 | X | 120 | 170 | 78 | x |
| 25 | 19 | 19 | EM(媒介结束) | 57 | 071 | 39 | 9 | 89 | 131 | 59 | Y | 121 | 171 | 79 | y |
| 26 | 1a | 1A | SUB(替换) | 58 | 072 | 3a | : | 90 | 132 | 5a | Z | 122 | 172 | 7a | z |
| 27 | 1b | 1B | ESC(退出) | 59 | 073 | 3b | ; | 91 | 133 | 5b | [ | 123 | 173 | 7b | { |
| 28 | 1c | 1C | FS(文件分隔符) | 60 | 074 | 3c | < | 92 | 134 | 5c | \ | 124 | 174 | 7c | | |
| 29 | 1d | 1D | GS(组分隔符) | 61 | 075 | 3d | = | 93 | 135 | 5d | ] | 125 | 175 | 7d | } |
| 30 | 1e | 1E | RS(记录分隔符) | 62 | 076 | 3e | > | 94 | 136 | 5e | ^ | 126 | 176 | 7e | ~ |
| 31 | 1f | 1F | US(单元分隔符) | 63 | 077 | 3f | ? | 95 | 137 | 5f | _ | 127 | 177 | 7f | DEL(删除) |
详细可参考ASCII码。
左侧
0〜31的代码表示控制字符,不可打印。十进制
32对应空格,后续依次是可打印的标点、数字、大写字母、小写字母以及若干符号。大写字母
A〜Z的 ASCII 码为65〜90。小写字母
a〜z为97〜122。数字字符
0〜9为48〜57,对应的大写和小写字母相差32。换行
\n的 ASCII 值是10。
#include <stdio.h>
int main()
{
int i = 0;
for (i = 32; i <= 127; i++)
{
printf("%c ", i);
if (i % 16 == 15)
{
printf("\n");
}
}
return 0;
}
字符串
C语言中的字符川使用双引号括起来的一串字符就被称为字符串,如:"abcdef",就是一个字符串。
字符串的打印格式可以使用 %s 来指定,也可以直接打印如下:
#include <stdio.h>
int main() {
printf("%s\n", "hello C");
printf("hello c");
return 0;
}
C语言字符串中一个特殊的地方,在字符串的末尾隐藏放着一个 \0 字符,这个 \0 字符是字符串的结束标志。
使用库函数 printf() 打印字符串或者 strlen() 计算字符串长度的时候,遇到 \0 的时候就动停止了。
C语言中也可以把一个字符串放在一个字符数组中:
#include <stdio.h>
int main() {
char arr1[] = {'a', 'b', 'c'};
char arr2[] = "abc";
printf("%s\n", arr1);
printf("%s\n", arr2);
}
运行后可以看到,arr1 字符数组在打印的时候,打印 a b c 之后打印了一些随机值,这是因为为 arr1 在末尾的地方没有 \0 字符作为结束标志,不知道何时停止。
但 arr2 的打印就是完全正常的,就是因为 arr2 数组是使用字符串常量初始化的,数组中有 \0 作为结束标志,打印可以正常停止。
如果在 arr1 数组中单独放一个 \0,那么都是打印到 \0 的时候就停止了。
转义字符
字符中有一组特殊的字符是转义字符,转义字符顾名思义:转变原来的意思的字符。
C语言中常见的转义字符有:
| 转义序列 | 说明 |
|---|---|
\? | 在书写连续多个问号时使用,防止它们被解析成“三字母词”(在现代编译器上已难以重现)。 |
| 表示字符常量 ' |
" | 在字符串内部表示双引号 |
\ | 表示反斜杠本身,避免被解析成转义序列起始符 |
| 警报;终端响铃或闪烁,或两者同时发生 |
\b | 退格;光标回退 1 个字符,但不删除字符 |
\f | 换页;光标移到下一页(现代系统多表现为垂直制表,类似 \v) |
\n | 换行 |
\r | 回车;光标回到当前行行首 |
\t | 水平制表;光标跳到下一个制表位,通常为 4/8 的倍数位置 |
\v | 垂直制表;光标移到下一行同一列的位置 |
\ddd | 1–3 位八进制数字表示字符,例如 \130 表示字符 X |
\xdd | 2 位十六进制数字表示字符,例如 \x30 表示字符 0 |
\0 | NULL 字符;作为字符串结束标志,其 ASCII 码为 0(属于 \ddd 形式的特例) |
详细可参考 转义字符。
语句
C语言的代码是由一条一条的语句构成的,C语言中的语句可为以下五类:
- 空语句。
- 表达式语句。
- 函数调用语句。
- 复合语句。
- 控制语句。
空语句
空语句是最简单的,一个分号就是一条语句,是空语句。
#include <stdio.h>
int main() {
;//空 语 句
return 0;
}
空语句一般出现的地方是:这里需要一条语句,但是这个语句不需要做任何事,就可以写一个空语。
表达式语句
表达式语句语句就是在表达式的后边加上分号。如下所示:
#include <stdio.h>
int main() {
int a = 20;
int b = 0;
b = a + 5; //表达式语句
return 0;
}
函数调用语句
函数调用的时候,也会加上分号,就是函数调用语句。
#include <stdio.h>
int Add(int x, int y) {
return x+y;
}
int main() {
printf("hehe\n"); //函数调用语句
int ret = Add(2, 3); //函数调用语句
return 0;
}
复合语句
复合语句其实就是代码块,成对括号中的代码就构成一个代码块,也被称为复合语句。
int main() {
int i = 0;
int arr[10] = {0};
for(i=0; i<10; i++) {
arr[i] = 10-i;
printf("%d\n", arr[i]);
}
return 0;
}
控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式择结构、循环结构),它们由特定的语句定义符组成,C语言有九种控制语句。
- 条件判断语句也叫分支语句:
if语句、switch语句。 - 循环执行语句:
do while语句、while语句、for语句。 - 转向语句:
break语句、goto语句、continue语句、return语句。
注释
注释是对代码的说明,编译器会忽略注释,也就是说,注释对实际代码没有影响。
注释是给程序员自己,或者其他程序员看的。好的注释可以帮我们更好的理解代码,但是也不要过度注释,不要写没必要的注释。
编译时,注释会被替换成一个空格。
/* 注 释 */
/*
这是一行注 释
*/
// printf("a ");
/*
printf("b ");
printf("c ");
*/
printf("d ");