c++/c中putchar/getchar、printf/scanf、预处理、文件--lesson9


前言

这一篇文章的是对C/C++中一些常用的功能进行介绍,至少嵌入式上还是很有用的,以此作为C结束,C++正式开始的标志。


一、数据的输入和输出(不是ANSI C/C++的内容,是各个编译系统自己实现的库函数,供我们使用的)

在讨论输入和输出的时候,是针对计算机来说的,例如键盘和显示器。
需要说明的是本身标准C语言是不没有和输入输出相关的语句的,但是各个编译系统厂家(或者软件厂家)根据客户的要求结合不同的OS(os和底层交互),实现并开发出相应的输入输出库函数,并且以目标文件(.obj)和头文件的形式(.h)供用户使用,用户只需添加头文件(如函数原型声明),用户添加头文件后,编译器只管函数的参数、函数类型是否和原型一致,直接将.c文件编译成.obj,后面将所有的obj(包括调用的库函数)链接,最后生成.exe程序,不同的编译系统提供的输入输出函数数量,名字和功能是不完全相同的,但是一些常用的大家都叫一样的名,如printf、scanf、putchar、getchar,puts、gets等等,仅仅是底层可能实现不同而已,对用户来只当作一个黑盒子来使用即可。
(备注:不同的编译系统有各个操作系统版本是为了在当地开发当地运行,也有在windows开发,linux运行的,那它的编译型系统内的库函数肯定针对linux的,还有就是嵌入式上用的,在linux上开发,在嵌入式linux运行,原理也是一样的。)

1.字符的输入和输出

putchar©:c是字符变量或者字符
c = getchar();获取一个字符并换行

int main(int argc, char* argv[])
{
	char c;
	char a[20] = "c/c++\n";
	
	c = getchar();

	return 0;
}

2.字符串的输入和输出

puts(s):s是字符串常量或者字符数组指针
gets(s);s字符数组指针

int main(int argc, char* argv[])
{
	char c;
	char a[20] = "c/c++\n";
	
	puts("nihao!");
	puts(a);
	gets(a);

	return 0;
}

3.格式输入和输出

①printf函数
a)prinf的函数的原型:int printf( const char* format, …);
b)使用格式:printf(格式控制字符串,输出列表)
或者叫printf(参数1,参数2,参数3,…参数n):
格式控制字符串由两个部分组成:格式说明(’%’+[附加符号/修饰符]+格式字符组成,如%d)和普通字符(原样输出字符,包括空格、回车、换行等转义字符);
输出列表:需要输出的数据。
也可以是说是将参数2~参数n按照参数1给定的格式输出
c)**针对’%'做如下说明:**表示格式说明的开始
d)针对附加符号做如下说明:

附加符号说明
l、L用于长整形整数,可加在格式字符d、o、x、u前面
数字m数据的最小宽度
数字n对实数表示n位小数、对字符串表示截取的字符个数
表示输出的数字或者字符在域内向左靠

e)针对格式字符做如下说明:

格式字符说明
d、i带符号十进制输出
o八进制输出
x、X十六进制输出
u无符号十进制输出
c输出一个字符
s输出字符串,我觉得用字符数组可能更好
f小数形式输出
e、E指数形式输出
g、G选用%f和%e中输出宽度较短的一种格式
int main(int argc, char* argv[])
{
	char c;
	char a[20] = "c/c++\n";
	
	printf("s = %s", a);

	return 0;
}

f)针对printf函数做如下的说明:
printf函数涉及到函数可变参数的问题,后面将继续学习;
格式说明以’%'开头,以上面介绍的9种格式字符结束;
如果要输出%,则需要%%。
②scanf函数
a)scanf的函数原型:int scanf(const char *format, …);
b)使用格式:scanf(格式控制字符串,地址列表)
格式控制字符串由两个部分组成:格式说明(’%’+[附加符号/修饰符]+格式字符组成,如%d)和普通字符(原样输出字符,包括空格、回车、换行等转义字符);
地址列表:若干个地址组成的列表,可以是变量的地址,也可以是字符串的首地址。
c)针对’%'做如下说明:表示格式说明的开始
d)针对附加符号做如下说明:

