一、什么是 C 语言?
C语言是一种较早的程序设计语言,诞生于1972年的贝尔实验室。1972 年,Dennis Ritchie 设计了C语言,它继承了B语言的许多思想,并加入了数据类型的概念及其他特性。C语言是一门面向过程的计算机编程语言。
虽然它很古老,但是不妨碍它的流行。C广泛应用于底层开发,它能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。
编程语言 | 年代 | 创建者 |
Algol | 1960 | International Group |
BCPL | 1967 | Martin Richard |
B | 1970 | Ken Thompson |
Traditional C | 1972 | Dennis Ritchie |
K & R C | 1978 | Kernighan & Dennis Ritchie |
ANSI C | 1989 | ANSI Committee |
ANSI/ISO C | 1990 | ISO Committee |
C99 | 1999 | Standardization Committee |
1.1. C 编辑器
要使用 C 就需要用于编写 C 代码的文本编辑器,这里我推荐微软出品的 Visual Studio Code
下载地址:https://code.visualstudio.com/Download
1.2. C 基本语法
下面是一段著名的输出 “Hello World” 的基本C代码:
#include <stdio.h>
int main() {
printf("Hello World!");
return 0;
}
代码说明:
- 第 1 行:#include <stdio.h> 是一个头文件库,可让我们使用输入和输出函数,例如 printf()(在第 3 行中使用)。头文件向 C++ 程序添加功能。
- 第 2 行:main() 称为函数。 其大括号 {} 内的任何代码都将被执行。
- 第 3 行:printf() 是用于将文本输出/打印到屏幕的函数。 在示例中,它将输出 Hello World。
- 第 4 行:return 0 结束 main() 函数。
- 第 5 行:不要忘记添加右大括号 } 以实际结束 main 函数。
二、基本用法
2.1. 变量
变量是存储数据值的容器,在 C 中,有不同类型的变量,例如:
- int:存储整数(整数),不带小数,例如 123 或 -123
- float:存储浮点数,带小数,例如 1.23 或 -1.23
- char:存储单个字符,例如“a”或“B”,字符值用单引号括起来
基本语法:
type variableName = value;
上述 type 是 C 类型之一(例如 int),variableName 是变量的名称(例如 x 或 myName 等可自定义), 等号用于为变量赋值。
示例:
int myNum = 12;
int myNum2; // 不赋值,然后再赋值
myNum2 = 12;
int myNum3 = 12; // myNum3 值为 12
myNum3 = 13; // 现在 myNum3 值为 13
float myFloatNum = 1.23; // 浮点数
char myLetter = 'D'; // 字符
int x = 1;
int y = 2;
int sum = x + y; // 添加变量相加
int x = 1, y = 2, z = 3; // 声明多个变量
2.2. 注释
// 这是一个注释
printf("Hello World!"); // 这是一个注释
/* 多行注释,上面的代码将打印出 Hello World!
到屏幕上,真是太棒了 */
2.3. 打印输出
printf("I am learning C.");
int testInteger = 5;
printf("Number = %d", testInteger);
float f = 1.23; // 浮点数
printf("Value = %f", f);
short a = 0b1010110; // 2 进制数字
int b = 02713; // 8 进制数字
long c = 0X1DAB83; // 16 进制数字
// 以 8 进制形似输出
printf("a=%ho, b=%o, c=%lo\n", a, b, c);
// 输出 => a=126, b=2713, c=7325603
// 以 10 进制形式输出
printf("a=%hd, b=%d, c=%ld\n", a, b, c);
// 输出 => a=86, b=1483, c=1944451
// 以 16 进制形式输出(字母小写)
printf("a=%hx, b=%x, c=%lx\n", a, b, c);
// 输出 => a=56, b=5cb, c=1dab83
// 以 16 进制形式输出(字母大写)
printf("a=%hX, b=%X, c=%lX\n", a, b, c);
// 输出 => a=56, b=5CB, c=1DAB83
2.4. 格式控制符
基本语法:
%[flag][width][.precision]type
- [ ] 表示此处的内容可有可无,是可以省略的。
- type (必须有)表示输出类型,比如 %d、%f、%c、%lf,type 就分别对应 d、f、c、lf;再如,%-9d 中 type 对应 d。
- width 表示最小输出宽度,也就是至少占用几个字符的位置;例如,%-9d 中 width 对应 9,表示输出结果最少占用 9 个字符的宽度。
格式控制符 | 说明 |
%c | 输出一个单一的字符 |
%hd %d %ld | 以十进制、有符号的形式输出 short、int、long 类型的整数 |
%hu %u %lu | 以十进制、无符号的形式输出 short、int、long 类型的整数 |
%ho %o %lo | 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数 |
%#ho %#o %#lo | 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数 |
%hx %x %lx | 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。 |
%hX %X %lX | |
%#hx %#x %#lx | 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。 |
%#hX %#X %#lX | |
%f %lf | 以十进制的形式输出 float 、double 类型的小数 |
%e %le %E %lE | 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。 |
%g %lg %G %lG | 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。 |
%s | 输出一个字符串 |
示例:
int a1=20, a2=345, a3=700;
int b1=56720, b2=9999, b3=20098;
int c1=233, c2=205, c3=1;
int d1=34, d2=0, d3=23;
printf("%-9d %-9d %-9d\n", a1, a2, a3);
printf("%-9d %-9d %-9d\n", b1, b2, b3);
printf("%-9d %-9d %-9d\n", c1, c2, c3);
printf("%-9d %-9d %-9d\n", d1, d2, d3);
上述输出结果:
20 345 700
56720 9999 20098
233 205 1
34 0 23
说明:%-9d 中,d 表示以 10 进制输出,9 表示最少占 9 个字符的宽度,宽度不足以空格补齐,- 表示左对齐。
2.5. 字符串
字符串用于存储文本/字符,C 没有 String 类型,使用 char 类型并创建一个字符 array。
char greetings[] = "Hello World!";
printf("%s", greetings); // 访问字符串
char greetings[] = "Hello World!";
printf("%c", greetings[0]); // 修改字符串
char greetings[] = "Hello World!";
greetings[0] = 'J';
printf("%s", greetings);
// 输出 "Jello World!"
char greetings[] = {'H','e','l','l','\0'};
printf("%s", greetings);
// 输出 "Hell!"
2.6. 条件判断
C 支持数学中的常见逻辑条件:
- 小于:a < b
- 小于或等于:a <= b
- 大于:a > b
- 大于等于:a >= b
- 等于 a == b
- 不等于:a != b
int mynum = 10;
if (mynum < 8) {
printf("small");
} else {
printf("big");
}
// 输出 -> "big"
int mynum = 12;
if (mynum < 10) {
printf("small");
} else if (mynum < 20) {
printf("middle");
} else {
printf("big");
}
// 输出 -> "big"
2.7. For 循环
如果确切知道要循环一段代码的次数时,请使用 for 循环。
基本语法:
for (表达式 1; 表达式 2; 表达式 3) {
// 要执行的代码块
}
- 表达式 1:在代码块执行之前执行(一次)。
- 表达式 2:定义了执行代码块的条件。
- 表达式 3:在代码块执行后(每次)执行。
示例:
int i;
for (i = 0; i < 5; i++) {
printf("%d\n", i);
}
int i;
for (i = 0; i < 10; i++) {
if (i == 4) {
break;
}
printf("%d\n", i);
}
// break 跳出循环
int i;
for (i = 0; i < 10; i++) {
if (i == 4) {
continue;
}
printf("%d\n", i);
}
// continue 跳出循环
2.8. While 循环
只要达到指定的条件,循环就可以执行一段代码。
基本语法:
while (条件) {
// 要执行的代码块
}
do {
// 要执行的代码块
} while (条件);
示例:
int i = 0;
while (i < 5) {
printf("%d\n", i);
i++;
}
int i = 0;
do {
printf("%d\n", i);
i++;
} while (i < 5);
int i = 0;
while (i < 10) {
if (i == 4) {
break;
}
printf("%d\n", i);
i++;
}
// break 跳出循环
int i = 0;
while (i < 10) {
i++;
if (i == 4) {
continue;
}
printf("%d\n", i);
}
// continue 跳出循环
注意:不要忘记增加条件中使用的变量,否则循环永远不会结束,成为“死循环”!
2.9. Switch 语句
基本语法:
switch(表达式) {
case 整型数值1:
// 代码块 1
break;
case 整型数值2:
// 代码块 2
break;
default:
// 代码块 3
}
示例:
int num = 2;
switch (num) {
case 1: printf("iam1"); break;
case 2: printf("iam2"); break;
default:
printf("iami");
}
// 输出 -> "iam2"
2.10. 数组
数组用于在单个变量中存储多个值,而不是为每个值声明单独的变量。要创建一个数组,请定义数据类型(如int)并指定数组的名称,后跟方括号[]。
- 更改数组元素:
int myNumbers[] = {25, 50, 75, 100};
myNumbers[0] = 33;
printf("%d", myNumbers[0]);
- 循环遍历数组:
int myNumbers[] = {25, 50, 75, 100};
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", myNumbers[i]);
}
- 设置数组大小:
// 声明一个由四个整数组成的数组:
int myNumbers[4];
// 添加元素
myNumbers[0] = 25;
myNumbers[1] = 50;
myNumbers[2] = 75;
myNumbers[3] = 100;
2.11. 枚举
C 中的枚举也称为枚举类型。它是一种用户定义的数据类型,由整数值组成,并为这些值提供有意义的名称。
- 定义枚举变量:
enum week a, b, c;
enum week { Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
- 枚举变量赋值:
enum week { Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;
// 或者
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;
示例:下面是一个简单的枚举示例应用,判断用户输入的是星期几。
#include <stdio.h>
int main(){
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
scanf("%d", &day);
switch(day){
case Mon: puts("Monday"); break;
case Tues: puts("Tuesday"); break;
case Wed: puts("Wednesday"); break;
case Thurs: puts("Thursday"); break;
case Fri: puts("Friday"); break;
case Sat: puts("Saturday"); break;
case Sun: puts("Sunday"); break;
default: puts("Error!");
}
return 0;
}
2.12. 用户输入
// 创建一个整数变量来存储我们从用户那里得到的数字
int myNum;
// 要求用户输入一个数字
printf("请输入一个数字: \n");
// 获取并保存用户输入的号码
scanf("%d", &myNum);
// 输出用户输入的数字
printf("您输入的数字: %d", myNum);
// 创建一个字符串
char firstName[30];
// 要求用户输入一些文本
printf("输入您的名字: \n");
// 获取并保存文本
scanf("%s", firstName);
// 输出文本
printf("Hello %s.", firstName);
三、运算符
运算符 | 含义 | 示例 |
+ | 加 | x + y |
- | 减 | x - y |
* | 乘 | x * y |
/ | 除 | x / y |
% | 取模 | x % y |
++ | 增量(将变量的值加 1) | ++ |
-- | 减量(将变量的值减 1) | --x |
&& | 与逻辑(如果两个语句都为真,则返回真) | x < 5 && x < 10 |
|| | 或逻辑(如果其中一个语句为真,则返回真) | x < 5 || x < 4 |
! | 非逻辑(反转结果,如果结果为真则返回假) | !(x < 5 && x < 10) |
== | 等于 | x == y |
!= | 不等于 | x != y |
> | 大于 | x > y |
< | 小于 | x < y |
>= | 大于或等于 | x >= y |
<= | 小于或等于 | x <= y |
& | 按位与操作,按二进制位进行"与"运算 | (A & B) 将得到 12 即为 0000 1100 |
| | 按位或运算符,按二进制位进行"或"运算 | (A | B) 将得到 61 即为 0011 1101 |
^ | 异或运算符,按二进制位进行"异或"运算 | (A ^ B) 将得到 49 即为 0011 0001 |
~ | 取反运算符,按二进制位进行"取反"运算 | (~A) 将得到 -61 即为 1100 0011 |
<< | 二进制左移运算符 | A << 2 将得到 240 即为 1111 0000 |
>> | 二进制右移运算符 | A >> 2 将得到 15 即为 0000 1111 |
示例:
unsigned int a = 60; /* 60 = 0011 1100 */
unsigned int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
printf("Line 1 - c 的值是 %d\n", c );
c = a | b; /* 61 = 0011 1101 */
printf("Line 2 - c 的值是 %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - c 的值是 %d\n", c );
c = ~a; /*-61 = 1100 0011 */
printf("Line 4 - c 的值是 %d\n", c );
c = a << 2; /* 240 = 1111 0000 */
printf("Line 5 - c 的值是 %d\n", c );
c = a >> 2; /* 15 = 0000 1111 */
printf("Line 6 - c 的值是 %d\n", c );
四、数据类型
数据类型 | 描述 |
char | 字符型 |
short | 短整型 |
int | 整型 |
long | 长整型 |
float | 单精度浮点型 |
double | 双精度浮点型 |
void | 无类型 |
数据类型 | 大小 | 取值范围 |
char | 1 字节 | −128 ~ 127 |
signed char | 1 字节 | −128 ~ 127 |
unsigned char | 1 字节 | 0 ~ 255 |
int | 2 到 4 字节 | −32,768 ~ 32,767 |
signed int | 2 字节 | −32,768 ~ 32,767 |
unsigned int | 2 字节 | 0 ~ 65,535 |
short int | 2 字节 | −32,768 ~ 32,767 |
signed short int | 2 字节 | −32,768 ~ 32,767 |
unsigned short int | 2 字节 | 0 ~ 65,535 |
long int | 4 字节 | -2,147,483,648 ~ 2,147,483,647 |
signed long int | 4 字节 | -2,147,483,648 ~ 2,147,483,647 |
unsigned long int | 4 字节 | 0 ~ 4,294,967,295 |
float | 4 字节 | |
double | 8 字节 | |
long double | 10 字节 |
格式说明符 | 数据类型 |
%d 或 %i | int 整数 |
%f | float 单精度的十进制类型 |
%lf | double 高精度浮点数据或数字 |
%c | char 字符 |
%s | 用于 strings 字符串 |
五、预处理器
指令 | 描述 |
#define | 定义宏 |
#include | 包含一个源代码文件 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则返回真 |
#ifndef | 如果宏没有定义,则返回真 |
#if | 如果给定条件为真,则编译下面代码 |
#else | #if 的替代方案 |
#elif | 如果 #if 条件为假,当前条件为真 |
#endif | 结束一个 #if……#else 条件编译块 |
#error | 当遇到标准错误时,输出错误消息 |
#pragma | 使用标准化方法,向编译器发布特殊的命令到编译器中 |
示例:
// 所有的 MAX_ARRAY_LENGTH 替换为 20
#define MAX_ARRAY_LENGTH 20
// 系统库中获取 stdio.h
#include <stdio.h>
// 本地目录中获取 myheader.h
#include "myheader.h"
#undef FILE_SIZE
#define FILE_SIZE 42 // 取消已定义并定义为 42
六、函数
6.1. 函数声明和定义
void myFunction() { // 声明 declaration
// 函数体(要执行的代码)(definition)
}
// 函数声明
void myFunction();
// 主要方法
int main() {
myFunction(); // --> 调用函数
return 0;
}
void myFunction() {// 函数定义
printf("晚上好!");
}
6.2. 调用函数
// 创建函数
void myFunction() {
printf("晚上好!");
}
int main() {
myFunction(); // 调用函数
myFunction(); // 可以被多次调用
return 0;
}
// 输出 -> "晚上好!"
// 输出 -> "晚上好!"
6.3. 数学函数
#include <math.h>
printf("%f", sqrt(16)); // 平方根
printf("%f", ceil(1.4)); // 四舍五入 (入)
printf("%f", floor(1.4)); // 四舍五入 (舍)
printf("%f", pow(4, 3)); // x(4)的y(3)次方
- abs(x) 绝对值
- acos(x) 反余弦值
- asin(x) 反正弦值
- atan(x) 反正切
- cbrt(x) 立方根
- cos(x) 余弦
- exp(x) Ex 的值
- sin(x) x 的正弦值
- tan(x) 角度的正切
七、文件处理
C 库中有许多函数可以打开/读取/写入/搜索和关闭文件。
7.1. 文件处理函数
函数 | 描述 |
fopen() | 打开新文件或现有文件 |
fprintf() | 将数据写入文件 |
fscanf() | 从文件中读取数据 |
fputc() | 将一个字符写入文件 |
fgetc() | 从文件中读取一个字符 |
fclose() | 关闭文件 |
fseek() | 将文件指针设置到给定位置 |
fputw() | 将整数写入文件 |
fgetw() | 从文件中读取一个整数 |
ftell() | 返回当前位置 |
rewind() | 将文件指针设置为文件的开头 |
7.2. 打开模式参数
参数 | 描述 |
r | 以读取模式打开一个文本文件,允许读取文件 |
w | 以写模式打开一个文本文件,允许写入文件 |
a | 以追加模式打开一个文本文件 |
如果文件不存在,则会创建一个新文件 | |
r+ | 以读写模式打开一个文本文件,允许读写文件 |
w+ | 以读写模式打开一个文本文件,允许读写文件 |
a+ | 以读写模式打开一个文本文件,允许读写文件 |
rb | 以读取模式打开二进制文件 |
wb | 以写入模式打开二进制文件 |
ab | 以追加模式打开二进制文件 |
rb+ | 以读写模式打开二进制文件 |
wb+ | 以读写模式打开二进制文件 |
ab+ | 以读写模式打开二进制文件 |
7.3. 打开文件示例
对文件执行所有操作后,必须关闭 fclose() 该文件。
#include<stdio.h>
void main( ) {
FILE *fp;
char ch;
fp = fopen("file_handle.c", "r");
while (1) {
ch = fgetc(fp);
if (ch == EOF)
break;
printf("%c", ch);
}
fclose(fp);
}
7.4. 写入文件示例
#include <stdio.h>
main() {
FILE *fp;
fp = fopen("file.txt", "w"); // 打开文件
// 将数据写入文件
fprintf(fp, "fprintf 的 Hello 文件..\n");
fclose(fp); // 关闭文件
}
7.5. 读取文件示例
#include <stdio.h>
main(){
FILE *fp;
char buff[255]; // 创建char数组存储文件数据
fp = fopen("file.txt", "r");
while(fscanf(fp, "%s", buff)!=EOF) {
printf("%s ", buff);
}
fclose(fp);
}