
一. C 语言是什么?
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程
C语言是一门面向过程的计算机编程语言,与C++、Java等面向对象的编程语言有所不同
二、C 语言的历史和辉煌
- C语言最初是作为Unix系统的开发工具而发明的

三、编译器的选择VS2022
C 语言是一门编译型计算机语言,C 语言源代码都是文本文件,文本文件本身无法执行,必须通过编译器翻译和链接器的链接,生成二进制的可执行文件,可执行文件才能执行
C 语言代码是放在.c 为后缀的文件中的,要得到最终运行的可执行程序,中间要经过编译和链接 2 个过程

注: 1. 每个源文件 (.c) 单独经过编译器处理生成对应的目标文件 (.obj 为后缀的文件)
2. 多个目标文件和库文件经过链接器处理生成对应的可执行程序 (.exe 文件)
3.1 编译器的对比
C 语言是一门编译型的计算机语言,需要依赖编译器将计算机语言转换成机器能够执行的机器指令。那我们常见的 C 语言编译器都有哪些呢?
- 比如: msvc、clang、gcc 就是一些常见的编译器,当然也有一些集成开发环境 如:VS2022、XCode、CodeBlocks、DevC++、Clion 等
- 集成开发环境 (IDE) 用于提供程序开发环境的应用程序,一般包括代码编辑器、 编译器 、 调试器 和 图形用户界面 等工具。 集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软 件服务套
VS2022 集成了 MSVC(安装包较大一些,安装简单,无需多余配置,使用起来非常方便)

XCode 集成了 clang(苹果电脑上的开发工具)

CodeBlocks 集成了 gcc(这个工具比较小众,需要配置环境,不太推荐)

Clion 是默认使用 CMake,编译器是可以配置的,工具是收费的

DevC++ 集成了 gcc(小巧,但是工具过于简单,对于代码风格的养成不好,一些竞赛使用)

3.2 VS2022 的优缺点
- 优点:
- VS2022 是一个主流的集成开发环境,企业中使用较为普遍
- VS2022 包含了:编辑器 + 编译器 + 调试器,功能强大,各工具无缝协同支持多场景开发
- 直接安装即可使用,基本不用额外配置环境,上手容易,一键完成安装省去繁琐步骤
- 默认界面是中文的,初学者友好,减少语言障碍,操作指引清晰易懂
- 缺点:
- 功能丰富,安装包大,占用空间多,对低配设备压力较大
四、VS项目 和 源文件、头文件介绍
在 VS 上写代码,我们是需要创建项目的,直接点创建新项目就可以了

然后选择C++后,点击创建空项目

填写项目名称然后修改位置即可

在项目中就可以添加源文件和头文件

C 语言把.c 为后缀的文件称为源文件,把.h 为后缀的文件称为头文件

