大一C语言程序设计核心笔记
第一章:C语言入门
什么是C语言?

(图片来源网络,侵删)
- 高级语言:接近人类自然语言和数学语言,易于理解和编写。
- 编译型语言:源代码需要通过编译器(如GCC)一次性全部翻译成机器码,生成可执行文件(
.exe),然后才能运行,运行速度快。 - 结构化语言:采用函数模块化的方式组织代码,结构清晰,便于维护。
- 底层操作能力强:可以直接操作内存地址,是系统编程、嵌入式开发的首选。
第一个C程序:Hello World!
#include <stdio.h> // 1. 包含标准输入输出库
int main() { // 2. 主函数,程序的入口
printf("Hello, World!\n"); // 3. 调用库函数,在屏幕上打印字符串
return 0; // 4. 返回0,表示程序正常结束
}
核心概念解析:
#include <stdio.h>:预编译指令。stdio.h是一个头文件,包含了printf函数的声明,不包含它,编译器就不认识printf。int main():主函数,每个C程序都必须且只有一个main函数,程序从这里开始执行。- 代码块,用于包裹一组语句。
printf():标准输出函数,用于向控制台(屏幕)输出内容。\n:转义字符,代表“换行”。return 0;:main函数的返回值,返回0表示程序成功执行完毕,非零值通常表示程序遇到了错误。
第二章:数据类型、变量与常量
基本数据类型
| 类型 | 关键字 | 字节(常见) | 范围(示例) | 描述 |
| :--- | :--- | :--- | :--- | :--- |
| 整型 | int | 4 | -2,147,483,648 ~ 2,147,483,647 | 存储整数 |
| 字符型 | char | 1 | -128 ~ 127 或 0 ~ 255 | 存储单个字符(如 'A', '1') |
| 单精度浮点型 | float | 4 | 约 ±3.4E±38 (7位有效数字) | 存储小数,精度较低 |
| 双精度浮点型 | double | 8 | 约 ±1.7E±308 (15-16位有效数字) | 存储小数,精度较高 |
变量

