C语言程序设计(十一)
文章目录
文件
格式化输入输出
printf
printf
%[flags][width][.prec][hlL]type
Flag | 含义 |
---|---|
- | 左对齐 |
+ | 在前面放 + 或 - |
(space) | 正数留空 |
0 | 0填充 |
举个栗子:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("%9d\n", 123); //输出占据9个字符的空间(包括123一共占据9个字符, 前面6个用空格占据)
printf("%-9d\n", 123); //左对齐, 输出占9个字符的空间
printf("%+9d\n", 123); //强制输出+号
printf("%+-9d\n", 123); //左对齐, 并且强制输出+号; 输出占9个字符的空间
printf("%+-9d\n", -123); //负数不能强制输出+号
printf("%09d\n", 123); //前面都用0 来填充, 即用0 代替前面的空格
printf("%-09d\n", 123); //左对齐不能前面填0, 即使填0也不会显示
return 0;
}
输出结果:
123
123
+123
+123
-123
000000123
123
width 或 prec | 含义 |
---|---|
number | 最小字符数 |
* | 下一个参数是字符数 |
.number | 小数点后的位数 |
.* | 下一个参数是小数点后的位数 |
举个栗子:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%9.2f\n", 123.0); //9代表占据9个字符, .2代表保留小数点后两位
printf("%*d\n", 6, 123); //*号代表有参数输入, 比如6就代替*号, 与上面的意思一样, 把6插入换掉*号,相当于printf("%6d\n",123);即占据6个字符的位置
int i = 9;
printf("%*d\n", i, 123); //可以用变量替代
printf("%*.2f\n", i, 123.0);
return 0;
}
输出:
123.00
123
123
123.00
类型修饰 | 含义 |
---|---|
hh | 单个字节 |
h | short |
l | long |
ll | long long |
L | long double |
int main(int argc, char *argv[])
{
printf("%hhd\n", 12345678); //一个int型占4个字节; 但%hh输出一个字节的整数; 相当于char的长度
printf("%hhd\n", (char)12345678); //输出一个字节的整数; 相当于char的长度, 取低4位
printf("%hd\n", 12345678);
printf("%ld\n", 12345678);
printf("%lld\n", 12345678);
printf("%Ld\n", 12345678);
//计算机内部都是以二进制运算, 输出是转化成十进制再输出
return 0;
}
输出:
24910
78
24910
12345678
12345678
12345678
说明一下: 12345678是为十进制, 转化为十六进制为BC614E
而char为占据一个字节(8位)的空间, 即两个位十六进制数即可表示8位二进制数, 因此低2位为4E, 转化为十进制为78
而两个字节为16位, 即614E 转为十进制为24910
type | 用于 | type | 用于 |
---|---|---|---|
i 或 d | int | g | float |
u | unsigned int | G | float |
o | 八进制 | a 或 A | 十六进制浮点 |
x | 十六进制 | c | char |
X | 字母大写的十六进制 | s | 字符串 |
f 或 F | float, 6 | p | 指针 |
e 或 E | 指数 | n | 读入/写出的个数 |
举个栗子:
#include <stdio.h>
int main(int argc, char *argv[])
{
int num;
printf("%d %n\n", 12345, &num); //%n是统计输出的字符数, 然后将值赋给num
printf("%d\n", num);
printf("%dty%n\n", 12345, &num);
printf("%d\n", num);
return 0;
}
scanf
scanf
%[flag]type
flag | 含义 |
---|---|
* | 跳过 |
数字 | 最大字符数 |
hh | char |
h | short |
l | long double |
ll | long long |
L | long double |
举个栗子 :
#include <stdio.h>
int main(int argc, char *argv[]) {
int num;
scanf("%*d%d", &num); //表示有两次输出, 但跳过第一次输出内容; 即*号表示跳过
printf("%d\n", num);
return 0;
}
输出:
123
456
456
type | 用于 |
---|---|
d | int |
i | 整数, 可能为十六进制或八进制 |
u | unsigned int |
o | 八进制 |
x | 十六进制 |
a,e,f,g | float |
c | char |
s | 字符串(单词) |
[…] | 所允许的字符 |
p | 指针 |
举个栗子:
#include <stdio.h>
int main(int argc, char *argv[]) {
int num;
scanf("%i", &num); //表示可以输入八进制,十六进制, 或其他进制数
printf("%d\n", num);
return 0;
}
输出结果:
0123
83
注: 0
开头为八进制; 0x
开头为十六进制
-
//$GPRMC,004319.00,A,3016.98468,N,12006.39211,E, 0.047,,130909,,,D*79
-
scanf("%*[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", sTime,sAV,sLati,&sNW,sLong,&sEW,sSpeed,sAngle,sDate);
printf 和 scanf 的返回值
-
scanf
: 读入的项目数 -
printf
: 输出的字符数 -
在要求严格的程序中,应该判断每次调用
scanf
或printf
的返回值,从而了解程序运行中是否存在问题
文件输入输出
-
用
>
和<
做重定向 -
>
: 输入 -
<
: 输出
输入结束
getchar
读到了EOF
scanf
返回小于要求读的数量
-
FILE* fopen(const char* restrict path, const char* restrict mode);
fopen(文件名, 类型)
FILE
是一个结构, 系统内置的
-
int fclose(FILE *stream);
-
fscanf(FILE*, ...)
-
fprintf(FILE*, ...)
打开文件的标准代码
FILE* fp = fopen(“file”,“r”); //打开文件
if ( fp ) { //判断文件是否打开, 如果是不是null(即fp非空咯), 就输出文件内容
fscanf(fp,...); //输入文件的内容
fclose(fp); //关闭文件
} else {
...
}
例如:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("12.in", "r");
if(fp){
int num;
fscanf(fp, "%d", &num);
printf("%d\n", num);
fclose(fp);
}else{
printf("无法打开文件\n");
}
return 0;
}
r | 打开只读 |
---|---|
r+ | 打开读写,从文件头开始 |
w | 打开只写。如果不存在则新建,如果存在则清空 |
w+ | 打开读写。如果不存在则新建,如果存在则清空 |
a | 打开追加。如果不存在则新建,如果存在则从文件尾开始 |
…x | 只新建,如果文件已存在则不能打开 |
二进制文件
-
其实所有的文件最终都是二进制的
-
文本文件无非是用最简单的方式可以读写的文件 (用UNIX系统)
- more、tail
- cat
- vi
-
而二进制文件是需要专门的程序来读写的文件
-
文本文件的输入输出是格式化,可能经过转码
文本 vs 二进制
-
Unix喜欢用文本文件来做数据存储和程序配置
- 交互式终端的出现使得人们喜欢用文本和计算机“talk”
- Unix的shell提供了一些读写⽂文本的小程序
-
Windows喜欢用二进制⽂文件
-
DOS是草根文化,并不继承和熟悉Unix文化
-
PC刚开始的时候能力有限,DOS的能力更有限,二进制更接近底层
-
- 文本的优势是方便人类读写,而且跨平台
- 文本的缺点是程序输入输出要经过格式化,开销大
- 二进制的缺点是人类读写困难,而且不跨平台
- int的大小不一致,大小端的问题… - 二进制的优点是程序读写快
程序为什么要文件
-
配置
- Unix用文本,Windows用注册表
-
数据
- 稍微有点量的数据都放数据库了
-
媒体
-
这个只能是二进制的
-
现实是,程序通过第三方库来读写文件,很少直接读写二进制文件了
二进制读写
-
size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
-
size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
-
注意
FILE
指针是最后一个参数 -
返回的是成功读写的字节数
为什么nitem?
-
因为二进制文件的读写一般都是通过对一个结构变量的操作来进⾏行的
-
于是
nitem
就是用来说明这次读写几个结构变量!
在文件中定位
-
long ftell(FILE *stream);
-
int fseek(FILE *stream, long offset, int whence);
-
SEEK_SET:从头开始
-
SEEK_CUR:从当前位置开始
-
SEEK_END:从尾开始(倒过来)
-
可移植性
- 这样的二进制文件不具有可移植性
- 在int为32位(实际上就是32位机)的机器上写成的数据文件无法直接在int为64位(64位机)的机器上正确读出
- 解决方案之一是放弃使用int,而是typedef具有明确大小的类型
- 更好的方案是用文本