电子类 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. 算术与运算符
-
int和float运算的结果是float,如9 + 2.5f = 11.5。 -
%不能操作浮点数。 -
赋值运算符:把
=右边的值赋给左边。 -
复合赋值:
-
a += 2等价于a = a + 2 -
a = a + 1等价于a++或++a -
a = b++与a = ++b:先赋值和先自增的区别。
-
-
关系运算符:
<、>、>=、<=,运算结果只有0和1。- 如
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中2¹位是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 位十六进制表示一个字节。
-
0x或0X表示十六进制。 -
例:
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 0000到1111 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.4572、9999.9999、0000.0001 -
浮点数:
632 4572、6 632 4572、0 632 4572、6324572、0.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)时,float和double都可以用%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
十、综合练习
-
#define的进阶用法 -
关于
char类型的使用 -
关于
short int类型的使用 -
类型强制转换(不改变物理实在)
第五讲:数组和指针入门
数组声明和格式
格式:数组名 + [数字下标]
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文件的变量并使用。
程序结构要点:
-
预处理指令
-
全局变量声明,函数声明
-
main函数 -
其他函数原型
-
函数内,局部变量:局部变量不初始化值时是随机的
-
语句都必须在函数内
-
C 语言就是由函数组成的,语句不能凭空出现
-
C 语言默认从
main函数开始执行 -
将前面求最大值并返回地址的函数移动到别的
.c文件里,封装成.c文件,封装.h文件(第一个自己定义引用的.h文件) -
.c文件存放各类原型,.h文件存放各类声明 -
外部变量
extern