C语言程序设计基础核心考点总结
C语言的核心在于 “结构化” 和 “高效直接地操作内存”,所有考点都围绕这两个核心展开。

(图片来源网络,侵删)
第一部分:C语言概述与环境
-
C语言的特点
- 高级语言与低级语言结合:既有高级语言的易读性,又有低级语言(如汇编)对硬件的操作能力。
- 结构化程序设计语言:支持函数、顺序、选择、循环三种基本结构。
- 可移植性好:标准C程序在不同平台上基本无需修改即可编译运行。
- 执行效率高:生成的目标代码质量高,运行速度快。
- 直接操作内存:通过指针可以直接访问和操作内存地址。
-
C程序的基本结构
#include <stdio.h>:包含标准输入输出库,提供printf,scanf等函数。main()函数:程序的入口点,一个C程序有且仅有一个main函数。- 函数体:由 括起来,包含变量声明和执行语句。
- 注释: (单行) 和 (多行)。
-
C程序的编译与执行过程
- 预处理:处理 开头的指令(如
#include,#define),生成.i文件。 - 编译:将预处理后的代码翻译成汇编代码,生成
.s文件。 - 汇编:将汇编代码翻译成机器码,生成
.o或.obj目标文件。 - 链接:将多个目标文件和所需的库文件链接在一起,生成最终的可执行文件(
.exe或无后缀)。
- 预处理:处理 开头的指令(如
第二部分:数据类型、运算符与表达式
-
基本数据类型
(图片来源网络,侵删)- 整型:
int: 通常为4字节。short: 通常为2字节。long: 通常为4字节(C99/C11后可能为8字节)。long long: C99引入,通常为8字节。- 有符号 (
signed) vs 无符号 (unsigned)。
- 浮点型:
float: 单精度,通常4字节,约6-7位有效数字。double: 双精度,通常8字节,约15-16位有效数字。long double: 长双精度,精度更高。
- 字符型:
char: 通常1字节,存储一个字符(如 'A')或小整数。
- 整型:
-
常量与变量
- 常量:程序运行期间不能改变的值。
- 整型常量:
10,0x10(十六进制),010(八进制)。 - 实型常量:
14,14e0(科学计数法)。 - 字符常量:
'a'。 - 字符串常量:
"hello"(本质是字符数组,末尾有隐含的\0)。 - 符号常量:
#define PI 3.14或const double PI = 3.14;。
- 整型常量:
- 变量:程序运行期间可以改变的值。
- 定义与声明:
int a;是定义,extern int a;是声明。 - 命名规则:由字母、数字、下划线组成,不能以数字开头,不能是关键字。
- 定义与声明:
- 常量:程序运行期间不能改变的值。
-
运算符
- 算术运算符:, , , , (取模)。
- 考点: 对于整数是整除,对于浮点是除法。 只能用于整数。
- 关系运算符:
>,<,>=,<=, , 。- 考点: (判断是否相等) 和 (赋值) 是常见混淆点。
- 逻辑运算符:
&&(与), (或), (非)。- 考点:短路求值。
a && b,a为假,则b不再计算。a || b,a为真,则b不再计算。
- 考点:短路求值。
- 位运算符:
&(按位与), (按位或),^(按位异或), (按位取反),<<(左移),>>(右移)。- 考点:常用于底层操作,如清零、置位、交换变量等。
- 赋值运算符:, , , , , ,
&=, ,^=,<<=,>>=。 - 自增自减运算符:, 。
- 考点:前置 (
++i) 和后置 (i++) 的区别,前置是先使用后增/减,后置是先增/减后使用。在复杂的表达式中,这是高频考点和易错点。
- 考点:前置 (
- 条件运算符(三目运算符):
exp1 ? exp2 : exp3。- 考点:
if-else语句的简化写法。
- 考点:
- 算术运算符:, , , , (取模)。
-
数据类型转换
- 隐式转换(自动转换):
- 规则:运算时,数据类型向精度更高、范围更广的类型转换,顺序大致为:
char->short->int->unsigned->long->unsigned long->float->double。 - 考点:
int和float运算,int会被提升为float。int和double运算,int会被提升为double。
- 规则:运算时,数据类型向精度更高、范围更广的类型转换,顺序大致为:
- 显式转换(强制类型转换):
- 语法:
(type)expression。 - 考点:
(double)5 / 2结果是5,而5 / 2结果是2。
- 语法:
- 隐式转换(自动转换):
第三部分:输入与输出
-
printf()函数
(图片来源网络,侵删)- 作用:格式化输出到标准输出(通常是屏幕)。
- 格式控制符:
%d: 输出int。%c: 输出char。%f: 输出float/double(默认6位小数)。%lf: 输入double时使用(printf中%f和%lf通常效果一样,但%lf是标准写法)。%s: 输出字符串。%p: 输出地址。%x: 以十六进制格式输出整数。
- 考点:格式控制符与变量类型不匹配会导致未定义行为或错误输出。
-
scanf()函数- 作用:从标准输入(通常是键盘)读取数据。
- 格式控制符:与
printf类似,但输入double必须用%lf。 - 考点:
- 变量前必须加
&(取地址符),除了数组名和指针变量。scanf("%d", &a);是正确的,scanf("%d", a);是错误的。 - 缓冲区问题:
scanf读取时会留下换行符\n在输入缓冲区中,可能会影响后续的getchar()或gets(),常用getchar()或fflush(stdin)(非标准,但常用) 清空缓冲区。
- 变量前必须加
第四部分:流程控制语句
-
选择结构
if-else语句:- 单分支:
if (condition) { ... } - 双分支:
if (condition) { ... } else { ... } - 多分支:
if-else if-else。 - 考点:
if后面的条件表达式必须用括号括起来。if和else的配对原则:else总是和它最近的、尚未配对的if配对。
- 单分支:
switch语句:- 语法:
switch (expression) { case const1: ... break; case const2: ... break; default: ... } - 考点:
expression的结果必须是int或char类型。case后的值必须是常量或常量表达式。break语句至关重要,如果没有break,程序会继续执行下一个case,造成“case穿透”。default可选,处理所有未匹配的情况。
- 语法:
-
循环结构
while循环:while (condition) { ... },先判断,后执行。do-while循环:do { ... } while (condition);,先执行,后判断,循环体至少执行一次。for循环:for (init; condition; increment) { ... },最灵活、最常用的循环。- 考点:
for循环的三个部分都可以省略,但分号不能省。for(;;)是一个死循环。
- 考点:
break和continue:break:立即终止整个循环。continue:跳过本次循环的剩余部分,直接进入下一次循环条件的判断。
第五部分:数组
-
一维数组
- 定义:
int arr[10];定义一个包含10个整数的数组。 - 初始化:
int arr[5] = {1, 2, 3, 4, 5};int arr[] = {1, 2, 3};(数组大小自动确定为3)。int arr[5] = {0};(将所有元素初始化为0)。
- 访问:通过下标,从
0开始。arr[0]是第一个元素。 - 考点:
- 数组下标越界:C语言不检查数组边界,访问
arr[10](如果定义大小为10) 会导致未定义行为,可能引发程序崩溃或数据错误,这是C语言的一大风险点。
- 数组下标越界:C语言不检查数组边界,访问
- 定义:
-
二维数组
- 定义:
int matrix[3][4];定义一个3行4列的整型矩阵。 - 初始化:
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};int matrix[2][3] = {1, 2, 3, 4, 5, 6};(按行存储)。int matrix[][3] = {1, 2, 3, 4, 5, 6};(列数必须指定)。
- 访问:
matrix[i][j]。
- 定义:
-
字符串
- 本质:以
\0(空字符) 结尾的字符数组。 - 初始化:
char str[] = "hello";(数组大小为6,包含5个字符和1个\0)。char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
- 常用函数 (在
string.h中):strlen(str): 返回字符串长度(不包括\0)。strcpy(dest, src): 将src复制到dest。strcat(dest, src): 将src拼接到dest后面。strcmp(str1, str2): 比较两个字符串,返回0(相等), 正数 (str1>str2), 负数 (str1<str2)。
- 考点:
strcpy和strcat容易导致缓冲区溢出,因为它们不检查目标空间是否足够,更安全的替代品是strncpy和strncat。
- 本质:以
第六部分:函数
-
函数的定义与声明
- 声明:告诉编译器函数的存在、名称、返回类型和参数列表,通常放在文件开头。
int max(int a, int b); - 定义:提供函数的具体实现。
int max(int a, int b) { return (a > b) ? a : b; } - 考点:函数定义只能有一次,声明可以有多次。
- 声明:告诉编译器函数的存在、名称、返回类型和参数列表,通常放在文件开头。
-
函数参数传递
- 值传递:
- C语言中,函数参数默认是值传递。
- 形参是实参的一份拷贝,在函数内部修改形参,不会影响实参。
- 考点:这是理解C语言函数行为的关键,如果想修改实参,需要使用指针。
- 指针传递:
- 传递变量的地址,函数可以通过指针间接修改实参的值。
- 考点:交换两个变量的值必须使用指针传递。
swap(&a, &b);。
- 值传递:
-
递归函数
- 定义:一个函数直接或间接地调用自身。
- 组成:递归调用 和 递归终止条件,没有终止条件的递归会导致栈溢出。
- 考点:经典问题如斐波那契数列、阶乘、汉诺塔等。
-
变量作用域与生命周期
- 局部变量:定义在函数内部,作用域仅限于该函数,生命周期随函数调用开始,结束而结束。
- 全局变量:定义在所有函数外部,作用域是整个文件,生命周期是整个程序运行期间。
- 考点:全局变量和局部变量同名时,局部变量优先,过度使用全局变量会破坏模块化设计。
第七部分:指针
指针是C语言的灵魂和精髓,也是考试的重中之重。
-
指针的基本概念
- 定义:指针是一个变量,其值为另一个变量的地址。
- 声明:
int *p;(声明一个指向整型数据的指针p)。 &(取地址运算符):获取变量的内存地址。p = &a;。- *`
(解引用/间接寻址运算符)**:获取指针指向地址处的值。printf("%d", *p);`。
-
指针与数组
- 数组名:数组名在表达式中“衰变”为指向数组第一个元素的指针。
- 指针遍历数组:
int arr[5] = {1, 2, 3, 4, 5}; int *p = arr;*p等价于arr[0]。p++或p + 1指向下一个元素arr[1]。
- 考点:
arr和&arr[0]的值相同,但arr是数组指针(指向整个数组),而&arr[0]是元素指针(指向单个元素),在sizeof和&运算时有区别:sizeof(arr)是整个数组的大小,sizeof(&arr[0])是一个指针的大小。
-
指针与函数
- 指针作为函数参数:用于修改实参的值(如交换函数)或传递大型数据结构(避免值传递带来的巨大开销)。
- 指针作为函数返回值:函数可以返回一个指针(指向某个变量或内存地址)。注意:不能返回局部变量的地址,因为局部变量在函数结束后会被销毁。
-
指针与字符串
- C语言中,字符串通常用字符指针表示。
char *str = "hello";。 - 考点:这种方式定义的字符串是字符串字面量,存储在只读内存区,因此不能通过指针修改其内容,要修改字符串,应使用字符数组:
char str[] = "hello"; str[0] = 'H';。
- C语言中,字符串通常用字符指针表示。
-
指针数组与数组指针
- 指针数组:一个数组,其元素都是指针。
int *ptr_array[5];(一个包含5个整型指针的数组)。 - 数组指针:一个指针,它指向一个数组。
int (*array_ptr)[5];(一个指向包含5个整数的数组的指针)。
- 指针数组:一个数组,其元素都是指针。
第八部分:内存管理
-
内存分区
- 栈:存储局部变量、函数参数、返回地址等,由编译器自动管理,速度快,容量小。
- 堆:由程序员手动管理(
malloc,free),用于动态内存分配,容量大,速度相对慢。 - 全局/静态区:存储全局变量、静态变量。
- 代码区:存储程序代码。
-
动态内存分配
malloc(size):从堆中分配size字节的连续内存块,返回指向该块首地址的指针。内存是未初始化的。calloc(n, size):分配n个size大小的内存块,并初始化为0。free(ptr):释放ptr指向的堆内存。必须释放,否则会造成内存泄漏。realloc(ptr, new_size):调整已分配内存块的大小。- 考点:
- 检查
malloc的返回值是否为NULL(分配失败时返回NULL)。 free之后,最好将指针置为NULL,防止成为“野指针”。- 忘记
free会导致内存泄漏,对已释放的内存再次free会导致未定义行为。
- 检查
第九部分:结构体与共用体
-
结构体
- 定义:将不同类型的数据组合成一个整体。
struct Student { int id; char name[20]; }; - 声明变量:
struct Student s1;或struct Student { ... } s1;。 - 成员访问:使用 运算符。
s1.id = 1001;。 - 结构体指针:使用
->运算符访问成员。struct Student *p = &s1; p->id = 1001;。
- 定义:将不同类型的数据组合成一个整体。
-
共用体
- 定义:所有成员共享同一段内存空间。
- 特点:同一时间只能存储其中一个成员的值。
- 用途:当需要处理多种不同类型的数据,但同一时间只会使用其中一种时,可以节省内存。
备考建议
- 理解重于记忆:不要死记硬背语法,要理解每个概念背后的原理(比如指针为什么能修改实参,
sizeof在不同情况下的区别)。 - 动手编程:理论知识必须通过实践来巩固,多写代码,调试代码,观察变量和内存的变化。
- 重视指针:把所有与指针相关的题目都搞懂,包括指针基础、指针与数组、指针与函数、指针与字符串。
- 注意细节: 和 的区别、
scanf的&、break的作用、for循环的写法等,这些细节是考试中的常见陷阱。 - 做真题:找一些历年考试题或模拟题,进行实战演练,熟悉题型和难度。
祝你考试顺利!