五、第一个C语言程序
- 打印 hello C
#include <stdio.h>
int main()
{
printf("hello C\n");
return 0;
}
- 使用VS2022中创建项目和编写C代码的过程,并运行出结果。
- 在VS2022上运行代码的快捷键:
Ctrl + F5
六、main函数
每个 C 语言程序不管有多少行代码,都是从 main 函数开始执行的,main 函数是程序的入口,main 函数也被叫做:主函数。main 前面的 int 表示 main 函数执行结束的时候返回一个整型类型的值。所以在 main 函数的最后写 return 0; 正好前后呼应。
- main函数是程序的入口
- main函数有且仅有一个
- 即使一个项目中有多个.c文件,但是只能有一个main函数(因为程序的入口只能有一个)
第一次写代码,一些常见的错误总结:
- main 被写成了mian
- main后边的()漏掉了
- 代码中不能使用中文符号,比如括号和分号
- 一条语句结束后,有分号
七、printf 和 库函数
7.1 printf
printf("hello C\n");
- 代码中使用了
printf函数,实现了在屏幕上的信息的打印 - 这里简单的介绍一下 printf , printf 是一个库函数,它的功能是在标准输出设备(一般指屏幕)上进行信息的打印。上面的代码是使用 printf 函数打印字符串。只要把想要打印的一串字符放在双引号中并传递给printf函数就可以打印。printf 函数也可以用来打印其他类型的数据,比如:
int n = 100;
printf("%d\n", n); //printf打印整型
printf("%c\n", 'q'); //printf打印字符
printf("%lf\n", 3.14); //printf打印双精度浮点型
- 这里的
%d,%c等是占位符,会被后边的值替换 - 同时我们在使用库函数的时候,是需要包含头文件的,比如:
printf函数需要包含的就是stdio.h(Standard Input and Output Header) 这个头文件,具体的方法就是:
#include <stdio.h>
7.2 库函数
那什么是库函数呢?
为了不再重复实现常见的代码,让程序员提升开发效率,C语言标准规定了一组函数,这些函数再由不同的编译器厂商根据标准进行实现,提供给程序员使用。这些函数组成了一个函数库,被称为标准库,这些函数也被称为库函数
一个系列的库函数一般会声明在同一个头文件中,所以库函数的使用,要包含对应的头文件
库函数比较多,后期慢慢来介绍,提前了解可参考链接:cplusplus
八、数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
//C语言有没有字符串类型?
- 为什么出现这么的类型?
- 每种类型的大小是多少?
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(long double));
return 0;
}