(图片来源网络,侵删)
- 定义:在内存中分配一块空间,用来存储数据。
- 三要素:数据类型、变量名、初始值(可选)。
- 命名规则:
- 只能由字母、数字、下划线
_组成。 - 不能以数字开头。
- 不能是C语言的关键字(如
int,for,if)。 - 建议使用有意义的名字(如
studentAge而不是a)。
- 只能由字母、数字、下划线
- 定义与赋值:
int age; // 定义一个整型变量 age age = 18; // 给 age 赋值 int score = 100; // 定义并初始化
常量
- 定义:在程序运行期间,其值不能被改变的量。
- 字面常量:直接写出的值,如
10,'A',14。 - 符号常量:使用
#define定义,或使用const关键字定义。#define PI 3.14159 // 宏定义,预处理阶段替换 const int MAX_NUM = 100; // const定义,具有类型检查,更安全
第三章:运算符与表达式
算术运算符
- (加), (减), (乘), (除), (取模/求余)
- 注意:
- 如果两边都是整数,结果也是整数(整除)。
5 / 2的结果是2。 - 只能用于整数,取余数的符号取决于被除数。
-5 % 2的结果是-1。
- 如果两边都是整数,结果也是整数(整除)。
赋值运算符
- , , , , , (复合赋值)
a += b等价于a = a + b
关系运算符
>(大于),<(小于),>=(大于等于),<=(小于等于), (等于), (不等于)- 注意: (判断是否相等) 和 (赋值) 是完全不同的,初学者极易混淆。
逻辑运算符
&&(逻辑与), (逻辑或), (逻辑非)- 短路求值:
a && b:a为false,b不会被计算。a || b:a为true,b不会被计算。
自增自减运算符
- (自增), (自减)
- 前置 vs 后置:
++a:先使用a的值,再a自增。a++:先使用a的值,再a自增。- 单独使用时(如
a++),结果一样,但在表达式中,结果不同。 - 建议:在复杂的表达式中谨慎使用,最好单独使用以避免混淆。
第四章:流程控制
顺序结构
- 程序从上到下,逐行执行,这是最基本的结构。
选择结构
- if-else 语句:
if (条件) { // 条件为真时执行的代码 } else { // 条件为假时执行的代码 } // 可以有多个 else if - switch 语句:
- 适用于多分支情况,判断一个整型或字符型变量。
- 重要:每个
case后面最好加break,否则会穿透执行下一个case。
循环结构
- for 循环:适用于循环次数已知的情况。
for (初始化表达式; 循环条件; 增量表达式) { // 循环体 } // 执行顺序:初始化 -> 条件判断 -> 循环体 -> 增量 -> 条件判断 -> ... - while 循环:适用于循环次数未知,循环条件在循环开始前就确定的情况。
while (循环条件) { // 循环体 } // 先判断条件,条件为真才执行循环体 - do-while 循环:适用于至少要执行一次循环体的情况。
do { // 循环体 } while (循环条件); // 先执行一次循环体,再判断条件
跳转语句
break:跳出当前循环或switch语句。continue:跳过本次循环,直接进入下一次循环。goto:无条件跳转到程序标记的位置。强烈不建议使用,因为它会使程序流程混乱,难以维护。
第五章:数组
定义
- 相同类型的数据元素的集合,在内存中是连续存放的。
- 定义格式:
数据类型 数组名[数组长度];int scores[5]; // 定义一个可以存放5个整数的数组 scores[0] = 100; // 数组下标从0开始 scores[1] = 95;
- 初始化:
int a[5] = {1, 2, 3, 4, 5}; // 完全初始化 int b[5] = {1, 2}; // 部分初始化,未初始化的元素自动为0 int c[] = {1, 2, 3}; // 由初始化列表自动推断长度,长度为3
核心要点
- 下标从0开始。
- 边界检查:C语言不会自动检查数组下标是否越界,访问
a[5](对于长度为5的数组)会导致未定义行为,可能破坏内存,引发程序崩溃。 - 遍历数组:通常使用
for循环。for (int i = 0; i < 5; i++) { printf("%d ", a[i]); }
第六章:函数
为什么需要函数?
- 代码复用:避免重复编写相同代码。
- 模块化:将复杂问题分解为小问题,使代码结构清晰,易于维护。
函数的组成
- 返回值类型:函数执行完后返回的数据类型,如果不需要返回值,用
void。 - 函数名:函数的标识符。
- 参数列表:传递给函数的数据。
- 函数体:实现功能的代码块。
函数定义与声明
- 声明:告诉编译器这个函数存在(原型)。
int add(int, int); // 可以省略参数名,但类型不能少 - 定义:函数的具体实现。
int add(int a, int b) { // 定义 return a + b; } - 调用:使用函数。
int sum = add(3, 5);
参数传递
- 值传递:C语言中函数参数默认都是值传递。
- 特点:函数内部接收到的是实参的副本,在函数内部修改副本,不会影响外部的实参。
- 例外:如果传递的是数组名,传递的是数组首元素的地址,这属于一种特殊的值传递(地址传递),可以在函数内部修改数组元素。
第七章:指针
指针是什么?
- 指针是变量,它存储的是另一个变量的内存地址。
- 定义格式:
数据类型 *指针变量名;int *p;:定义一个指向整型数据的指针p。- 是指针运算符(解引用/间接寻址),表示获取指针指向地址上的值。
&是取地址运算符,获取变量的内存地址。
指针的核心操作
int a = 10;
int *p; // 定义一个整型指针
p = &a; // 将变量 a 的地址赋给指针 p
printf("%p\n", p); // 输出指针 p 中存储的地址
printf("%d\n", *p); // 输出指针 p 指向的地址上的值,即 10
*p = 20; // 修改指针 p 指向的地址上的值,即修改变量 a 的值
printf("%d\n", a); // 输出 20
指针与数组
- 数组名就是数组首元素的地址。
a[i]和*(a + i)是等价的。- 可以用指针来遍历数组:
int arr[3] = {1, 2, 3}; int *p = arr; // p 指向 arr[0] for (int i = 0; i < 3; i++) { printf("%d ", *(p + i)); }
指针与函数
- 通过指针传递参数,可以在函数内部修改外部变量的值。
void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int main() { int a = 10, b = 20; swap(&a, &b); // 传递地址 printf("a=%d, b=%d", a, b); // 输出 a=20, b=10 return 0; }
第八章:字符串
C语言中的字符串
- C语言没有内置的字符串类型,字符串是以字符数组的形式存储的。
- 特点:字符串以
\0(空字符) 作为结束标志。strlen计算长度时,只计算\0之前的字符数。
字符串的两种形式
- 字符数组:在栈上分配空间,可以修改。
char str1[] = "Hello"; // str1[5] = '\0' str1[0] = 'h'; // 合法
- 字符串字面量/指针:通常存储在只读的代码段,不能修改。
char *str2 = "Hello"; // str2 指向 "Hello" 的首地址 // str2[0] = 'h'; // 非法!会导致程序崩溃
常用字符串函数
strlen(str):求字符串长度。strcpy(dest, src):字符串拷贝,将src拷贝到dest。确保dest空间足够!strcmp(str1, str2):字符串比较,返回0表示相等,>0表示str1更大,<0表示str2更大。strcat(dest, src):字符串拼接,将src拼接到dest后面。确保dest空间足够!
第九章:结构体
为什么需要结构体?
- 当需要存储一组不同类型的数据时,结构体可以将它们打包成一个整体。
定义与使用
// 1. 定义结构体类型
struct Student {
int id; // 学号
char name[20]; // 姓名
float score; // 分数
};
// 2. 定义结构体变量
struct Student stu1;
struct Student stu2 = {1001, "Zhang San", 95.5};
// 3. 访问成员
stu1.id = 1002;
strcpy(stu1.name, "Li Si");
stu1.score = 88.0;
printf("ID: %d, Name: %s, Score: %.1f\n", stu1.id, stu1.name, stu1.score);
学习建议与常见误区
- 多动手,少看书:C语言是实践性极强的学科,看懂了不代表会写了,一定要把书上的例子自己敲一遍,并尝试修改、扩展。
- 理解内存模型:这是C语言的精髓,理解变量、数组、指针在内存中是如何存放的,能帮助你解决很多疑难杂症(如野指针、内存泄漏等)。
- 善用调试器:不要只靠
printf来调试,学会使用GDB(Linux)或IDE自带的调试器,可以单步执行、查看变量值、调用栈,效率极高。 - 重视基础:指针、内存管理、数组越界是初学者最容易出错的地方,一定要反复练习,彻底搞懂。
- 规范代码风格:从一开始就养成良好的缩进、命名习惯,这会让你未来的学习工作事半功倍。
- 不要害怕报错:编译器的错误信息虽然看起来吓人,但它是你最好的老师,学会阅读错误信息,定位问题所在。
祝你学习顺利,在C语言的世界里探索愉快!
