c语言 第一周,

初识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;

变量必须先声明再使用

运算

  • +(加)、-(减)、*(乘)、/(除)、%(取余)

变量命令规则

  • 仅包含英文字母(大小写)、数字下划线

    注意

    1. 不能以数字开头

    2. 不能和关键字重复(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 位小数)

  • 常见错误

    1. 占位符与参数数量不匹配(多传 / 少传参数,导致输出乱码)

    2. 数据类型不匹配(例:用%d输出float变量,结果错误)

输入函数scanf

  • 语法格式:scanf(“字符串”, &参数1, &参数2, …);

    ★重点:修改变量值时必须加&(取地址符)

  • 用法:

    1. 读取整数和小数:int a; float b; scanf(“%d%f”, &a, &b);(连续输入,空格 / 回车分隔)

    2. 带提示格式输入:scanf(“a=%db=%f”, &a, &b);(需按「a=3b=3.14」格式输入)

  • 一般不改变变量值的直接调用变量 一般改变变量值的需要取地址&


注释

注释类型与用法

  • 单行注释:// 注释内容

  • 多行注释:/* 注释内容 */

预处理指令

头文件:#include

  • 作用:引入系统提供的标准功能库

    (例:#include <stdio.h>,引入输入输出库,才能使用printfscanf

    宏定义:#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 = ++ji=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(;:wink: 等价于 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列元素

内存结构

  • 多维数组在内存中按 “行优先” 顺序连续存储*(如num0后紧跟num0,再是num1)*

常量数组与字符串

常量数组

  • 关键字: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文件:存放函数声明、宏定义(供其他文件引用)

  • 示例:

    1. 自定义max.h(声明文件):

       #ifndef MAX_H  // 防止头文件重复包含
       #define MAX_H
       int getMax(int arr[], int len);  // 函数声明
       #endif
      
    2. 自定义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;
       }
      
    3. 主文件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仅声明,不分配内存;全局变量默认可外部访问