注意:存在这么多的类型,其实是为了更加丰富的表达生活中的各种值。
类型的使用
char ch = 'w';
int weight = 120;
int salary = 20000;
九、变量、常量
- 生活中的有些值是不变的(比如:圆周率,性别(?),身份证号码,血型等等)
- 有些值是可变的(比如:年龄,体重,薪资)。
不变的值,C语言中用 常量 的概念来表示,变得值C语言中用 变量 来表示。
9.1 变量的分类
- 局部变量
- 全局变量
#include <stdio.h>
int global = 2025; // 全局变量
int main()
{
int local = 2026; // 局部变量
// 下面定义的global会不会有问题?
int global = 2027; // 局部变量
printf("global = %d\n", global);
return 0;
}
- 总结:
- 上面的局部变量
global变量的定义其实没有什么问题的! - 当局部变量和全局变量同名的时候, 局部变量优先使用
- 上面的局部变量
9.2 变量的使用
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:> ");
scanf("%d %d", &a, &b);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
9.3 变量的作用域和生命周期
作用域
- 作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效可用的
- 而限定这个名字的可用性的代码范围就是这个名字的 作用域
- 局部变量的作用域是变量所在的 局部范围 ,全局变量的作用域是 整个工程
生命周期
- 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
- 局部变量的生命周期是: 进入作用域 生命周期开始, 出作用域 生命周期结束。
- 全局变量的生命周期是: 整个程序的生命周期 。
9.4 常量
C语言中的常量和变量的定义的形式有所差异。
C语言中的常量分为以下几种:
- 字面常量
const修饰的常变量#define定义的标识符常量- 枚举常量
#include <stdio.h>
#define MAX 100 // #define定义的标识符常量
// 枚举常量定义
enum Sex
{
MALE, // 枚举常量,默认值为0
FEMALE, // 枚举常量,默认值为1
SECRET // 枚举常量,默认值为2
};
int main()
{
// 1. 字面常量:直接书写的常量值(数值、字符、字符串等)
printf("----- 1. 字面常量示例 -----\n");
printf("数值字面常量:%f(浮点数)、%d(整数)\n", 3.14, 1000);
printf("字符字面常量:%c\n", '!'); // 单个字符
printf("字符串字面常量:%s\n", "Literal"); // 字符串(字符数组)
// 2. const修饰的常变量:值不可修改的变量(本质是变量,仍占内存)
printf("\n----- 2. const修饰的常变量示例 -----\n");
const float pai = 3.14f; // 定义常变量pai
// pai = 5.14; // 错误!常变量的值无法修改(编译报错)
printf("const常变量pai的值:%f\n", pai);
// 3. #define定义的标识符常量:预处理阶段替换,无类型
printf("\n----- 3. #define标识符常量示例 -----\n");
printf("MAX的值:%d\n", MAX); // MAX会被替换为100
int arr[MAX] = {0}; // 可用作数组大小(编译时视为100)
printf("数组arr的大小:%zu字节\n", sizeof(arr)); // 100*4=400(int占4字节)
// 4. 枚举常量:enum定义的常量,值默认从0开始
printf("\n----- 4. 枚举常量示例 -----\n");
enum Sex gender = MALE; // 定义枚举变量,赋值枚举常量
printf("MALE的值:%d\n", MALE); // 输出0
printf("FEMALE的值:%d\n", FEMALE); // 输出1
printf("SECRET的值:%d\n", SECRET); // 输出2
printf("枚举变量gender的值:%d\n", gender); // 输出0(等于MALE)
return 0;
}
十、字符串 + 转义字符 + 注释
10.1 字符串
由 双引号(Double Quote) 引起来的一串字符称为 字符串字面量(String Literal),简称字符串。
注意:
- 字符串的末尾会隐藏一个
\0转义字符,\0是字符串的结束标志(不算作字符串内容)。
- 字符串的末尾会隐藏一个
代码示例(对比 \0 的影响):
#include <stdio.h>
// 下面的字符串哪里不一样?为什么?(结合'\0'的意思分析)
int main()
{
char arr1[] = "bit";
char arr2[] = {'b', 'i', 't'};
char arr3[] = {'b', 'i', 't', '\0'};
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
return 0;
}
10.2 转义字符
- 转义字符:通过反斜杠
\改变字符的原始含义(如让特殊字符变普通,或赋予普通字符特殊功能)。
问题代码(未转义,输出异常):
#include <stdio.h>
int main()
{
printf("c:\code\test.c\n");
return 0;
}
(运行后可能输出乱码,因为 \c、\t 被解析为转义字符)
修正代码(用 \ 转义,还原路径):
#include <stdio.h>
int main()
{
printf("c:\\code\\test.c\n");
return 0;
}
运行结果示例:
c:\code\test.c
请按任意键继续. . .
- 说明:
- 转义后,
\不再被解析为转义符号,而是作为普通路径分隔符,输出正常字符串。
- 转义后,
常见的转义字符如下
| 转义字符 | 释义 |
|---|---|
| \? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
| \’ | 用于表示字符常量’ |
| \" | 用于表示一个字符串内部的双引号 |
| \\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
| \a | 警告字符,蜂鸣 |
| \b | 退格符 |
| \f | 进纸符 |
| \n | 换行 |
| \r | 回车 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ddd | ddd表示1~3个八进制的数字,如:\130 X |
| \xdd | dd表示2个十六进制数字,如:\x30 0 |
#include <stdio.h>
int main()
{
// 问题1:在屏幕上打印一个单引号,怎么做?
// 问题2:在屏幕上打印一个字符串,字符串的内容是一个双引号,怎么做?
printf("%c\n", '\'');
printf("%s\n", "\"");
return 0;
}
//程序输出什么?
#include <stdio.h>
#include <string.h>
int main()
{
printf("%d\n", strlen("abcdef"));
// \32被解析成一个转义字符, 而不是\328
printf("%d\n", strlen("c:\test\328\test.c"));
return 0;
}
// 答案
6
14
10.3 注释
#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
/*C语言风格注释
int Sub(int x, int y)
{
return x-y;
}
*/
int main()
{
//C++注释风格
//int a = 10;
//调用Add函数,完成加法
printf("%d\n", Add(1, 21));
return 0;
}
- 注释有两种风格:
- C语言风格的注释
/*xxxxxx*/- 缺陷:不能嵌套注释
- C++风格的注释
//xxxxxxx- 可以注释一行也可以注释多行
- C语言风格的注释
十一、选择语句
- 在 C 语言中,选择语句主要有以下三种:单分支
if语句、双分支if-else语句、多分支switch语句。下面分别通过实际场景举例说明:
11.1 单分支 if 语句
作用:当指定条件为“真”(非 0)时,执行对应的代码块;条件为“假”(0)时,不执行任何操作。
语法:
if (条件表达式) {
// 条件为真时执行的代码
}
- 示例:判断一个整数是否为正数
#include <stdio.h>
int main() {
int num = 15;
// 单分支if:仅当num>0时执行打印
if (num > 0) {
printf("%d 是正数\n", num); // 输出:15 是正数
}
return 0;
}
11.2 双分支 if-else 语句
作用:条件为“真”时执行
if块中的代码,条件为“假”时执行else块中的代码(两个分支必执行其一)。语法:
if (条件表达式) {
// 条件为真时执行的代码
} else {
// 条件为假时执行的代码
}
- 示例:判断一个整数是偶数还是奇数
#include <stdio.h>
int main() {
int num = 7;
// 双分支if-else:二选一执行
if (num % 2 == 0) { // 若能被2整除
printf("%d 是偶数\n", num);
} else { // 否则
printf("%d 是奇数\n", num); // 输出:7 是奇数
}
return 0;
}
11.3 多分支 switch 语句
作用:通过匹配“常量表达式”的值,执行对应的
case分支;若没有匹配的 case,则执行default分支(可选)注意:每个 case 后需用
break终止当前分支,否则会出现“穿透”(继续执行下一个 case)语法:
switch (表达式) { // 表达式必须是整数/字符/枚举类型
case 常量1:
// 匹配常量1时执行的代码
break;
case 常量2:
// 匹配常量2时执行的代码
break;
// ... 更多case
default:
// 无匹配时执行的代码(可选)
break;
}
- 示例:根据分数输出评级(0-100分)
#include <stdio.h>
int main() {
int score = 85;
// 将分数按10分一段简化(85→8)
int grade = score / 10;
switch (grade) {
case 10: // 100分
case 9: // 90-99分
printf("成绩评级:A(优秀)\n");
break;
case 8: // 80-89分
printf("成绩评级:B(良好)\n"); // 输出:成绩评级:B(良好)
break;
case 7: // 70-79分
case 6: // 60-69分
printf("成绩评级:C(及格)\n");
break;
default: // 0-59分
printf("成绩评级:D(不及格)\n");
break;
}
return 0;
}
11.4 总结
| 语句类型 | 适用场景 | 核心特点 |
|---|---|---|
单分支 if | 仅需处理“满足条件”的情况 | 条件为假时不执行任何操作 |
双分支 if-else | 需在两种互斥情况中选择其一 | 必执行且仅执行一个分支 |
多分支 switch | 基于常量值的多条件匹配 | 效率高于多嵌套 if-else,但仅支持特定类型 |
十二、循环语句
- C语言中如何实现循环呢?
- while 语句
- for 语句
- do … while 语句
12.1 while 语句示例
- 语法:
while (条件表达式) { 循环体 } - 逻辑:先判断条件,若成立则执行循环体(条件不成立时,循环体可能一次都不执行)。
#include <stdio.h>
int main() {
int i = 1; // 初始化计数器
int sum = 0; // 初始化累加和
while (i <= 10) { // 条件:i 不超过 10
sum += i; // 累加 i 的值
i++; // 更新计数器(必须,否则会无限循环)
}
printf("1-10 的和:%d\n", sum); // 输出:55
return 0;
}
12.2 for 语句示例
- 语法:
for (初始化表达式; 条件表达式; 更新表达式) { 循环体 } - 逻辑:初始化、条件判断、更新操作集中定义,适合 已知循环次数 的场景。
#include <stdio.h>
int main() {
int sum = 0;
// ①初始化 i=1 ②判断 i<=10 ③每次循环后 i++
for (int i = 1; i <= 10; i++) {
sum += i; // 累加 i 的值
}
printf("1-10 的和:%d\n", sum); // 输出:55
return 0;
}
12.3 do…while 语句示例
- 语法:
do { 循环体 } while (条件表达式); - 逻辑:先执行循环体,再判断条件(循环体至少执行一次)
#include <stdio.h>
int main() {
int num;
do {
printf("请输入一个正数:");
scanf("%d", &num); // 先执行输入操作
} while (num <= 0); // 再判断:若输入非正数,重复循环
printf("你输入了正数:%d\n", num);
return 0;
}
12.4 总结
| 循环语句 | 执行顺序 | 循环体最少执行次数 | 典型适用场景 |
|---|---|---|---|
while | 先判断,后执行 | 0次 | 未知循环次数(如等待用户输入) |
do...while | 先执行,后判断 | 1次 | 必须至少执行一次的场景(如输入验证) |
for | 初始化→判断→执行→更新 | 0次 | 已知循环次数(如遍历固定范围) |
十三、函数
函数是C语言中实现模块化编程的核心,它将一段独立功能的代码封装起来,可被重复调用,提高代码复用性和可读性
13.1 函数的分类
- 库函数:C语言标准库提供的现成函数(如
printf、scanf、strlen等),需包含对应头文件才能使用 - 自定义函数:程序员根据需求自行设计的函数,由返回类型、函数名、参数列表和函数体组成
13.2 函数的定义与调用
- 语法:
返回类型 函数名(参数列表) {
// 函数体(实现功能的代码)
return 返回值; // 与返回类型匹配
}
示例1:基础自定义函数(两数相加)
#include <stdio.h>
// 函数定义:实现两数相加
int Add(int x, int y) { // x、y为形式参数(形参)
int z = x + y;
return z; // 返回计算结果
}
int main() {
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:> ");
scanf("%d %d", &num1, &num2); // 修正原代码中的&a、&b为&num1、&num2
// 函数调用:num1、num2为实际参数(实参)
sum = Add(num1, num2);
printf("sum = %d\n", sum);
return 0;
}
13.3 函数的参数与返回值
- 形参:函数定义时的参数,仅在函数内部有效(相当于局部变量)
- 实参:函数调用时传递的参数,需与形参类型、数量匹配
- 返回值:通过
return语句传递给调用者,若无需返回值,返回类型为void
示例2:无返回值函数(打印信息)
#include <stdio.h>
// 无返回值(void),无参数
void PrintWelcome() {
printf("===== 欢迎使用计算器 =====\n");
// 无需return语句
}
int main() {
PrintWelcome(); // 调用无参函数
return 0;
}
13.4 函数的声明
- 若函数定义在调用之后,需提前声明函数(告诉编译器函数的存在)
示例3:函数声明与调用
#include <stdio.h>
// 函数声明(分号结尾)
int Max(int a, int b);
int main() {
int x = 10, y = 20;
printf("较大值:%d\n", Max(x, y)); // 调用前已声明,可正常使用
return 0;
}
// 函数定义(在调用之后)
int Max(int a, int b) {
return a > b ? a : b;
}
13.5 嵌套调用与递归
- 嵌套调用:函数内部调用其他函数。
- 递归:函数自身调用自身(需有终止条件,避免无限递归)。
示例4:递归函数(计算n的阶乘)
#include <stdio.h>
// 递归计算n!(n的阶乘)
int Factorial(int n) {
if (n == 0) { // 终止条件:0! = 1
return 1;
}
return n * Factorial(n - 1); // 自身调用
}
int main() {
printf("5的阶乘:%d\n", Factorial(5)); // 输出:120
return 0;
}
十四、数组
- 要存储1-10的数字,怎么存储?
14.1 数组定义
- 数组是相同类型元素的有序集合,定义时需指定元素类型、数组名和长度(常量表达式),语法为:
数据类型 数组名[元素个数];
- 以下是常见的数组定义与初始化方式:
基本定义(指定长度 + 完全初始化)
int arr1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 整型数组,10个元素 char arr2[5] = {'a', 'b', 'c', 'd', 'e'}; // 字符数组,5个元素 float arr3[3] = {3.14f, 2.71f, 1.618f}; // 单精度浮点型数组不完全初始化(未赋值元素自动为0)
int arr4[5] = {1, 2}; // 前2个元素为1、2,后3个自动补 0 → {1,2,0,0,0} char arr5[4] = {'x'}; // 第一个元素为'x',其余补 0 → {'x',0,0,0}省略长度(编译器自动计算)
初始化时若已明确元素个数,可省略[]中的长度:int arr6[] = {10, 20, 30}; // 长度自动为3 → 等价于int arr6[3] = {10,20,30} char arr7[] = {'a', 'b', 'c'}; // 长度为3字符串数组(特殊的字符数组)
用双引号初始化时,编译器会自动添加结束符\0,长度需多留1位:char str1[6] = "hello"; // 实际存储:'h','e','l','l','o','\0'(长度6) char str2[] = "world"; // 自动计算长度为6(含'\0')
- 注意:
- 数组长度必须是常量表达式(如
10、3+2),不能用变量(C99前不支持变长数组) - 数组元素通过下标访问,下标从
0开始(如arr1[0]是第一个元素)
- 数组长度必须是常量表达式(如
14.2 数组的使用
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(i=0; i<10; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
十五、操作符
算术操作符:
+ - * / %移位操作符:
>> <<位操作符:
& ^ |赋值操作符:
= += -= *= /= &= ^= |= >>= <<=单目操作符:
| 操作符 | 释义 |
|---|---|
! | 逻辑反操作 |
~ | 按位取反 |
++ | 自增 |
-- | 自减 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
-> | 结构体成员访问(指针操作符) |
.(点) | 结构体成员访问 |
关系操作符:
>、>=、<、<=、!=(用于测试“不相等”)、==(用于测试“相等”)逻辑操作符:
&&(逻辑与) 、||(逻辑或)条件操作符:
exp1 ? exp2 : exp3逗号表达式:
exp1, exp2, exp3,...expN下标引用、函数调用和结构成员:
[]、()、.、->
十六、常见关键字
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
16.1 类型相关关键字
用于定义/修饰数据类型、构建自定义复合类型:
| 分类 | 关键字列表 |
|---|---|
| 基础数据类型 | char、int、short、long、float、double |
| 符号修饰 | signed(有符号,默认)、unsigned(无符号) |
| 空类型 | void(表示“无类型”,如无返回值函数、空指针) |
| 类型约束 | const(只读常变量,值不可修改) |
| 存储修饰 | static(静态存储,延长生命周期/限制作用域) |
| 自定义类型 | enum(枚举)、union(共用体)、struct(结构体) |
| 类型辅助 | auto(局部变量默认修饰,可省略)、typedef(类型重命名,如typedef int INT;) |
16.2 循环控制关键字
- 用于实现重复执行的逻辑(循环结构):
break(跳出循环/switch)、continue(跳过本次循环,进入下次)、do(do-while循环开头)、while(while循环)、for(for循环)
16.3 分支控制关键字
- 用于实现条件判断(选择执行不同代码块):
if(条件判断)、else(if的互补分支)、switch(多分支匹配)、case(switch的分支标签)、default(switch的默认分支)、goto(无条件跳转,谨慎使用)
16.4 函数与链接关键字
| 分类 | 关键字 & 作用 |
|---|---|
| 函数核心 | return(函数返回值,结束函数执行) |
| 跨文件共享 | extern(声明外部符号,使变量/函数可跨文件访问) |
16.5 特殊用途关键字
| 关键字 | 作用简述 |
|---|---|
register | 建议编译器将变量存储到寄存器(加速访问,现代编译器已智能优化) |
sizeof | 计算类型/变量的字节大小(如 sizeof(int) 获取int占多少字节) |
volatile | 提醒编译器避免优化(用于并发/硬件编程) |
16.6 举例
16.6.1 关键字 typedef
typedef 顾名思义是类型定义,这里更准确理解为 类型重命名
比如:
// 将unsigned int 重命名为uint_32,所以uint_32是一个类型名
typedef unsigned int uint_32;
int main()
{
// 变量num1和num2,这两个变量的类型是一样的
unsigned int num1 = 0;
uint_32 num2 = 0;
return 0;
}
16.6.2 关键字 static
在C语言中:
static是用来修饰变量和函数的- 修饰局部变量 - 静态局部变量
// 代码1
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//运行结果
1 1 1 1 1 1 1 1 1 1
// 代码2
#include <stdio.h>
void test()
{
// static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//运行结果
1 2 3 4 5 6 7 8 9 10
结论:
static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,直到程序结束,生命周期才结束。- 修饰全局变量 - 静态全局变量
// 代码1
// add.c
int g_val = 2018;
// test.c
#include <stdio.h>
int main()
{
printf("%d\n", g_val);
return 0;
}
//运行结果:
2018
// 代码2
// add.c
static int g_val = 2018;
// test.c
#include <stdio.h>
int main()
{
printf("%d\n", g_val);
return 0;
}
//运行结果:
编译错误,提示“未定义标识符g_val”(静态全局变量仅能在本源文件使用)。
- 修饰函数
// 代码1
// add.c
int Add(int x, int y)
{
return x+y;
}
// test.c
#include <stdio.h>
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//运行结果:
5
// 代码2
// add.c
static int Add(int x, int y)
{
return x+y;
}
// test.c
#include <stdio.h>
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//运行结果:
编译错误,提示“未定义标识符Add”(静态函数仅能在本源文件使用)。
16.6.3 #define 定义常量和宏
// #define定义标识符常量
#define MAX 1000
// #define定义宏
#define ADD(x, y) ((x)+(y))
#include <stdio.h>
int main()
{
int sum = ADD(2, 3);
printf("sum = %d\n", sum);
sum = 10*ADD(2, 3);
printf("sum = %d\n", sum);
return 0;
}
//运行结果:
sum = 5
sum = 50
十七、指针
内存可以理解为一条连续的“存储带”,整个空间按“字节”划分成一个个独立的存储单元,就像数组中按顺序排列的元素
每个字节单元都有一个唯一的编号,这个编号就是内存地址(类似数组的索引)。程序运行时,所有数据(变量、函数等)都要存放在这些字节单元中,而要访问这些数据,必须通过它们的地址
指针的核心逻辑就在于此:指针是一种特殊的变量,它里面存储的不是普通数据,而是某个内存单元的地址。通过指针中存储的地址,我们就能直接找到并访问对应的内存单元,就像用门牌号找到具体的房间一样
简单说:内存是带编号的字节集合,地址是编号,指针是存放编号的“小本子”,通过这个“小本子”能快速找到目标内存
17.1 指针的基本使用(整型指针示例)
#include <stdio.h>
int main()
{
int num = 10; // 定义整型变量 num,存储值 10
int *p = # // 定义指针 p,存储 num 的地址(& 为取地址符)
*p = 20; // 通过指针修改 num 的值(* 为解引用操作,访问 p 指向的内存)
return 0;
}
17.2 指针的类型推广(字符指针示例)
- 指针适配任意数据类型,逻辑一致:
#include <stdio.h>
int main()
{
char ch = 'w'; // 字符变量 ch,存储 'w'
char* pc = &ch; // 字符指针 pc,存储 ch 的地址
*pc = 'q'; // 通过指针修改 ch 的值为 'q'
printf("%c\n", ch); // 输出:q
return 0;
}
//运行结果
q
17.3 指针变量的大小
- 测试不同类型指针的大小:
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(char *)); // 指针大小(与类型无关,与平台位数相关)
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}

- 结论:
- 32位平台:指针变量大小为 4字节(存储32位地址)
- 64位平台:指针变量大小为 8字节(存储64位地址)
十八、结构体
18.1 结构体的定义
- 语法:
struct 结构体名 {
数据类型 成员名1;
数据类型 成员名2;
// ... 更多成员
};
示例:描述学生信息
// 定义结构体类型 struct Stu(注意末尾分号)
struct Stu
{
char name[20]; // 名字(字符数组,最多存19个字符+结束符\0)
int age; // 年龄(整型)
char sex[5]; // 性别(字符数组,如"男"/"女")
char id[15]; // 学号(字符数组)
};
18.2 结构体的初始化
- 定义结构体变量时,可直接赋值初始化,支持 顺序初始化 和 指定成员初始化
- 顺序初始化(按成员声明顺序赋值)
// 定义并初始化结构体变量 s
struct Stu s = {"张三", 20, "男", "20180101"};
- 指定成员初始化(灵活赋值,不要求顺序)
struct Stu s = {
.name = "李四",
.age = 21,
.sex = "女",
.id = "20180102"
};
18.3 结构体成员的访问
- 访问结构体成员有两种方式:
.操作符:用于结构体变量直接访问成员->操作符:用于结构体指针间接访问成员(需解引用指针)
示例:打印结构体信息
#include <stdio.h>
// 结构体定义(可写在main函数外,全局可见)
struct Stu
{
char name[20];
int age;
char sex[5];
char id[15];
};
int main()
{
// 1. 定义并初始化结构体变量 s
struct Stu s = {"张三", 20, "男", "20180101"};
// 2. 用 . 操作符访问成员(变量直接访问)
printf("name = %s age = %d sex = %s id = %s\n",
s.name, s.age, s.sex, s.id);
// 3. 定义结构体指针 ps,指向 s 的地址(&s 取地址)
struct Stu *ps = &s;
// 4. 用 -> 操作符访问成员(指针间接访问)
printf("name = %s age = %d sex = %s id = %s\n",
ps->name, ps->age, ps->sex, ps->id);
return 0;
}
//运行结果:
name = 张三 age = 20 sex = 男 id = 20180101
name = 张三 age = 20 sex = 男 id = 20180101
18.4 结构体的应用场景
- 描述复杂对象:如学生、员工、书籍、几何图形(点、矩形等)
- 作为函数参数/返回值:传递整个复合数据(建议用指针传递,避免拷贝开销)
- 构建复杂数据结构:如链表、队列、树等(通过指针连接结构体)
18.5 拓展:结构体数组
- 若需描述多个学生,可定义结构体数组:
#include <stdio.h>
struct Stu
{
char name[20];
int age;
char sex[5];
char id[15];
};
int main()
{
// 定义并初始化结构体数组(3个学生)
struct Stu class[3] = {
{"张三", 20, "男", "20180101"},
{"李四", 21, "女", "20180102"},
{"王五", 19, "男", "20180103"}
};
// 遍历数组,打印每个学生信息
for (int i = 0; i < 3; i++) {
printf("第%d个学生:name=%s, age=%d, sex=%s, id=%s\n",
i+1, class[i].name, class[i].age, class[i].sex, class[i].id);
}
return 0;
}
//运行结果:
第1个学生:name=张三, age=20, sex=男, id=20180101
第2个学生:name=李四, age=21, sex=女, id=20180102
第3个学生:name=王五, age=19, sex=男, id=20180103
结构体让C语言具备描述复杂世界的能力,是实现模块化、面向对象思想的基础,务必熟练掌握!
结尾
基础筑牢,代码力拉满!动手实践,让这些知识 “活” 起来吧~
要是你觉得这些分享还算不错,不妨点个关注;顺手点赞、收藏一下,下次想找过来的时候,就不会迷路啦~

浙公网安备 33010602011771号