当前位置: 首页 > news >正文

嵌入式开发学习(第二阶段 C语言基础)

C语言:第4天笔记

内容提要

  • 流程控制
    • C语句
    • 数据的输入与输出

流程控制

C语句

定义
  • C程序是以函数为基础单位的。
  • 一个函数的执行部分是由若干条语句构成的。
  • C语言都是用来完成一定操作的任务。
  • C语句必须依赖于函数存在
C程序结构

在这里插入图片描述

C语句分类
1.控制语句

作用:用来完成一定的控制,功能

举例:

if…else…、for…、while…、do…while…、continue…、break…、switch、return、goto

2.函数调用语句

由一个函数调用+分号组成,例如:

printf("这是一个函数调用语句");
tesr();
3,表达式语句

由一个表达式+分号组成,最经典的表达式语句就是赋值语句,例如:

a = 3;      //表达式
score >= 90;//表达式
score = 90; //表达式语句

4,空语句

==只有一个分号,==什么都不做,例如:

;
for(;;)
5.符合语句

用=={…}==括起来的若干个语句,例如;

{z = z + y;t = z / 100;printf("%f\n",t);//超过1条语句就是复合语句
}

数据的输入输出

数据的输入与输出是相对而言,其中:

  • 从计算机向外部设备输送称数据之为输出(output)。通常的输入输出设备包括:显示器、打印机等。
  • 从外部设备向计算机输送数据称之为输入(input)。通常输入设备包括:键盘、鼠标、扫描仪等。

在C语言中。输入输出设备需要使用标准的输入输出库(stdio.h)中的输入函数(scanf())、输 出函数(printf())实现,后期可以扩展其他输入输出函数。本章节接触函数属于外设IO

库函数已经被编译成了目标文件,在连接时编译源程序得到的目标文件相链接,生成可执行程序。

注意:在使用系统库函数的时候,需要用预处理指令#include 将有关的文件包含到用户资源文件中(一般放在程序的开头位置)头文件中包含了调用函数时需要的有关信息,具体的函数在编译的 时候再去链接对应的系统库。

输入输出缓冲机制
缓冲区的概念
  • 缓冲区(缓存)是内存空间的一部分,用于缓存输入或输出的数据。

  • 在进行输入操作时,系统从外部设备(如键盘)读取数据,先放入缓冲区程序再从缓冲区读取数据。

    输入时数据流向:外部设备→输入缓冲区→程序

  • 在进行输入操作时,系统先将数据放入缓冲区,然后在特条件下(如缓冲区满、遇到特定字 符、手动刷新等)再将缓冲区中的数据输出到外部设备(如屏幕)。

    输出时数据流向:程序→输入缓冲区→外部设备

缓冲区的类型

C语言的缓冲区有三种类型:

  • 全缓冲:当缓冲区填满后,才进行实际的输入输出操作。例如:对磁盘文件的读写。—window全缓冲区的大小是4096字节,Linux全缓冲区大小是1024字节。
  • **行缓冲:**当在输入和输出中遇到换行符(==\n或者回车)时,执行实际的输入输出操作。例如:标准输入(stdin)和(stdout)。
  • **无缓冲:**不进行缓冲直接进行输入输出操作。例如:标准错误流(stderr)
缓冲区的刷新条件

缓冲区的刷新(将缓冲区的数据实际输出到外部设备)通常发生在以下情况:

  • **缓冲区满:**当缓冲区写满时,会自动刷新。
  • 遇到特定字符:如换行字符(\n)等
  • **手动刷新:**使用fflush (stdout)函数手动刷新输出缓冲区。
  • **程序关闭时:**当程序结束时,缓冲区中的数据会被刷新。
缓冲区的实际应用
  • **提高效率:**通过缓冲区,可以减少与外部设备的交互次数,提高数据传输的效率
  • **处理输入输出:**例如:使用scanf和printf函数时,数据先被放入缓冲区,然后按照特定的规则 从缓冲区读取或输出。

实现原理图:

在这里插入图片描述

简单的输入与输出
用printf函数输出数据

语法:

printf("格式控制",输出列表);

引入文件:

#include <stdio.h>

举例:

printf("i=%d,x=%d,y=%d\n",i,34,i+1);

注意:格式控制中格式化符号(%d)要和输出的数据一一对应。