附加符号说明
l、L用于长整形整数以及double
h用于短整形数据
域宽置定数据所占的宽度(列数),为正整数
*表示本输入项在读入都不赋值给相应的变量

e)针对格式字符做如下说明:

格式字符说明
d、i带符号十进制输出
o八进制输出
x、X十六进制输出
u无符号十进制输出
c输出一个字符
s输出字符串,我觉得用字符数组可能更好
f小数形式输出
e、E指数形式输出
g、G选用%f和%e中输出宽度较短的一种格式

f)针对scanf函数做如下的说明:
sacnf函数涉及到函数可变参数的问题,后面将继续学习;
1.格式说明以’%'开头,以上面介绍的9种格式字符结束;
2.如果在格式控制字符串中有其他的字符,则在输入数据时对应的位置用输入与这些字符相同的字符;

scanf("%d,%d", &a,&b);
3,4回车(此处注意','

3.在用’%c’格式输入字符时,空格字符和转义字符都作为有效的字符;
4.在输入有效数据时,遇到以下情况时认为该数据的提取结束:
遇空格、或者回车或者跳格(TAB);
按指定的宽度结束,如“%3d”,只取3列;
遇到非法的输入。
以上这些,以后再做试验验证。

二、预处理

1.预处理命令的内涵

在程序中,我们经常看见以符号#开头的语句(其实是命令),不知道还以为是c语言语句,其实不然,之前我们说过程序开发过程:编写->预处理->编译->链接->.exe,其中预处理命令就是在编译(包括词法与语法分析、代码生成、优化等)之前对程序中这些特殊的命令进行“预处理”,使用的是预处理器,处理完之后就全是c语言语句了,再有编译器进行编译,得到obj,链接(链接器)最后生成exe。
但是目前的编译系统已经将这些功能集成在一起,所以很多初学者都不知道其中的原理,要正确区分预处理命令和c语言语句
C语言中预处理功能主要有3个:
1、宏定义(不带参数的宏定义和带参数的宏定义)
2、文件包含
3、条件编译
分别有宏定义命令、文件包含命令、条件编译命令来实现,为了与一般的C语句区别,这些命令以符号#开头。
当然还需要注意预编译器中预定于的一些宏也要学习,所以如何想实现预处理功能自由,请好好学习@!
https://www.runoob.com/cprogramming/c-preprocessors.html

2.宏定义

①不带参数的宏定义(之前的符号常量就是其中的一种,符号常量在stm中貌似就Private define和Exported constants)
定义:#define 标识符(宏名) 字符串
它的主要作用就是在预处理阶段进行字符(注意是字符替换替换替换!!!)替换(宏展开),不做任何的语法检查,只有在编译的时候才发现问题,很危险!
注意作用域,可以加上#undef 标识符 强制作用于停止
还有一种极端定义:#define 标识符(宏名),啥也不干,就是定义一个宏玩玩,后面条件编译用的上。

#define PI 3.1415
void max()
{
}
#undef PI //结束PI的作用域

②带参数的宏定义(stm中貌似就Exported macro 和Private macro)
定义:#define 宏名(参数) 字符串
它是这样展开的,将程序中宏中的实参替换形参,形成替换的字符串返回,在预处理阶段进行字符(注意是字符替换替换替换!!!)替换(宏展开),不做任何的语法检查,只有在编译的时候才发现问题,很危险!
注意:#define max(a,b)

3.文件包含

包含文件的类型很多:.h、.c甚至没有后缀
②#include “文件”
③file1 include file2它的作用是将file2文件内容包含进来,成为file1的一部分,这个很重要,理解了这个其他的知道怎么回事了。

4.条件编译

条件编译的三种形式:

#ifdef 标识符
程序段1
#else
程序段2
#endif
它的作用是若指定的标识符已经被**#define命令(如出现#define MM 16、#define MM slkjdkajsk,甚至是#define MM)定义过(准确的说是#define 标识符** 就可以),则程序编译阶段编译程序段1,否则编译程序段2
②和①相反
#ifndef 标识符
程序段1
#else
程序段2
#endif

#if 表达式
程序段1
#else
程序段2
#endif

三、文件

文件在编程系统里面属于输入输出的范围,从操作系统的角度看来,所有和系统相连的都是文件,包括键盘是输入文件、显示器和打印机是输出文件、磁盘文件。
c语言把文件是字节的序列,即一个一个的序列组成文件,根据数据的组织形式,可分为ASCII文件(又称文本文件)和二进制文件,两者的区别在于二进制文件是将内存中的数据按其在内存中的存储形式原样的输出到磁盘,但是ASCII文件用ascii的形式域字符一一对应输出。如内存中有整数10000,采用二进制输出为0x2710,2个字节,但是采用ascii的形式的话就是包括"1"、“0”、“0”、“0”、“0”,为5个字节。
一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节。C 语言不仅提供了访问顶层的函数,也提供了底层(OS)调用来处理存储设备上的文件。本章将讲解文件管理的重要调用。

1.文件类型指针


文件 <—> 每个被使用的文件在内存中都被开辟了一个区,用来存放文件的有关信息,这些信息被保存在一个类型为FILE的变量中 <–> FILE *fp,系统使用fp用来指向FILE类型的变量,从而反向找到与它相关的文件
②在程序开始运行的时候,系统自动打开3个标准文件:标准输入、标准输出、标准出错输出,通常这3个文件都与终端相联系,同时系统自动定义了3个文件类型指针stdin、stdout、stderr,分别指向3个终端文件,所以和普通文件一样,直接通过文件指针stdin、stdout、stderr就可以操作终端文件。因此以前我们所任6用到的从终端输入或输出都不需要打开终端文件。
③文件缓冲区(貌似好像叫流):我们知道,当我们打开文件时,系统自动在内存中为每一个打开的文件开辟一个缓冲区,从键盘输入数据的时候,先送到缓冲区,装满之后才一起送入磁盘的文件中(放在了缓冲区中,然后我们从缓冲区中得到我们想要的数据 )。注意和①FILE结构体的区别,但是FILE结构体中有一部分文件缓冲区的信息。

2.文件的操作

在这里插入图片描述
对以上表格进行部分总结:
①以前使用的putchar©是在stdio.h文件中用预处理命令#define定义的宏,因此putchar是由fputc函数派生出来的:
#define putchar(c) fputc(c, stdout) //stdout是系统自己定义的
②为了书写方便,系统把fputc和fgetc定义为宏名putc和getc,是在stdio.h文件中定义的:
#define putc(c,fp) fputc(c, fp)
#define getc(fp) fgetc(fp)

//文件fopen和fclose操作
int main(int argc, char* argv[])
{
	FILE *fp;

	//fopen带回指向a1文件的指针,并将其赋值给fp,这样fp就和文件a1相联系了,
	//或者说fp指向a1文件
	fp = fopen("C:/Users/Marvin/Desktop/c++/project/lesson_09/Debug/a1.txt", "w+");

	
	//fclose就是使fp不再指向文件a1,文件指针变量fp和文件a1脱钩
	//不能再用fp操作文件a1
	fclose(fp);

	return 0;
}

三、C/C++编译系统

①C:Turbo C 2.0、Turbo C 3.0、VC++ 6.0
②C++:VC++ 6.0、GCC(RHIDE-keil、DJGPP-armcc)


总结

以上是我对c/c++语言中要用到的知识做的最后总结,文件的操作涉及到和操作系统和文件系统的问题,这里我的能力不足以做过多的解释,后续看到相关的书籍再做总结。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值