文件——C语言程序设计(十一)

C语言程序设计(十一)

文件

格式化输入输出

printf

  • printf
    • %[flags][width][.prec][hlL]type
Flag含义
-左对齐
+在前面放 + 或 -
(space)正数留空
00填充

举个栗子:

#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单个字节
hshort
llong
lllong long
Llong 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 或 dintgfloat
uunsigned intGfloat
o八进制a 或 A十六进制浮点
x十六进制cchar
X字母大写的十六进制s字符串
f 或 Ffloat, 6p指针
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含义
*跳过
数字最大字符数
hhchar
hshort
llong double
lllong long
Llong 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用于
dint
i整数, 可能为十六进制或八进制
uunsigned int
o八进制
x十六进制
a,e,f,gfloat
cchar
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 : 输出的字符数

  • 在要求严格的程序中,应该判断每次调用scanfprintf的返回值,从而了解程序运行中是否存在问题


文件输入输出

  • ><做重定向

  • > : 输入

  • < : 输出


输入结束

  • getchar读到了EOF
  • scanf返回小于要求读的数量

FILE
  • 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;
}
fopen
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具有明确大小的类型
  • 更好的方案是用文本
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值