参数:

  • 格式控制:用一对英文双引号括起来,包含两种信息:
    • 格式说明:由%特定字符组成,如%d,%f,%c等,这是格式说明
    • 普通字符:作为说明性的文字、符号等,按照输入原样输出
  • 输出列表:输出列表中的各项目指出了所要输出的内容,可以是常量(字面量、符号常量、const修饰的变量)、变量、表达式。输出列表的个数,由格式控制中的格式化符号来决定。
基本的格式化符

%d 按有符号十进制整型(int)数据的实际长度输出。(十进制(0)、八进制(00)、十六进 制(0x00))

%u 按无符号十进制整型(int)数据的实际长度输出。

%c 仅输出一个字符(char)

%s 输出结果是字符串,举例:printf(“%s\n”,“CHINA”);,输出结果:CHINA

%f 以小数形式输出一个实数(涵单双精度)。整数部分全部输出,小数部分输出6位。

%e 也可以写作%E,以指数形式输出一个实数(涵单双精度)。小数点前1位非0数字,并输出6位小数。

%hd 短整型(short int/short)

%hhd 字符型的ASCII码,char数据对应的ASCII码的值,举例:char a = ‘A’;printf(“%hhd\n”,a);,输 出结果:65

%lf 双精度浮点型(double)

%ld 长整型(long int/long)

%lld 长长整型(long long int/long long)

