初识c语言
printf函数
基本用法
-
基础输出:printf(" ");(双引号中是字符串)
-
多行输出:\n换行
转义序列
-
组成:【\ +字母】
-
核心:\n(换行符)
-
eg: printf(“hello micu\nhello may”);
结果hello micu
*hello may*
变量与数据类型
核心数据类型
-
int :存储整数
-
float:存储小数
变量操作
-
声明:类型+变量名 eg:int a;float b;
-
变量初始化:声明时直接赋值 eg:int a=1;
变量必须先声明再使用
运算
- +(加)、-(减)、*(乘)、/(除)、%(取余)
变量命令规则
-
仅包含英文字母(大小写)、数字、下划线
注意:
-
不能以数字开头
-
不能和关键字重复(main、int、return等)
-
-
批量声明:多个同类型变量可一次声明,用逗号分隔
eg:int a,b,c;(仅声明)、int a=1,b=2,c=3;(声明并初始化)、int a,b=2,c;(部分初始化)
格式化输入输出
输出函数printf
-
语法格式:printf(“格式串”, 参数1, 参数2, …);*(格式串包含普通字符串 + 占位符)*
-
核心占位符:
%d:匹配int类型变量(输出整数)
%f:匹配float类型变量(输出小数) -
格式控制(进阶用法):
%n.md(用于整数 / 普通数字):n = 最小栏宽(不足补空格,超过正常显示),m = 有效位数(不足补 0)
eg1:printf(“%5.2d”, 3);(输出: 03,栏宽 5,有效位数 2)%n.mf(用于小数):n = 最小栏宽,m = 小数点后位数(默认 6 位)
eg2:printf(“%.2f”, 3.1415);(输出:3.14,保留 2 位小数) -
常见错误:
-
占位符与参数数量不匹配(多传 / 少传参数,导致输出乱码)
-
数据类型不匹配(例:用%d输出float变量,结果错误)
-
输入函数scanf
-
语法格式:scanf(“字符串”, &参数1, &参数2, …);
★重点:修改变量值时必须加&(取地址符)
-
用法:
-
读取整数和小数:int a; float b; scanf(“%d%f”, &a, &b);(连续输入,空格 / 回车分隔)
-
带提示格式输入:scanf(“a=%db=%f”, &a, &b);(需按「a=3b=3.14」格式输入)
-
-
一般不改变变量值的直接调用变量 一般改变变量值的需要取地址&
注释
注释类型与用法
-
单行注释:// 注释内容
-
多行注释:/* 注释内容 */
预处理指令
头文件:#include
-
作用:引入系统提供的标准功能库
(例:
#include <stdio.h>,引入输入输出库,才能使用printf、scanf)宏定义:#define
-
语法格式:#define 宏名 常量值(例:#define PI 3.14f)
-
优势:代码中多次使用的常量,修改时仅需改宏定义,无需逐个修改
解决实际问题
长方体体积计算
step1:固定值计算
// 1. 声明并初始化长宽高(int类型)
int length=3; // 长
int width=4; // 宽
int high=5; // 高
int volum; // 体积(仅声明,后续赋值)
// 2. 计算体积:长×宽×高
volum = length * width * high;
// 3. 输出结果(★注意:早期错误写法printf("体积:volum"); 无法显示变量值)
printf("体积:%d", volum); // 正确写法:用%d占位符匹配int变量
step2:接收用户输入(进阶版)
int length, width, high, volum;
// 读取用户输入的长宽高(★重点:&不可省略,变量名需对应)
scanf("%d", &length);
scanf("%d", &width);
scanf("%d", &high);
volum = length * width * high;
printf("体积:%d", volum);
step3:完善
int length, width, high, volum;
// 提示用户输入(避免用户迷茫)
printf("请输入物体的长:");
scanf("%d", &length); // ★修正PPT笔误:原PPT重复写&length,此处应为&width、&high
printf("请输入物体的宽:");
scanf("%d", &width);
printf("请输入物体的高:");
scanf("%d", &high);
volum = length * width * high;
printf("物体的体积是:%d", volum);
表达式与选择语句
表达式
基础概念
-
表达式:产生值的代码片段(如 4+5、a>3)
-
语句:执行动作的代码(通常以分号结尾)
算术运算符
| 类型 | 运算符 | 说明 |
|---|---|---|
| 二元 | + - * / | 加减乘除;int与float运算结果为float |
| 求余 | % | 仅用于整数,浮点数不支持 |
| 一元 | + - | 一元正号(无实际作用)、一元负号 |
注意:负数的/和%结果不确定,避免依赖
优先级
-
优先级:* / % > + -
-
简化方案:**直接用括号()**明确运算顺序(无需死记优先级)
赋值
-
语法:左值 = 右值(左值必须是可修改的变量,如i,不能是12、i+j)
-
连续赋值:i = j = k = 5*(从右往左执行,最终i,j,k均为 5)*
复合赋值
- a += b 等价于 a = a + b*(-、*、/、%同理)*
自增 / 自减运算符
| 运算符 | 说明(以i为例) |
示例(初始i=2,j=3) |
|---|---|---|
| i++ | 后置:先使用i,再自增 | i = j++ → i=3,j=4 |
| ++i | 前缀:先自增i,再使用 | i = ++j→i=4,j=4 |
选择语句
关系运算符
-
结果:真(1)、假(0)
-
运算符:>(大于)、<(小于)、>=(大于等于)、<=(小于等于)
等于
-
注意:==(判断相等)与=(赋值)的区别
-
运算符:
==(相等)、!=(不相等)示例:5==5→1(真),5!=5→0(假)
逻辑运算符
| 运算符 | 名称 | 真值表(A 为真,B 为真) |
|---|---|---|
| ! | 逻辑非 | !A→假 |
| && | 逻辑与 | A&&B→真;A&&!B→假 |
短路特性:&&前假则后续不执行,||前真则后续不执行
if语句
if(表达式) // 表达式为真执行
语句1;
else // 否则执行
语句2;
核心要点
-
多语句需用{}包裹代码块
-
悬空 else:else 始终与最近的未配对 if结合
编程实例
-
判断奇数偶数
int num; scanf("%d", &num); if(num % 2 == 0) printf("偶数\n"); else printf("奇数\n"); -
奇偶数运算:
if(num % 2 == 1)
printf("%d\n", num*3);
else
printf("%d\n", num*5);
条件表达式
-
语法:表达式1 ? 表达式2 : 表达式3
-
逻辑:表达式 1 为真→执行表达式 2,否则→执行表达式 3
示例:
a = (b>c) ? b : c;(a 取 b 和 c 中的较大值)
布尔值
-
类型:_Bool(C99 新增),取值仅 0(假)、1(真)
-
兼容:int可替代(0 为假,非 0 为真)
switch语句
基本结构
switch(表达式) {
case 常量1: 语句1; break; // break避免穿透
case 常量2: 语句2; break;
...
default: 语句n; // 无匹配时执行
}
核心要点
-
表达式结果需为整数类型
-
必须加break,否则会从匹配 case 开始持续执行后续所有 case
-
示例(成绩判定):
int score;
scanf("%d", &score);
switch(score) {
case 10: case 9: case 8: case 7: printf("优秀\n"); break;
case 6: printf("及格\n"); break;
case 5: case 4: case 3: case 2: case 1: case 0: printf("不及格\n"); break;
default: printf("成绩输入有误\n");
}
循环语句
循环语句核心
while 语句
基本结构
while(表达式) { // 表达式为真(非0)则执行循环体
语句; // 多语句需用{}包裹
}
核心要点
-
先判断条件,再执行循环体 * 可能一次都不执行*
-
无限循环:while(1)(需配合break退出)
-
i–与–i区别(循环中常用):
| 运算符 | 执行逻辑 | 循环中影响 |
|---|---|---|
| i– | 先用后减 | 循环次数与初始值匹配 |
| --i | 先减后用 | 循环次数比初始值少 1(需注意边界) |
int i = 5;
while(i >= 1) {
printf("%d ", i); // 输出:5 4 3 2 1
i--; // 后置自减,先输出再减1
}
do-while 语句
基本结构
do {
语句; // 至少执行一次
} while(表达式); // 分号不可省略
核心要点:先执行循环体,再判断条件(确保至少执行 1 次)
- 实例
int num, count = 0;
printf("请输入一个整数:");
scanf("%d", &num);
do {
num /= 10; // 每次除以10,去掉末尾一位
count++; // 统计位数
} while(num != 0); // num为0时结束
printf("该整数的位数为:%d\n", count);
for 语句
基本结构
for(表达式1; 表达式2; 表达式3) {
语句;
}
// 执行逻辑:表达式1(初始化)→ 表达式2(条件判断)→ 循环体 → 表达式3(更新)→ 重复
核心要点
-
表达式 1:初始化变量*(如int i=5,C99 支持在这定义变量)*
-
表达式 2:循环条件*(为真则执行,假则退出)*
-
表达式 3:更新变量*(如自增 / 自减)*
-
省略形式:
省略表达式 1:需提前初始化变量*(int i=5; for(;i>=1;i–))*
省略表达式 2:默认条件为真*(无限循环,for(;
等价于 while(1))*
省略表达式 3:需在循环体内更新变量*(否则无限循环)* -
实例:显示从5到1
for(int i=5; i>=1; i--) { // C99支持在表达式1定义i
printf("%d ", i); // 输出:5 4 3 2 1
}
逗号运算符
- 作用:在for的表达式 1 或 3 中分隔多个语句,从左到右执行
示例:for(int i=0, j=10; i<j; i++, j–)(同时初始化两个变量,同步更新)
循环控制语句
break 语句
-
功能:立即退出当前所在循环(或switch语句)
-
示例(素数判断):
int num, is_prime = 1;
printf("请输入一个整数:");
scanf("%d", &num);
for(int i=2; i<=num/2; i++) {
if(num % i == 0) { // 能被整除,不是素数
is_prime = 0;
break; // 退出循环,无需继续判断
}
}
if(is_prime && num > 1)
printf("%d是素数\n", num);
else
printf("%d不是素数\n", num);
continue 语句
-
功能:跳过本次循环剩余语句,直接进入下一次循环判断
注意:不退出循环,仅跳过当前轮次后续代码
goto 语句
基本结构
标识符: 语句; // 定义跳转目标
goto 标识符; // 跳转到目标语句
核心
-
可跨语句跳转(甚至跳出循环),但不推荐频繁使用(破坏代码结构)
-
仅限在同一函数内跳转
关键总结
循环选择:
-
已知循环次数 → 优先for
-
未知循环次数(需先执行)→ do-while
-
未知循环次数(先判断)→ while
循环退出:
break(直接退出)、continue(跳过本次)
避免陷阱:
-
while/for条件漏写更新语句(导致无限循环)
-
do-while末尾漏加分号
-
混淆i–与–i的执行顺序
数制与码制 + 基本数据类型
数制
常见数制及对应表示
| 数制 | 数码范围 | 示例 |
|---|---|---|
| 10 进制 | 0~9 | 1,2,…,9,10,11,…,20 |
| 8 进制 | 0~7 | 1,2,…,7,10,11,…,24 |
| 16 进制 | 09,AF(大小写均可) | 1,2,…,9,A,B,…,F,10,11,…,14,15,1A,1B |
| 2 进制 | 0~1 | 1,10,11,…,10011,10100 |
核心概念:位权
定义:
- 每个数字位对应的权重(基于进制基数的幂次)
示例:
- 10 进制 632.45:位权为 10²、10¹、10⁰、10⁻¹、10⁻²,位值 = 6×10²+3×10¹+2×10⁰+4×10⁻¹+5×10⁻²
进制转换:
- 直接使用程序员计算器高效实现
计算机存储体系
底层基础
二进制:
- 计算机唯一存储语言(0 = 低电平,1 = 高电平)
核心单位:
-
位(bit):最小单位(0 或 1)
-
字节(Byte):基本存储单位,1 字节 = 8 位(如01010101)
-
字长:CPU 一次能处理的数据长度(8 位、16 位、32 位、64 位)
二进制与十六进制转换(重点)
-
转换规则:1 位 16 进制 = 4 位二进制(精准对应)
-
实用技巧:2 位 16 进制可表示 1 个字节(8 位)
-
标识:16 进制以 0x 或 0X 开头(如0xA2、0xF0)
-
示例:0x11 对应 00010001,0xC1 对应 11000001
码制
无符号整数存储(1 字节 = 8 位)
-
存储范围:00000000~11111111*(对应 10 进制 0~255)*
-
编码逻辑:直接通过进制转换映射(如 10 进制 18→二进制00010010)
有符号整数存储(1 字节 = 8 位)
-
符号位:最高位为符号位*(0 = 正数,1 = 负数*
-
编码方式:
原码:直接表示符号 + 数值(如 - 6→10000110)
反码:正数与原码一致,负数 = 原码符号位不变 + 数值位取反(如 - 6 反码→11111001)
补码:计算机常用(正数与原码一致,负数 = 反码 + 1;如 - 6 补码→
11111010)关键:补码解决了 “正负 0” 问题(仅保留一个 0:00000000)
小数存储
分类:
-
定点数:固定小数点位置(如0110.1100→6.75)
-
浮点数:科学计数法表示(符号位 + 阶数 + 尾数),适配大范围小数
二进制与 10 进制小数转换可能出现循环,导致精度问题
基本数据类型及 I/O
字符类型(char)
| 类型 | 字长 | 表示范围 | 占位符 | 说明 |
|---|---|---|---|---|
| signed char | 1 字节 | -128~127 | %c | 带符号(默认) |
| unsigned char | 1 字节 | 0~255 | %c | 无符号 |
注意:字符用单引号包裹(如’a’、‘5’)
浮点数类型
| 类型 | 存储结构(符号位 + 阶数 + 尾数) | 输入占位符 | 输出占位符(常用) |
|---|---|---|---|
| float(单精度) | 1 位 + 8 位 + 23 位 | %f | % f(默认 6 位小数)、% e(科学计数法小写)、% g(自动选择) |
| double(双精度) | 1 位 + 11 位 + 52 位 | %lf | % f、% E(科学计数法大写)、% G(自动选择) |
| long double | 扩展精度 | %Lf | %Lf、%Le、%Lg |
浮点数关键注意事项
-
精度丢失:二进制与 10 进制小数转换可能存在循环(如 0.1→二进制无限循环
-
比较禁忌:避免用 == 或 != 直接比较浮点数
-
解决方案:基于误差范围判断(如fabs(a-b) < 1e-6)
数组和指针入门
一维数组
核心概念
-
用途:存储多个同类型数据(解决批量数据存储问题,如多名学生成绩)
-
本质:内存中连续的存储空间
声明与初始化
声明格式
数据类型 数组名[数组长度]; // 长度为正整数
int num[4]; // 声明1个长度为4的int型数组(下标0~3)
初始化方式
| 初始化形式 | 说明 |
|---|---|
| int num[4] = {5,7,9,1}; | 完全初始化(元素顺序对应下标 0~3) |
| int num[4] = {0}; | 部分初始化(未赋值元素默认设为 0) |
| int num[] = {5,7,9,1}; | 省略长度(编译器自动根据元素个数确定长度为 4) |
| 后续赋值 | num[0] = 6; num[1] = 2;(下标访问赋值) |
核心要点
-
数组下标从 0 开始(长度为 n 的数组,下标范围 0~n-1)
-
单个元素使用:与同类型普通变量完全一致(可参与运算、判断、输入输出)
if(num[0] == 7) scanf("%d", &num[0]); // 合法操作
多维数组
核心概念
-
以二维数组为核心(本质是 “数组的数组”,内存中仍连续存储)
-
用途:存储表格化数据(如矩阵、多行多列的成绩表)
声明与使用
声明格式
数据类型 数组名[行数][列数];
int num[5][9]; // 5行9列的int型二维数组
元素访问
num[3][2] = 6; // 给第4行第3列元素赋值(下标从0开始)
int a = num[4][0]; // 读取第5行第1列元素
内存结构
常量数组与字符串
常量数组
-
关键字:
const(运行时不可修改,节省内存) -
const char a[] = {'0','1','2',...,'F'}; // 存储16进制字符,不可修改
字符串(特殊的字符数组)
| 字符数组 | 字符串(双引号声明) | 核心区别 |
|---|---|---|
| char str[3] = {‘a’,‘b’,‘c’}; | char str[] = “abc”; | 字符串自动末尾加\0(结束标志) |
占位符:%c(单个字符) |
占位符:%s(整个字符串) |
字符串依赖\0识别结束 |
字符串操作需包含头文件 #include <string.h>
指针入门
核心概念
-
指针:存储内存地址的变量(每个指针指向内存中唯一的字节)
-
关键关联:地址(内存单元编号)→ 指针变量(存地址)→ 目标变量(地址对应的值)
指针变量的声明与使用
声明格式
数据类型 *指针变量名; // 数据类型表示指针指向的变量类型
int a; // 普通int变量
int *a_p; // 指向int型变量的指针变量
float c;
float *c_p; // 指向float型变量的指针变量
核心运算符
| 运算符 | 作用 | 示例 |
|---|---|---|
| & | ``取地址符(获取变量地址) | a_p = &a;(将 a 的地址赋给 a_p) |
| * | 解引用符(通过地址访问值 | *a_p = 1;(等价于a = 1;) |
关联逻辑
int a = 1;
int *a_p = &a; // a_p存储a的地址(如0x00000003)
printf("%d", *a_p); // 输出1(通过指针访问a的值)
核心要点
-
指针变量的类型必须与指向的变量类型一致(如 int * 不能指向 float 变量)
-
指针的本质是 “地址”,解引用
*是通过地址找到目标变量
函数和程序结构
函数
核心概念与结构
-
用途:封装重复代码,实现代码复用
-
基本结构:
返回值类型 函数名(参数列表) {
函数本体; // 执行逻辑
return 返回值; // 无返回值可省略(返回值类型为void)
}
- 关键字
void:表示 “无返回值” 或 “无参数”
无参无返回值函数
-
示例:封装打印
hello micu的函数#include <stdio.h> void printHello() { // void表示无参数、无返回值 printf("hello micu\n"); } int main() { printHello(); // 函数调用 return 0; }
有参有返回值函数
-
示例:封装求两个数平均值的函数
#include <stdio.h> float average(int a, int b) { // 接收两个int参数,返回float return (a + b) / 2.0f; // 返回计算结果 } int main() { int x = 3, y = 7; float res = average(x, y); // 调用函数,接收返回值 printf("平均值:%f\n", res); // 输出:5.000000 return 0; }
指针传参(解决值传递局限)
关键问题:直接传参无法交换变量值
-
错误示例(值传递:仅传递变量副本,原变量不变):
void exchange(int x, int y) { // x、y是a、b的副本 int temp = x; x = y; y = temp; // 仅修改副本,原变量a、b无变化 } int main() { int a = 2, b = 3; exchange(a, b); printf("a=%d, b=%d\n", a, b); // 输出:a=2, b=3(未交换) return 0; } -
正确方案:指针传参(传递变量地址,直接操作原变量)
void exchange(int *x_p, int *y_p) { // 接收变量地址 int temp = *x_p; // 解引用,获取原变量a的值 *x_p = *y_p; // 修改原变量a的值 *y_p = temp; // 修改原变量b的值 } int main() { int a = 2, b = 3; exchange(&a, &b); // 传递a、b的地址 printf("a=%d, b=%d\n", a, b); // 输出:a=3, b=2(交换成功) return 0; }
函数返回值的灵活用法
-
作为右值赋值:
int res = average(3,7); -
参与判断:
if(average(3,7) > 4) { ... } -
作为其他函数参数:
printf("%f", average(3,7)); -
处理多组数据:通过指针或数组作为参数(适配批量数据操作)
示例:求两个数组的最大值并计算平均值
#include <stdio.h>
int getMax(int arr[], int len) { // 数组作为参数(本质是指针)
int max = arr[0];
for(int i=1; i<len; i++) {
if(arr[i] > max) max = arr[i];
}
return max;
}
float avgOfMax(int a[], int lenA, int b[], int lenB) {
int maxA = getMax(a, lenA);
int maxB = getMax(b, lenB);
return (maxA + maxB) / 2.0f;
}
int main() {
int arr1[] = {1,3,5}, arr2[] = {2,4,6};
printf("平均值:%f\n", avgOfMax(arr1, 3, arr2, 3)); // 输出:5.000000
return 0;
}
递归函数
-
定义:函数调用自身(需明确终止条件,避免无限递归)
-
示例:计算 n 的阶乘(n! = n × (n-1) × … × 1)
#include <stdio.h> int fact(int n) { if(n <= 1) return 1; // 终止条件:n=1或0时返回1 else return n * fact(n-1); // 递归调用:拆分为n × (n-1)! } int main() { printf("5! = %d\n", fact(5)); // 执行流程:5→4→3→2→1,返回120 return 0; }
函数声明
-
规则:函数使用前必须声明(告知编译器函数的返回值类型、参数列表)
-
方式:
// 单独声明(放在main函数前) float average(int a, int b); int main() { average(3,7); // 合法调用 } // 函数实现(放在main函数后) float average(int a, int b) { return (a + b)/2.0f; }
程序结构
整体组成(按执行顺序)
预处理指令(如#include <stdio.h>、#define)
全局变量声明 + 函数声明
main函数(程序入口,C 语言默认从main开始执行)
其他函数实现(自定义函数的具体逻辑)
变量作用域与初始化
| 变量类型 | 定义位置 | 初始化规则 | 作用域 |
|---|---|---|---|
| 局部变量 | 函数内部 | 未初始化时值为随机值 | 仅在所在函数内有效 |
| 全局变量 | 函数外部 | 未初始化时默认值为 0 | 整个程序所有函数可访问 |
-
核心:所有语句必须包含在函数内,不能凭空出现
多文件封装(模块化开发)
-
目的:拆分代码,提高可读性和复用性
-
规则
.c文件:存放函数实现(函数本体).h文件:存放函数声明、宏定义(供其他文件引用) -
示例:
-
自定义
max.h(声明文件):#ifndef MAX_H // 防止头文件重复包含 #define MAX_H int getMax(int arr[], int len); // 函数声明 #endif -
自定义
max.c(实现文件):#include "max.h" int getMax(int arr[], int len) { // 函数实现 int max = arr[0]; for(int i=1; i<len; i++) { if(arr[i] > max) max = arr[i]; } return max; } -
主文件
main.c(引用使用):#include <stdio.h> #include "max.h" // 引用自定义头文件 int main() { int arr[] = {1,3,5}; printf("最大值:%d\n", getMax(arr, 3)); // 调用其他文件的函数 return 0; }
-
外部变量extern
-
用途:在一个文件中访问另一个文件定义的全局变量
-
示例:
-
-
文件 A.c:
int globalVar = 10;(定义全局变量) -
文件 B.c:
extern int globalVar;(声明外部变量,无需重新定义) -
注意:
extern仅声明,不分配内存;全局变量默认可外部访问
-
-