蓝桥杯单片机第1阶段,电子类C语言

引言课

一,学习方法

A,第一天学番茄炒蛋、第二天学红烧牛肉、第三天学
B,第一天学100种香料、第二天学50种蔬菜、第三天学30种肉类、第四天学满汉全席

==有针对性的备赛==(电子类C语言、适当补充计算机原理、数据结构知识)
参考书籍:C语言程序设计现代方法、深入理解计算机系统


第一讲 初始C语言

一,前言

  • 打字练习(金山打字)

  • 静音键盘

  • 加入交流群

注意事项

  • 不要把python语法和C语言语法搞混了!!!
  • 不要觉得以前学过现在就不动手敲代码

二,基本语法

scanf()

基本语法格式:

    scanf("%f",&length);
    scanf("%d",&day)
    scanf("%f %f",&r1,&r2);		//多个变量输入,输入时应严格遵守格式
	scanf("%f,%f,%f",&lenth,&width,&high);

示例1:

    float length;
    printf("请输入长方体的长\n");
    scanf("%f",&length);
    printf("长度=%.2f",length);

输入:

6

输出结果:

长度=6.00

语法说明:
%d用于int型变量
%f用于float型变量

示例2:

	printf("请输入2个圆的半径,用空格连接:\n");
	scanf("%f %f",&r1,&r2);
	
	S1=PI*r1*r1;
	printf("圆1的面积是%10.2f\n",S1);
	S2=PI*r2*r2;
	printf("圆2的面积是%10.2f\n",S2);

输入:

4 6

输出:

圆1的面积是 50.27
圆2的面积是 113.10

常见错误:

错误语句 错误原因
a=scanf(“%d”,&a); 混淆python语法
scanf(“请输入a的值%d”,a) 混淆python语法
scanf(“%f”,length); 没加&

printf()

基本语法格式:

	printf("你好%d\n",num);
	printf("圆1的面积是%10.2f\n",S1);

语法说明:
%d用于int型变量
%f用于float型变量
%n.md n最小栏宽,m有效位数
%n.mf m小数位数
栏宽表示输出数据加数据前的空格的总长度
若数据长度超过n,则正常显示数字

常见错误:

print(“C语言语法”);

#define

宏定义,可用于定义常量:

#define PI 3.14f
#define a 1
#define ZhangGeZhiZuQiuMengXiang "外挂"

宏定义属于预处理指令、在编译之前处理

变量定义

规则

  • 1,变量名为字母、数字、下划线组成(不能是汉字)
    2,变量开头必须是字母
    3,变量不能是关键字

  • 4,区分大小写
    5,可以初始化、也可不初始化(赋值)
    6,可以一次声明多个变量

函数

可传参(可不传参),输出值或动作


第二讲 表达式和选择语句

一,前言

  1. 多用typora记笔记
  2. 善用AI
  3. 多动手尝试
  4. 会用就说明掌握知识了

二,基本语法

表达式

运算符:

​ 一元运算符:正负号:
​ + -
​ 二元运算符:加减乘除取余
​ + - * / %
​ %结果只能是整数

赋值运算符:

  =
  i=2
  i+=2
  i++

关系运算符

	> < == >= <= !=

布尔类赋值

_Bool
需要使用

	#include <stdbool.h>

示例1:

	int b=3;
	int a=b++;		//先给a赋值,再执行b++
	printf("a=%d\n",a);
	printf("b=%d\n",b);

输出结果:

a=3
b=4

示例2:

a、b取值于示例1。

	int c=(a>b);		//结果为False 输出0
	printf("c=%d\n",c);

输出结果:

c=0

示例3:

	//#include <stdbool.h>
	_Bool ks=2;
	if(ks==1){
		printf("真的");
	}

输出结果:

真的

选择语句

if语句

格式:

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

示例:

	int num=0;
	printf("请输入一个正整数\n");
	scanf("%d",&num);
	if((num%2==0)&&(num>0)){
		printf("%d是偶数\n",num);
	}else if((num%2==1)&&(num>0)){
		printf("%d是奇数\n",num);
	}else{
		printf("输入错误\n");
	}

输入:

10

输出:

10是偶数

输入:

41

输出:

41是奇数

输入:

-1

输出:

输入错误

三段表达式

格式:

	表达式1?表达式2:表达式3
	如果表达式1真则执行表达式2否则执行表达式3

示例:

	int f1,f2=2,f3=4;
	f1=f2<f3?f2:f3;
	printf("f1=%d\n",f1);

输出结果:

f1=2

switch语句