%x 十六进制,但是十六进制的前缀0x不会打印出来,举例:printf(“%x,%#x\n”,198,198);,输 出结果:c6,0xc6

%#x 十六进制,并且十六进制的前缀0x也会打印出来,举例:0x05

%o 八进制,前缀0不会打印出来,举例:5

%#o 八进制,并且八进制的前缀0也会打印出来,举例:05

%p 打印内存的地址

%% 输出%本身

案例:

/*************************************************************************> File Name:    demo01.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 09时57分32秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{printf("%x,%#x\n",255,255);// 输出16进制整数   printf("%o,%#o\n",255,255); // 输出8进制整数  printf("%d%c",5,'%');   // 输出5%printf("%%\n");;// 输出 %printf("%f,%1f,%e\n",99.78945,99.78945,99.78945);   // 输出小数return 0;
}

运行结果:

在这里插入图片描述

用scanf函数输入数据

基础用法

语法:

scanf("格式控制",地址列表);   

注意:地址列表不能传变量、常量、表达式,只能传与之对应的内存地址(首地址),通过&+变量名获取。

举例:

int a = 10; // 定义了一个变量a
scanf("%d",&a);//&在这里称作取地址符,&a的意思是获取变量a对应的内存地址(首地址)

作用:

将从键盘输入的数据存入所占的存储单元,存储单元有地址标识。

参数:

  • ==格式控制:==含义等同于printf函数的格式控制,说明输入的数据应该使用的格式。
  • ==地址列表:==是由若干个地址组成,可以是变量的地址或者字符串的地址。&是取地址变量的地址。与格式化输出一样,在格式控制中,用于说明数据格式的格式说明符以%开 头,后面紧跟具体的格式。

案例:

需求:从键盘输入整数给变量

代码:

/*************************************************************************> File Name:    demo02.c> Author:       刘孟丹> Description:  > Created Time: 2025年05月07日 星期三 14时25分48秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{//定义三个变量a,b,c,用来接收控制台的输入int a,b,c;// 因为这里需要接收控制台键盘的输入,所以无需赋初始值// 每次在使用键盘输入之前,在控制台提示一下printf("请输入三个数字:\n");scanf("%d%d%d",&a,&b,&c);//注意:scanf格式化控制不要加\n,因为回车后会自动产生一个\n//测试printf("a=%d,b=%d,c=%d\n",a,b,c);return 0;
}

运行结果:

在这里插入图片描述

总结:输入多个数据的时候可以用空格、Tab键、回车键中的任意一种。

说明:

  • scanf函数中的“格式控制”后面应当是变量的地址,由取地址&和变量名共同组成,举例:

    scanf("%f%d", &a, &b);
    
  • 如果“格式控制”中除了格式说明以外还有其他字符,则在输入数据时必须在对应位置输入与之相 同的字符,举例:

scanf("%d,%d",&a, &b);

从键盘录入数据的时候,使用格式控制中的逗号分隔:3,4

scanf("%d-%d-%d",&year,&month,&day);

从键盘录入数据的时候,使用格式控制中的短横线分隔: 2025-5-7

scanf("%d年%d月%d日",&year,&month,&day);

从键盘录入数据的时候,使用格式控制中的年月日分隔:2025年05月07日

  • 用%c格式输入字符时,空格和转义符(如:\n,\:转义符)都作为有效字符输入,应注意:

    scanf("%c%c%c",&a,&b,&c);
    

在这里插入图片描述

注意:其实Tab键、空格键、回车键的响应都是当做字符处理。

  • 在输入数值数据(整型+浮点型)时,遇到空格、回车、Tab键或遇到非法输入(A,?…)则认为该输入结束;
scanf("%d%d%d",&a, &b, &c);

在这里插入图片描述

  • 对于unsigned型变量所需的数据,可以%u(unsigned int)或者%d(signed int)格式输入。
复杂的输入输出

按指定格式输出数据宽度、小数位数、上下行数据按小数点对齐、用八进制、十六进制等。

输出数据格式控制

整型格式说明符

  • 十进制形式(0~9)

    说明符说明数据类型
    %d和%md用于基本整型int
    %ld和%mld用于长整型long
    %u和%mu用于无符号基本整型unsigned int
    %lu和%mlu用于无符号长整型unsigned long
  • 八进制形式(0~7)

    说明符说明数据类型
    %o和%mo用于基本整型int
    %lo和% mlo用于长整型long
  • 十六进制形式(0~F)

说明符说明数据类型
%x和%mx用于基本整型int
%lx和%mlx用于长整型long

说明:

m表示输出整型数据所占总宽度(列数,1个字符占1列),其中:

①当实际数据的位数不到m位,数据前面将用空格填满,举例:原数据(“12”

②若实际数据的位数大于等于m位时,则以数据的实际位数为标准进行输出,列宽无效,举例:

​ 原数据("12345")列宽m(4)的数据("12345"

总结:

如果实际数据列宽<m,使用空格补全m。

如果实际数据列宽>=m,输出实际数据,m失效。

一个int型整型也可以使用%u输出,反之一个unsigned型整数也可以用%d、%o、%x格式输出。 按相互赋值的规则处理。

/*************************************************************************> File Name:    demo03.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 15时37分11秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{printf("%d\n",12);             // "12"      输出后,实际列宽位2printf("%6d\n",12);            // "    12"  输出后,实际列宽为6,右对齐printf("%-6d\n",12);           // "12    "  输出后,实际列宽为6,左对齐printf("%6d\n",1234567);       // "1234567" 输出后,实际列宽为7,m失效printf("%06d\n",12);           // "000012"  输出后,实际列宽为6,不足补0printf("%+d,%+d\n",12,-12);    // "+12,-12" 显示正负号printf("%#06x,%#06o\n",12,12); // "0x000c,000014" 输出后,实际列宽6return 0;
}

运行效果:
在这里插入图片描述

字符型格式说明符
  • 字符型

    说明符说明举例
    %c或者%mc输出的字符占m列printf(“%3c\n”,‘a’);

用法和整型的用法一致。

  • 字符串型

    在C语言中,支持字符串常量,不支持字符串变量

    说明符说明
    %ms输出的字符串占m列。若串长>=m,全部输出;反之在串前补空格(m为正往前补空格) 举例: printf("%6s\n","hello"); " hello"
    %-ms输出的字符串占m列。若串长>=m,全部输出;反之在串前补空格(m为负往后补空格) 举例: printf("%-6s\n","hello"); " hello"
    %m.ns输出的字符串占m列,只取字符串前n个字符,不足部分串前补空格。 举例: pri ntf("%6.2s\n","hello"); " he"
    %-m.ns输出的字符串占m列。只取字符串前n个字符,不足部分串后补空格。 举例: pri ntf("%-6.2s\n","hello"); "he "

案例:

  • 需求:字符串输出

  • 代码:

    /*************************************************************************> File Name:    demo04.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 16时02分40秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
    {printf("%3s,%7.2s,%-5.3s,%.4s\n","CHIAN","CHIAN","CHINA","CHINA");return 0;
    }
  • 运行结果

    在这里插入图片描述

浮点格式说明符

浮点型格式分为三种形式:

序号名称说明
1十进制形式%m.nf或者%-m.nf,m是列宽,n是保留的小数位
2指数形式%m.ne或者%-m.ne,m是列宽,n是保留的尾数位
3%g或者%G形 式根据数值的大小,自动选择%f或者%e中宽度较短的一种格式,不输出 无意义的0

解释:

在输出浮点型数据时,格式说明符中的m表示整个数据所占的列宽,n表示小数点后面所占的位数 (保留的小数位)

如果在小数点后取n位后,所规定的数据宽度m不够输出数据前面的整数部分(包括小数点),则 按实际的位数进行输出。

案例:

  • 需求:输出浮点型数时,指定小数位。

  • 案例:

/*************************************************************************> File Name:    demo05.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 16时09分47秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{float f = 123.155f;//f是标识符,不计入列宽,实际列宽是7printf("%8.2f,%-8.2f,%8.6f,%8.2e.%g,%G\n",f,f,f,f,f,f);//指定小数位,采用四舍五入//结果为“  123.15”,“123.15  ”,“123.155000”,“1.23e+02”,“123.155”,“123.155”return 0;
}
  • 运行结果:

    在这里插入图片描述

    这里的小数保留采用四舍五入

案例:

  • 要求:求3个圆的周长,输出结果时要求按小数点对齐,取两位小数。
  • 代码:
/*************************************************************************> File Name:    demo06.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 16时26分57秒************************************************************************/#include <stdio.h>
#define PI 3.14int main(int argc,char *argv[])
{double r1 = 1.53, r2 = 21.83,r3 = 123.71,s1,s2,s3;s1 = 2.0 * PI * r1;s2 = 2.0 * PI * r2;s3 = 2.0 * PI * r3;printf("%f\n%f\n%f\n",s1,s2,s3);return 0;
}

在这里插入图片描述

案例:

  • 要求:设有如下C程序

  • 代码

    #include "stdio.h"main(){ double x=34.567;printf("x=%f\n",x);// 34.567000printf("x=%d\n",x);// 27263,这种写法错误,自动类型转换异常printf("x=%d\n",(int)x);// 34}
    
  • 这个程序的实际运行结果为

x=34.567000

x=27263

x=34

  • 说明

    显然,这个程序中的第二个格式输出语句输出的结果是错误的,这是因为在第二个格式输出语 句中,格式说明符%d是基本整型格式说明符,而输出项目是双精度型的数据,它们是不匹配 的。

输出数据格式控制

整型格式说明符

  • 十进制形式(0~9)

    说明符说明数据类型
    %d和%md用于基本整型int
    %ld和%mld用于长整型long
    %u和%mu用于无符号基本整型unsigned int
    %lu和%mlu用于无符号长整型unsigned long
  • 八进制形式(0~7)

    说明符说明数据类型
    %o和%mo用于基本整型int
    %lo和% mlo用于长整型long
  • 十六进制形式(0~F)

说明符说明数据类型
%x用于基本整型int
%lx用于长整型long

总结:

​ ① 用于输入与输出整型数据的格式说明符是完全一致的。

​ ② 与输出情形一样,对于八进制与十六进制的输入格式,主要用于输入无符号的整型数据。

浮点型格式说明符
说明符说明数据类型
%f或者%e用于单精度浮点型float
%lf用于双精度浮点型double

总结:

①与输出不同,输入时无论单精度还是双精度,都不能用m.n来指定输出的宽度和小数点后保留的位数。

②可以指定输入数据所占的列数,系统自动按它截取所需的数据,如;

scanf("%3d%3d",&a,&b);

输入测试数据:1234567

结果:a=123,b=456

explain:从输入的数据1234567中,截取前三列(123),赋值给a,再截取3列(456),赋值给b,剩余的7舍去

③若在%后有一个==*和一个数字==,表示跳过指定的列数,如:

scanf("%2d%*3%3d",&a,&b);

输入测试数据:12345678

结果:a=12,b=678

explain:从输入的数据12345678中,截取前2列(12),赋值给a,再跳转3列,然后截取3列(678),赋值给b

案例:

/*************************************************************************> File Name:    demo06.c> Author:       小刘> Description:  > Created Time: 2025年05月07日 星期三 16时26分57秒************************************************************************/#include <stdio.h>
#define PI 3.14int main(int argc,char *argv[])
{int a,b;scanf("%3d%3d",&a, &b);// 输入:1234567printf("a=%d,b=%d\n"); // 输出:a=123,b=456return 0;
}

说明:

当用于输入整型数据的格式说明符中没有宽度说明时,则在具体输入数据时分为以下两种情况:

① 如果各格式说明符之间没有其它字符,则在输入数据时,两个数据 之间用"空格"、或"Tab"、 或"回车"来分隔。

② 如果各格式说明符之间包含其它字符,则在输入数据时,应输入与 这些字符相同的字符作为间 隔。

例如,设有如下说明

​ int a,b;

​ float c,d;

现要利用格式输入函数输入a=12,b=78,c=12.5,d=7.6。 采用不同的格式说明,其输入数据的形 式也是不同的。分别说明如下:

  • 若输入语句为 scanf("%d%d%f%f",&a,&b,&c,&D. ; (即格式说明符中没有宽度说明, 各格式说明符之间也没有其他字符。)

    则输入数据的形式应为 12 78 12.5 7.6 ↲ (两个数据之间用空格来分隔,当然也可用“Tab”或“回车”来分隔。)

  • 若输入语句为 scanf("%d,%d,%f,%f",&a,&b,&c,&D. ; (格式说明符中没有宽度说明,但各 格式说明符之间有其它字符,即逗号)

    则输入数据的形式应为 12,78,12.5,7.6 ↲ (即在输入的两个数据之间同时要输入逗号。)

  • 若输入语句 scanf("a=%d,b=%d,c=%f,d=%f",&a,&b,&c,&D. ; (即格式说明符中没有宽度 说明,但各格式说明符之间有其它字符。)

    输入数据的形式应为 a=12,b=78,c=12.5,d=7.6 ↲ (即在输入的两个数据之间同时要输入这 些非格式说明符的字符。)

  • 在用于输入的实型格式说明符中不能用m.n来指定输入的宽度和小数点后的位数(这是与输出的 不同之处)。

    例如: scanf("%7.2f",&a); × 此用法是错误的

  • 为了便于程序执行过程中从键盘输入数据,在一个C程序开始执行时,系统就在计算机内存中开 辟了一个输入缓冲区,用于暂存从键盘输入的数据。开始时该输入缓冲区是空的。当执行到一 个输入函数时,就检查输入缓冲区中是否有数据;

扩展:

说明符含义示例
%n已读取的字符数scanf(“%d%n”, &num, &count);

代码:

/*************************************************************************> File Name:    demo07.c> Author:       刘孟丹> Description:  > Created Time: 2025年05月07日 星期三 16时57分15秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{int num,count;printf("请输入一个数据:\n");scanf("%d%n",&num,&count);printf("num=%d,count=%d\n",num,count);return 0;
}

运行结果;

7.2f",&a); × 此用法是错误的`

  • 为了便于程序执行过程中从键盘输入数据,在一个C程序开始执行时,系统就在计算机内存中开 辟了一个输入缓冲区,用于暂存从键盘输入的数据。开始时该输入缓冲区是空的。当执行到一 个输入函数时,就检查输入缓冲区中是否有数据;

扩展:

说明符含义示例
%n已读取的字符数scanf(“%d%n”, &num, &count);

代码:

/*************************************************************************> File Name:    demo07.c> Author:       刘孟丹> Description:  > Created Time: 2025年05月07日 星期三 16时57分15秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{int num,count;printf("请输入一个数据:\n");scanf("%d%n",&num,&count);printf("num=%d,count=%d\n",num,count);return 0;
}

运行结果;
在这里插入图片描述

相关文章:

  • 学习黑客威胁情报(Threat Intelligence)
  • TensorFlow深度学习实战(15)——编码器-解码器架构
  • docker 日志暴露方案 (带权限 还 免费 版本)
  • 阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
  • c/c++的Libevent 和OpenSSL构建HTTPS客户端详解(附带源码)
  • Python毕业设计219—基于python+Django+vue的房屋租赁系统(源代码+数据库+万字论文)
  • 如何制作网站?制作网站的流程。
  • C++ 观察者模式详解
  • k8s之ingress
  • 电路研究9.3.4——合宙Air780EP中的AT开发指南:HTTPS示例
  • 具身智能数据集解析
  • n8n系列(4):生产环境最佳实践
  • 数据库基础:概念、原理与实战示例
  • 云轴科技ZStack入选赛迪顾问2025AI Infra平台市场发展报告代表厂商
  • 万兴PDF-PDFelement v11.4.13.3417
  • 对遗传算法思想的理解与实例详解
  • odoo-049 Pycharm 中 git stash 后有pyc 文件,如何删除pyc文件
  • python打卡day20
  • LeetCode 热题 100_编辑距离(94_72_中等_C++)(动态规划)
  • 并发设计模式实战系列(19):监视器(Monitor)
  • 远离军事前线的另一面暗斗:除了“断水”,印度还试图牵制对巴国际援助
  • 九家企业与上海静安集中签约,投资额超10亿元
  • 夜读丨母亲的手擀面
  • 老人刷老年卡乘车被要求站着?公交公司致歉:涉事司机停职
  • 消费者在天猫一旗舰店换手机电池疑遭套路致手机损坏,平台已介入
  • 市场监管总局发布《城镇房屋租赁合同(示范文本)》