第一周-笔记

电子类 C 语言学习笔记

第一讲:初识 C 语言

1. 转义序列

  • \ + 字母构成转义序列。

  • \n:换行。

2. 变量和赋值

1)声明变量(使用之前)

  • 整数:int

  • 小数:float

  • 命名规则:

    • 只能包含英文、数字、下划线;

    • 不能以数字开头;

    • 不能与关键字重复;

    • 区分大小写。

  • , 隔开可以声明多个变量。

2)变量运算

+-*/%(取余)

3)占位符

  • int 类型:%d%+d 可带符号输出)

  • printf("体积=%d", volum); // 格式化输出

4)输入内容赋值给变量

scanf("%d", &l); // 格式化输入

5)注释

// 单行注释
​
/*
 * 多行注释
 * 多行注释
 */

6)预处理指令

#include   // 包含头文件
#define    // 宏定义
#define Pi 3.14f

7)printf 函数

printf("格式串", 参数1, 参数2, 参数3);
  • 小数默认显示 6 位。

  • printf("a=%9.2d", a);9 表示栏宽,2 表示精度。

  • %d 表示整数,%f 表示小数。

8)scanf 函数

scanf("格式串", 参数1, 参数2, 参数3);
scanf("a=%d b=%f", &a, &b);

作业一

#include <stdio.h>
#define pi 3.14159
​
int r1;
int r2;
float volum1;
float volum2;
​
int main(void)
{
    printf("请输入第一个圆的半径=");
    scanf("%d", &r1);
    printf("请输入第二个圆的半径=");
    scanf("%d", &r2);
​
    volum1 = 4.0 / 3.0f * pi * r1 * r1 * r1;
    volum2 = 4.0 / 3.0f * pi * r2 * r2 * r2;
​
    printf("第一个圆的体积是:%f\n", volum1);
    printf("第二个圆的体积是:%f\n", volum2);
​
    return 0;
}

第二讲:表达式和选择语句

1. 算术与运算符

  • intfloat 运算的结果是 float,如 9 + 2.5f = 11.5

  • % 不能操作浮点数。

  • 赋值运算符:把 = 右边的值赋给左边。

  • 复合赋值:

    • a += 2 等价于 a = a + 2

    • a = a + 1 等价于 a++++a

    • a = b++a = ++b:先赋值和先自增的区别。

  • 关系运算符:<>>=<=,运算结果只有 01

    • a = 2 > 3;,结果 a = 0
  • 判断运算符:==!=

  • 逻辑运算符:&&(与)、||(或)、!(非)

2. 选择语句

if 语句

if (表达式)
{
    语句
}
else
{
    语句
}

示例:

#include "stdio.h"
​
int num;
​
int main()
{
    printf("请输入一个数字:");
    scanf("%d", &num);
    if (num % 2 == 0)
    {
        num = num * 3;
        printf("这是一个偶数%d", num);
    }
    else
    {
        num = num * 3;
        printf("这是一个奇数%d", num);
    }
​
    return 0;
}

级联式 if 语句

if ()
{
}
else if ()
{
}
else
{
}

条件表达式

表达式1 ? 表达式2 : 表达式3;

如果表达式 1 为真,就选择表达式 2,否则选择表达式 3。

示例:

a = b < c ? b : c;

布尔值

  • _Bool:只有赋值为 0 时为假(数值为 0),其余皆为真(数值为 1)。

switch 语句

找到匹配常量后顺序执行。

成绩判定

#include "stdio.h"
​
int num;
​
int main()
{
    printf("请输入你的成绩:");
    scanf("%d", &num);
    switch (num)
    {
    case 0:
        printf("你的成绩不合格");
        break;
    case 1:
        printf("你的成绩不合格");
        break;
    case 2:
        printf("你的成绩不合格");
        break;
    case 3:
        printf("你的成绩不合格");
        break;
    case 4:
        printf("你的成绩不合格");
        break;
    case 5:
        printf("你的成绩不合格");
        break;
    case 6:
        printf("你的成绩合格");
        break;
    case 7:
        printf("你的成绩优秀");
        break;
    case 8:
        printf("你的成绩优秀");
        break;
    case 9:
        printf("你的成绩优秀");
        break;
    case 10:
        printf("你的成绩满分");
        break;
    default:
        printf("您输入的成绩有误");
        break;
    }
​
    return 0;
}

第三讲:循环结构

while 语句基本结构

while (表达式)
{
    语句
}

示例:

while (i)
{
    printf("%d\n", i);
    i = i - 1; // i--, --i
}
while (i--)
{
    printf("%d\n", i + 1);
}

无限循环:

while (1)
{
}

do...while 语句

do
{
    语句
} while (表达式);

示例:

#include "stdio.h"
​
int num;
int i;
​
int main()
{
    printf("请输入一个整数");
    scanf("%d", &num);
    do
    {
        num = num / 10;
        i++;
    } while (num > 0);
​
    printf("输入的数字有%d位", i);
​
    return 0;
}

for 语句

for (表达式1; 表达式2; 表达式3)
{
    语句
}

示例:

for (int i = 5; i > 0; i--)
{
    printf("%d\n", i);
    // 此处加 break 语句可以跳转到循环之外
}

表达式里可以用逗号隔开。

判断一个数是否为素数

#include "stdio.h"
​
int num;
int i;
​
int main()
{
    printf("请输入一个整数:");
    scanf("%d", &num);
​
    for (i = 2; i < num; i++)
    {
        if ((num % i) == 0)
        {
            break;
        }
    }
​
    if (i < num)
        printf("这不是一个素数");
    else
        printf("这是一个素数");
​
    return 0;
}

continue 语句

  • continue 会跳转到循环的末尾,不会跳出循环。

  • break 会跳出循环。

goto 语句

会跳转到标识符位置。

goto b;
a:
    printf("这是a\n");
b:
    printf("这是b\n");
c:
    printf("这是c\n");
// goto 语句会让程序跳转到 b: 位置开始运行

第四讲:数制与码制和基本类型

  • 0X 表示 16 进制。

  • 互补数代表负数。

  • 浮点数。

  • 有符号字符变量 char:只占一个字节,范围 -128 ~ 127

  • 无符号字符变量 unsigned char:只占一个字节,范围 0 ~ 255

  • 浮点数中,谨慎使用 ==!=,有精度偏差,应使用基于误差范围的方法。

  • #define 的进阶用法:

    #define u8 unsigned char
    
  • char 类型使用。

  • 类型强制转换。

1. 常见数制

  • 二进制

  • 八进制

  • 十进制

  • 十六进制

示例:

  • 十进制:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

  • 八进制:1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20

  • 十六进制:1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20

2. 位权

以十进制 632.45 为例:

数字 6 3 2 . 4 5
位权 10² 10¹ 10⁰ 10⁻¹ 10⁻²

位值:
6×10² + 3×10¹ + 2×10⁰ + 4×10⁻¹ + 5×10⁻²

科学计数法:
6.3245×10²

二进制位权示例:
0110.1100

计算:
0×2³ + 1×2² + 1×2¹ + 0×2⁰ + 1×2⁻¹ + 1×2⁻² + 0×2⁻³ + 0×2⁻⁴
= 0 + 4 + 2 + 0 + 0.5 + 0.25
= 6.75

注:PPT 中此处有笔误,实际 0110.1100 位是 1,应加上 1×2¹ = 2

进制转换:

  • 直接用程序员计算器。

二、计算机存储体系

1. 二进制

  • 计算机底层只有 0 / 1。

2. 字位与字节

  • 字位:如 1 0 1

  • 字节:如 0101 0101

3. CPU 字长

  • CPU 一次能处理的数据长度。

  • 常见:8 位、16 位、32 位、64 位。

【图片位置:第4页图1】
8 个灯泡,前 4 个亮、后 4 个灭,表示“字/位”的物理模型。

【图片位置:第4页图2】
“Ingral intloreatica”芯片/道路图,标注 8 bit、16 bit、32 bit、64 bit,表示 CPU 字长对比。

【图片位置:第4页图3】
内存概念模型:灯泡阵列,部分亮、部分灭,表示内存中 0/1 存储。


三、十六进制与二进制转换

  • 十六进制每一位刚好可以用二进制 4 位表示。

  • 常用 2 位十六进制表示一个字节。

  • 0x0X 表示十六进制。

  • 例:0x10 表示十六进制 10,即十进制 16。

  • 例:0xA2 = 1010 0010

对应表:

二进制 十六进制 二进制 十六进制
0000 0 1000 8
0001 1 1001 9
0010 2 1010 A
0011 3 1011 B
0100 4 1100 C
0101 5 1101 D
0110 6 1110 E
0111 7 1111 F

【图片位置:第5页图】
8 个灯泡,前 4 个亮、后 4 个灭,用于说明二进制与十六进制之间的对应关系。


四、码制

1. 存储正整数

一个字节 8 位:

  • 范围:0000 00001111 1111

  • 十进制:0 到 255

举例:

  • 十进制 18

  • 物理实在:0001 0010

PPT 写“以 17 来举例”,但物理实在写的是 0001 0010,对应十进制 18。若以 17 为例,应为 0001 0001

2. 存储带正负的整数

一个字节 8 位:

  • 最高位为符号位。

  • 最高位 0 表示正数。

  • 最高位 1 表示负数。

-6 为例:

编码 表示
原码 1 000 0110,即 1000 0110
反码 1 111 1001,即 1111 1001
补码 1 111 1010,即 1111 1010

补码常用。

正负 0 问题:

  • 原码、反码会出现 +0-0

  • 补码只有一个 0。


五、补码运算

6 - 3 为例:

  • 6 = 0000 0110

  • 3 = 0000 0011

  • -3 的补码 = 1111 1101

相加:

  0000 0110
+ 1111 1101
= 1 0000 0011

舍去最高进位:

0000 0011 = 3

时钟类比:

  • 12 进制中,逆时针转 1 格 = 顺时针转 11 格。

  • 所以 -1 = +11

  • 2 + 11 = 13,在 12 进制中相当于 1


六、小数的存储

1. 十进制小数位权

632.4572 为例:

数字 6 3 2 . 4 5
位权 10² 10¹ 10⁰ 10⁻¹ 10⁻²

位值:
6×10² + 3×10¹ + 2×10⁰ + 4×10⁻¹ + 5×10⁻²

科学计数法:
6.324572×10²

2. 8 位十进制

  • 定点十进制:xxxx.xxxx

  • 例:0632.45729999.99990000.0001

  • 浮点数:632 45726 632 45720 632 457263245720.6324572

3. 8 位二进制

  • 定点:0110.1100

  • 计算:6.75

  • 浮点表示:0110.1100 = 1.101100×2²

  • 浮点组成:符号位、阶数、尾数

  • PPT 示例:0 10 1 0111

【图片位置:第9页图】
PPT 原页为若干“〇”组成的示意图,没有文字说明。可放在“小数存储 / 浮点数结构”处,作为存储单元或浮点结构示意。


七、基本数据类型

1. 有符号字符变量 char / signed char

  • 字长:1 字节

  • 表示范围:-128 ~ 127

2. 无符号字符变量 unsigned char

  • 字长:1 字节

  • 表示范围:0 ~ 255

  • 物理实在:8 个 0/1

  • 占位符:%c

  • 单引号 '' 表示字符

3. 物理实在、编码格式、逻辑层、用户意义

示例 1:

  • 物理实在:0110 0111

  • 编码格式:有符号 8 位整型

  • 逻辑层:数字 103

  • 用户意义:'g'

示例 2:

  • 物理实在:0000 0011

  • 编码格式:有符号 8 位整型

  • 逻辑层:数字 3

  • 用户意义:优秀学生

惯用 char 表示字符。

4. 大端法和小端法

示例:

00000000 00000011
00000011 00000000

八、浮点数类型与输出

1. 单精度浮点数 float

  • 1 位符号位

  • 8 位指数位

  • 23 位尾数

2. 双精度浮点数 double

  • 1 位符号位

  • 11 位指数位

  • 52 位尾数

3. long double

  • 精度通常比 double 更高。

4. 基本输出

  • %f 用于输出小数形式。

  • 默认保留 6 位小数。

  • 例:

printf("%f", 3.14f);
分类 格式符 适用数据类型 描述与示例
基本输出 %f float, double 输出小数形式,默认保留6位小数。例:printf("%f", 3.14f);
%e float, double 科学计数法,指数部分为小写 ‘e’。例:printf("%e", 3.14); 输出类似 3.140000e+00
%E float, double 科学计数法,指数部分为大写 ‘E’。例:printf("%E", 3.14); 输出类似 3.140000E+00
%g float, double 自动选择 %f%e(小写 e),省略无意义的零。例:printf("%g", 3.0); 输出 3
%G float, double 自动选择 %f%E(大写 E),省略无意义的零。例:printf("%G", 0.0000314); 可能输出 3.14E-05
特殊格式 %a float, double 十六进制浮点数,字母输出为小写。例:printf("%a", 3.14); 输出 0x1.91eb86p+1
%A float, double 十六进制浮点数,字母输出为大写。例:printf("%A", 3.14); 输出 0X1.91EB86P+1
输入 %f float 用于 scanf 读取 float 类型变量。例:scanf("%f", &floatVar);
%lf double 用于 scanf 读取 double 类型变量。例:scanf("%lf", &doubleVar);
长度修饰符 %Lf long double 输出 long double 类型。例:printf("%Lf", longDoubleVar);
%Le long double 科学计数法输出 long double,指数小写 e。
%Lg long double 自动选择 %Lf%Le 输出 long double
%La long double 十六进制输出 long double 类型。
  • 输出printf)时,floatdouble 都可以用 %f%e%g 等。

  • 但在输入scanf)时,float 必须用 %f,而 double 必须用 %lf(加 l 长度修饰符),否则会导致数据读取错误。

  • 对于 long double 类型,无论是输入还是输出,都需要加 L 修饰符(如 %Lf)。