格式:

	switch(score){
	case 10:
        需要执行的语句
    	break;
	case 9:
            
	...
            
	case 0:
		
	default:
		
		break;

示例:

	int score=0;
	scanf("%d",&score);
	switch(score){
	case 10:
		printf("满分,天才");
		break;
	case 9:
		printf("优秀");
		break;
	case 8:
	case 7:
	case 6:
		printf("及格");
		break;
	case 5:
	case 4:
	case 3:
	case 2:
	case 1:
	case 0:
		printf("不及格,少壮不努力,老大徒伤悲!");
		break;
	default:
		printf("输入成绩无效"); 
		break;

输入:

10

输出:

满分,天才

输入:

9

输出:

优秀

输入:

7

输出:

及格

输入:

3

输出:

不及格,少壮不努力,老大徒伤悲!

输入:

12

输出:

输入成绩无效


第三讲 循环语句

一,前言

  1. ==Zlibrary== (电子书网站)

二,基本语法

while循环

判断是否满足循环条件:

  • 若满足→执行循环语句至不满足条件为止
  • 若不满足→直接跳过循环,不执行循环内语句

格式:

	while(条件){
		执行语句
    }

示例:

    int i=5;
    while(i>0 && i<=5){
        printf("i=%d\n",i);
        i--;
    }

输出:

i=5

i=4

i=3

i=2

i=1

注意,while(1){ } 为死循环。

do while循环

先执行一遍循环内的语句,再判断是否满足循环条件:

  • 若满足循环条件→执行循环
  • 若不满足循环条件→循环执行结束

格式:

    do{
		执行语句
    }while(条件);

示例:

    int num,num1;
    int k=0;	//整数位数

	scanf("%d",&num);
    num1=num;
    do{
        num=(num-(num%10))/10; 
        k++;
    }while(num>0);
    printf("整数%d有%d位",num1,k);

输入:

43215

输出:

整数43215有5位

for循环

一般来说for循环的括号内由3个语句组成

  • 语句1:
    一般来说是局部变量或索引变量的赋值,例如:

    i=5;
    i=1,j=2;
    ;		//空着,在for循环外赋值
    
  • 语句2:
    一般是判断条件,例如:

    i<1;
    (i>=0)&&(i<=100);
    ;		//当满足特定条件,break
    
  • 语句3:
    一般是局部变量或索引变量的自增或自减,例如:

    i++;
    i=i-2;
    

格式:

for(语句1;语句2;语句3){
	执行语句
}

示例:

    int x,j,m;
    for(x=2;x<=100;x++){

        m=(sqrt(x));

        for(j=1;j<m+1;j++){
            if((x%j==0)&&(j>1)){
                break;
                }	
            }
            if(j==m+1){
            	printf("%d\n",x);
        	}
    }

输出:

  • 1-100以内的所有质数(素数)

for循环与while循环的等价转化

for循环:

	for(i=5;i>0;i--){		//i=5可以空着,在循环外声明i=5
						//也可以用逗号隔开多个语句for(i=5,j=6,k=7;i>0;i--)
	}

while循环:

    i=5;
    while(i>0){

        i--;
    }

break与continue

break

  • 作用:跳出当前循环

注:此处的循环是指循环语句(for、while、do while),而非选择语句。不要直接把大括号{ }当成一个循环单位。

示例,遍历质数:

    int x,j,m;
    for(x=2;x<=100;x++){

        m=(sqrt(x));

        for(j=1;j<m+1;j++){
            if((x%j==0)&&(j>1)){
                break;
                }	
            }
            if(j==m+1){
                printf("%d\n",x);
            }
    }
  • 输出1-100的质数。

continue

  • 作用:跳过当步循环

示例:

    for(i=1;i<=10;i++){
        if(i%2==0){
            continue;
            }
        printf("%d\n",i);
    }

输出:

1

3

5

7

9

goto

  • 用法:跳转至标签语句。

注:goto一般很少用,代码行数过多时影响可读性

示例:

    goto m2;
    m1:
    	printf("我是m1");
    m2:
    	printf("我是m2");

输出:

我是m2

补充

;
  • 单个分号也是一个语句

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

一,前言

  1. 第四讲逐渐深入,难度增加,逐渐系统化
  2. 有C语言基础的也建议听

二,正文

1.数制

  • 定义:数学层面的计数方法(二进制,八进制,十进制,十六进制)

对于十进制的632.45:

数值:632.45=6*10^2^+3*10^1^+2*10^0^+4*10^-1^+5*10^-2^
位权:10^2^ 10^1^ 10^0^ 10^-1^ 10^-2^
数字:6 3 2 4 5

注:进制转化可用程序员计算器

2.计算机存储体系

  1. 二进制 0 1 组成
  2. 字、字节
    字/位 : 1 0 1
    字节:0101 0101
  3. CPU字长:8(51单片机)、16、32(STM32)、64(计算机)
  4. 2进制转16进制 0101→5 、1010→10

3.码制

无符号存储方式:

18 → 0001 0010

有符号存储方式:

  • 源码 反码 补码
  • 补码的意义是为了防止计算时出现正负零
  • 正数的补码等于源码,负数的补码等于反码加一
  • 负数补码的意义是计算减法时,把减法转化成加法
数值 源码 反码 补码
-6 1 000 0110 1 111 1001 1 111 1010
-3 1 000 0011 1 111 1100 1 111 1101
6 0 000 0110 0 000 0110 0 000 0010

计算示例:

6-3 → 6+(-3) → 6+3的互补数 → 对于12进制,1和11互补,-1等价于+11

6:0 000 0110

-3:1 111 1101

6+(-3)1 0000 0011 去除溢出位

得到结果:0000 0011 (+3)

小数存储

  • 科学计数法

  • 定点数

    • 缺点:计数范围、精度有限 xxxx.xxxx 上限9999.9999 精度 0.0001
  • 浮点数:符号位 阶数 尾数

    • 例如:0 2 632 4572 → +632.4572

4.C语言中的基本类型

整型

  • int(signed int 的缩写)
    字长:4字节(32、64位电脑常见)
    0000 0000 0000 0000 0000 0000 0000 0000 -2^31^~2^31^-1
    字长:2字节(8、16位单片机)
    0000 0000 0000 0000 -2^15^~2^15^-1
  • unsigned int
    字长:4字节(32、64位电脑常见)
    0000 0000 0000 0000 0000 0000 0000 0000 0~2^32^-1
数据类型 字节数
int 4
short int 2
long int 4/8
long long int 8
char 1
  • char 用 %c ''表示字符

  • ASCII码→用一个char表示字符,例如:
    0110 0111代表数字103,代表字符’g’
    惯用char表示字符,避免大小端模式带来的影响

浮点型

数据类型 符号位位数 指数位位数 尾数位位数
float 1 8 23
double 1 11 52

注:由于浮点数存在精度丢失的问题,浮点数比较中,推荐用误差范围法替代==或!=

示例1,wucha=0.0000 0000 1f(1*10^-9^):

float a=0.1f;

float wucha=0.000000001f;

int main(int argc, char *argv[]) {
	if((a-0.1)<=wucha){
		printf("a=%4.2f\n",a);
	}else if((a-0.1)>wucha){
		printf("超出误差\n");
	}
	
	printf("运行结束");
	
	return 0;
}

输出:

超出误差
运行结束

示例2,wucha=0.0000 0001f(1*10^-8^):

float a=0.1f;

float wucha=0.00000001f;

int main(int argc, char *argv[]) {
	if((a-0.1)<=wucha){
		printf("a=%4.2f\n",a);
	}else if((a-0.1)>wucha){
		printf("超出误差\n");
	}
	
	printf("运行结束");
	
	return 0;
}

输出:

a=0.10
运行结束

5.define进阶用法

示例:

#define u8 unsigned char

u8 a=12;

6.精度转化

示例1:

	unsigned short int c=65535;
	printf("%hd\n",c);
	printf("%hu\n",c);
	printf("%d\n",c);

输出:

-1
65535
65535

示例2:

	float f1 =6.7;
	printf("f1=%d",f1);

输出:

f1=-1073741824

可见此时输出结果为一个随机值


第五讲 数组和指针入门

一,前言

  1. 进度说明:
    方法①看完电子类C语言6讲,再开始第2阶段的学习;
    方法②第1阶段学习完成70%,余下30%穿插在第2阶段中。
  2. 灵活根据自己的时间来推进蓝桥杯单片机的学习。
  3. 基础课,会一部分就学其他的部分,不是需要系统性的学完C语言才去学其他的部分,跳出一个萝卜一个坑的惯性思维。
    等后续遇到C语言问题后,再回过头来深入学习C语言。

二,基本语法

1.数组

一位数组

  • 引入
    对于有3个学生,想要乱序存储3个学生的成绩,声明6个变量(3个表示学生的学号,3个表示学生的成绩)的方式十分麻烦,我们可以采用数组来解决此类问题。

图 1 数组和内存的结构
  • 基本语法:
    int num[4];	//声明一个长度为4的有符号整型数组
    int num[4]={5,7,1,9};
    int num[4]={0}	//暂不初始化数组
  • 示例:
    int student[3]={0};
    int i,j;
    for(i=0;i<3;i++){
        printf("请输入学生的学号:\n");
        scanf("%d",&j);
        printf("请输入学生分数:\n");
        scanf("%d",&student[j-1]);
    }

    int num1;
    printf("请输入学生的学号\n");
    scanf("%d",&num1);
    printf("学生%d的成绩为%d\n",num1,student[num1-1]);
  • 作用:

乱序存储学生成绩,存储3次后,输入学生学号,即可查询学生成绩(若已录入)。

多维数组

  • 格式:
    int num[5][9];	//5行9列
    num[2][2] = 16;
  • 示例:
	int a[2][3]={{1,2,3},{4,5,6}};
    printf("a[1][2]=%d",a[1][2]);
    //C语言不论数组维数,在电脑中都按照一维数组的形式存储
  • 输出结果:

a[1][2]=6

字符串数组

  • 格式:
    char string1[3]={'a','c','d'};
	char string2[]="cdf";
  • 示例:
    char string1[3]={'a','c','d'};
    char string2[]="cdf";
    printf("%c%c%c吃菜",string1[1],string1[2],string2[2]);
  • 输出结果:

cdf吃菜

2.指针

初步了解指针:

int* 表示声明int型的指针变量,*p表示指向的值,p表示地址。
定义指针变量时,优先赋值NULL。

图 2 指针结构示意图
  • 格式:
    int a;	//内容
    int* a_p;	//地址
  • 示例:
    int a=1;
    int* p=NULL;// 安全的做法:立即初始化为NULL或一个有效地址

    p=&a;	//p指向a的地址
    printf("a=%d\n",a);
    *p=5;	//修改p的值
    printf("a=%d\n",a);
  • 输出结果:

a=1

a=5


第六讲 函数和程序结构

一,前言

  1. 学习一样事情,准备一样比赛,==不要贪==,在此时此刻无法同时兼顾到的,就不要去再多想无法做到的事情了,要想取得,得舍去一些东西。
  2. 很多时候并没有所谓的完美解法,只有尽可去提高完成度,或加权总分
  • 有两件事情A、B(重要权重0.8、0.2)

    • 方案一:只完成A,自评95分→95*0.8=76
    • 方案二:完成A、B,自评70分,60分→70*0.8+60*0.2=68
    • 方案三:重点完成A,随便完成B,自评90分,40分→80
  • ==综上可见方案二综合得分最低,取得的成果最小,由此可得:==
    不推荐同时想把好几件事情都同时做好,并且时间分配相对平均
    推荐按照重要程度分配时间完成者几件事情

二,正文

1.函数

格式:

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

示例1,求最大数函数:

int display_max_num(int* addr,int length);

int display_max_num(int* addr,int length){
	int max_num=0;
	int j;
	for(j=0;j<length;j++){
		if(max_num<addr[j])max_num=addr[j];
	}
	
	return max_num;
}
  • 说明:
  1. 函数参数是数组和数组长度
  2. 函数中数组当做指针处理

示例2,求平均值函数:

int function2(int a,int b){
	float r;
	r=(a+b)/2;
	return r;
}
  • 说明:

返回两个正整数的平均值(返回值数据类型也是正整数)

示例3,交换两个正整数:

void function3(int* x,int* y){
	int t;
	t=*x;
	*x=*y;
	*y=t;
}
  • 说明:

交换两个正整数的地址,从而使得两个数的输出结果发生交换。

2.函数的递归

  • 示例,阶乘计算:
int fun(int n);

int fun(int n){		//特殊函数,代码默认从main函数开始执行
	if(n==1 || n==0)return 1;
	else return n*fun(n-1);
}

int main(int argc, char *argv[]) {
	
	printf("%d\n",fun(5));
	
	return 0;
}

  • 输出结果

120

3.模块化编程

对阶乘计算的函数进行模块化编程:

main.c

#include <stdio.h>
#include <stdlib.h>

#include "fun.h"

extern int p;

//特殊函数,代码默认从main函数开始执行
int main(int argc, char *argv[]) {
	
	printf("%d\n",fun(5));
	printf("p=%d",p);
	
	return 0;
}

fun.h

#ifndef FUN_H
#define FUN_H

int fun(int n);

#endif

fun.c

#include "fun.h"

int p=5;

int fun(int n){		
	if(n==1 || n==0)return 1;
	else return n*fun(n-1);
}
  • 输出结果

120

p=5

4.extern

在上个例子模块化编程中,使用到了extern语句,作用:
声明的变量在其他文件中定义,提醒编译时编译器到其他文件中寻找变量定义。

第1阶段电子类C语言学习感悟

  1. 多动手、多尝试、多思考、多做笔记、不要听完视频就结束了。

  2. 专注于当下做的事情,努力提升自我能力。

  3. 其他比赛组不了队就算了,这个比赛目前一定要拿下(==当下权重最高==)。

  4. 继续跟着进度学习。

  5. 本周状态:学习连贯性较好、基本上能在不拖沓的情况下完成学习。

  6. 难点:持续的花费时间,如何长期心理建设,较为连贯的高效学习。

  7. 本周学到内容:C语言基本语法printf(),scanf(),变量定义,选择语句(if-else if-else,switch),循环语句(while,do while,for),(break,continue,goto),函数(结构,递归),#define,数组(一维、多维、字符、指针),模块化编程,extern,数制与码制,基本变量类型,浮点数是否相等判断方法(误差判断法)。