九、浮点数精度丢失问题

  • 进制转换会带来循环和精度丢失。

  • 例如:

    • 3 进制:0、1、2、10

    • 0.n = n/m

    • m 进制中:0.1 = 1/10

    • 3 进制 0.1 转十进制为 0.33333333...

    • 0.1 = 1/10

结论:

  • float 比较中,谨慎使用 ==!=

  • 应使用基于误差范围的方法,例如:

fabs(a - b) < 1e-6

十、综合练习

  1. #define 的进阶用法

  2. 关于 char 类型的使用

  3. 关于 short int 类型的使用

  4. 类型强制转换(不改变物理实在)


第五讲:数组和指针入门

数组声明和格式

格式:数组名 + [数字下标]

int num[4] = {5, 7, 9, 1};
int num[4] = {0};

小作业

#include <stdio.h>
​
int student[10] = {0};
int i;
int x;
​
int main()
{
    for (i = 0; i < 10; i++)
    {
        printf("请输入学员的学号:");
        scanf("%d", &x);
        printf("请输入学员的成绩:");
        scanf("%d", &student[x - 1]);
    }
    printf("请输入学员的学号");
    scanf("%d", &x);
    printf("学员%d号的成绩为:%d", x, student[x - 1]);
    return 0;
}

思考题(冒泡排序)

#include <stdio.h>
​
int main()
{
    int num[10];
    int i, j, temp;
​
    // 先输入 10 个数
    for (i = 0; i < 10; i++)
    {
        printf("请输入第%d个数字:", i + 1);
        scanf("%d", &num[i]);
    }
​
    // 冒泡排序:从小到大
    for (i = 0; i < 9; i++)
    {
        for (j = 0; j < 9 - i; j++)
        {
            if (num[j] > num[j + 1])
            {
                temp = num[j];
                num[j] = num[j + 1];
                num[j + 1] = temp;
            }
        }
    }
​
    // 输出排序后的结果
    printf("从小到大输出:");
    for (i = 0; i < 10; i++)
    {
        printf("%d ", num[i]);
    }
    printf("\n");
​
    return 0;
}

多维数组

int num[2][2];

const 关键字

  • 字符串:双引号,占位符 %s

  • 字符:单引号,占位符 %c

指针

  • 每一个指针指向唯一一个字节。

  • 指针变量:

int a;
int *a_p = NULL;
a = 1;
&a = 3;        // a 的地址记为 3
a_p = 3;       // a 的地址存储在 a_p 中,计为 3
*a_p = 1;      // a_p 中存储的地址并指向地址数据

第六讲:函数和程序结构

函数结构

返回值类型 函数名(参数)
{
    函数本体;
}

没有参数和返回值用 void 表示。

交换函数的封装(指针与地址)

#include <stdio.h>
​
int a = 3, b = 7, c = 0;
​
void exchange(int *x, int *y)
{
    int j = 0;
    j = *x;
    *x = *y;
    *y = j;
}
​
int main()
{
    exchange(&a, &b);
    printf("%d\n%d", a, b);
​
    return 0;
}

返回最大值的地址

#include <stdio.h>
​
// 全局变量
int a = 3, b = 7, c = 0;
int num1[3] = {2, 3, 4};
int num2[3] = {5, 4, 3};
​
int *max(int *addr) // 函数声明
{
    int *m = NULL;
    m = addr;
    int i = 0; // 局部变量,内部调用,全局和内部变量可以重复
    for (i = 0; i < 3; i++)
    {
        if (addr[i] > *m)
        {
            m = addr + i;
        }
    }
​
    return m;
}
​
void exchange(int *x, int *y)
{
    int j = 0; // 局部变量
    j = *x;
    *x = *y;
    *y = j;
}
​
int main()
{
    exchange(max(num1), max(num2));
    printf("%d\n%d", num1[2], num2[0]);
​
    return 0;
}

递归

int fun(int a)
{
    if (a <= 1)
        return 1;
    else
        return a * fun(a - 1);
}

程序结构

  • 模块化编程。

  • extern:在一个 .c 文件中声明另一个 .c 文件的变量并使用。

程序结构要点:

  1. 预处理指令

  2. 全局变量声明,函数声明

  3. main 函数

  4. 其他函数原型

  5. 函数内,局部变量:局部变量不初始化值时是随机的

  6. 语句都必须在函数内

  7. C 语言就是由函数组成的,语句不能凭空出现

  8. C 语言默认从 main 函数开始执行

  9. 将前面求最大值并返回地址的函数移动到别的 .c 文件里,封装成 .c 文件,封装 .h 文件(第一个自己定义引用的 .h 文件)

  10. .c 文件存放各类原型,.h 文件存放各类声明

  11. 外部变量 extern