第十三周:文件

简介: 重点学习按位运算

13.1-1格式化输入输出格式

%flags.prectype

Flag 含义
- 左对齐
+ 在前面放+或-
(space) 正数留空
0 0填充

#include

intmain(intargc,charconst*argv[])

{

   printf("%9d\n",123);//需要占9个字符的空间,123前还有6个空格

   printf("%-9d\n",123);//一样需要占9个字符,123后面还有6个空格

   printf("%+9d\n",123);//在123前面多上一个+,是可以0时跟左对齐同时进行的

   printf("%09d\n",123);//空格地方变成0,000000123

   

   return0;

}

width或prec 含义
number 最小字符数
* 下一个参数是字符数
.number 小数点后的位数
.* 下一个参数是小数点后的位数

#include

intmain(intargc,charconst*argv[])

{

   printf("%9.2f\n",123.0);//占据9个字符且其中有两位小数

   printf("%*d\n",6,123);//让格式更灵活,6这个数是会替换到*号上的,具体效果就是占据6个字符

   

   return0;

}

类型修饰 含义
hh 单个字节
h short
l long
ll long long
L long double

#include

intmain(intargc,charconst*argv[])

{

   printf("%hhd\n",12345);//只能输入单个字符,输出多个报错

   printf("%hhd\n",(char)12345);//但可以强制类型转换,可以得到57的结果

   printf("%9.2f\n",123.0);

   

   return0;

}

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

intmain(intargc,charconst*argv[])

{

   intnum;

   printf("hhd%n\n",(char)12345,&num);

   printf(num);//以上的意思是,截至到%n为止前面有几位字符,会将多少位字符传递给指针&num的地址

   //然后在下面num就会输出2,因为上面(char)12345的值输出是57,是2位数

   

   return0;

}

scanf:%[flag]type

flag 含义 flag 含义
* 跳过 l long,double
数字 最大字符数 ll long long
hh char L long double
h short
type 用于 type 用于
d int s 字符串(单词)
i 整数,可能为十六进制或八进制可以将读入的八进制和十六进制格式的数值转化为十进制 [...] 所允许的字符
u unsigned int p 指针
o 八进制
x 十六进制
a,e,f,g float
c char

printf和scanf的返回值

  1. 读入的项目数
  2. 输出的字符数
  3. 在要求严格的程序中,应该判断每次调用scanf或printf的返回值,从而了解程序运行中是否存在问题

13.1-3文件输入输出

文件输入输出

  1. 用>和<做重定向

FILE

  1. FILEfopen(const char**restrict path,const char*restrict mode);
  2. int fcolose(FILE*stream);
  3. fscanf(FILE,...)
  4. fprintf(FILE*,...)
  5. fprintf(FILE,...)

打开文件的标准代码

FILE*fp=fopen(“file(文件名),“r”);

if(fp){

   fscanf(fp,...);

   fcolose(fp);

}else{

   ...

}

-----------------------------------------------------------------

   #include

   

   intmain(intargc,charconst*argv[])

{

   FILE*fp=fopen("12.in","r");

   if( fp ){

       intnum;

       fscanf(fp,"%d",&num);

       printf("%d\n",num);

       fclose(fp);

   }else{

       printf("无法打开文件\n");

   }

   return0;

}

fopen

r 打开只读
r+ 打开读写,从文件头开始
w 打开只写。如果不存在则新建,如果存在则清空
w+ 打开读写。如果不存在则新建,如果存在则清空
a 打开追加。如果不存在则新建,如果存在则从文件尾开始
..x 只新建,如果文件已存在则不能打开(防止对文件造成破坏)

13.1-3二进制文件

  1. 其实所有的文件最终都是二进制的
  2. 文件无非是用最简单的方式可以读写的文件
  1. more、tail
  2. cat
  3. vi
  1. 而二进制文件是需要专门的程序来读写的文件
  2. 文本文件的输入输出是格式化,可能经过转码

文本文件 VS 二进制文件

  1. Unix喜欢用文本文件来做数据存储和程序配置
  1. 交互式终端的出现使得人们夏欢用文本和计算机“talk”
  2. Unix的shell提供了一些读写文本的小程序
  1. windows喜欢二进制文件
  1. DOS是草根文化,并不继承和熟悉Unix文化
  2. PC刚开始的时候能力有限,DOS的能力更有限,二进制进行输入输出更接近底层

优劣:

  1. 文本的优势是方便人类读写,而且跨平台
  2. 文本的缺点是程序输入输出要经过格式化,开销大
  3. 二进制的缺点是人类读写困难,而且不跨平台
  1. int的大小不一致,大小端的问题
  1. 二进制的优点是程序读写快

程序为什么要文件

  1. 配置
  1. Unix用文本,Windows用注册表
  1. 数据
  1. 稍微有点量的数据都放数据库了
  1. 媒体
  1. 这个只能是二进制的
  1. 现实是,程序通过第三方库来读写文件,很少直接读写二进制文件了

二进制读写(可跳过,底层)

  1. size_t fread(voidrestrict ptr,size_t size,size_t nitems,FILErestrict stream);
  2. size_t fwrite(const voidrestruct ptr,size_t size,size_t nitems,FILErestrict stream);
  3. 注意FILE指针是最后一个参数
  4. 返回的是成功读写的字节数

为什么nitems

  1. 因为二进制文件的读写一般都是通过对一个结构变量的操作来进行的
  2. 于是nitem就是用于说明这次读写几个结构变量!

在文件中定位

  1. long ftell(FILE*stream);
  2. int fseek(FILE*stream,long offset,int whence);
  1. SEEK_SET:从头开始
  2. SEEK_CUR:从当前位置开始
  3. SEEK_END:从尾开始(倒过来)

#include

#include"student.h"

voidread(FILE*fp,intindex);

intmain(intgrac,charconstgrav[])

{

   FILE*fp=fopen("student.data","r");

   if( fp ) {

       fseek(fp,0L,SEEK_END);

       longsize=ftell(fp);

       intnumber=size/sizeof(Student);

       intindex=0;

       printf("有%d个数据,你要看第几个:",number);

       scanf("%d",&index);

       read(fp,index-1);

       fcolose(fp);

   }

   return0;

}

voidread(FILE*fp,intindex)

{

   fseek(fp,index*sizeof(Student),SEEK_SET);

   Studentstu;

   if( fread(&stu,sizeof(Student),1,fp) ==1){

       printf("第%d个学生:",index+1);

       printf("\t姓名:%s\n",stu.name);

       printf("\t性别:");

       switch ( stu.gender ){

           case0:printf("男\n");break;

           case1:printf("女\n");break;

           case1:printf("其他\n");break;

       }

       printf("\t年龄:%d\n",stu.age);

   }

}

可移值性

  1. 这样的二进制文件不具有可移植性
  1. 在int为32位的机器上写成的数据文件无法直接在int为64的机器上正确读出
  1. 解决方法之一就是放弃使用int,而是使用typedef具有明确大小的类型
  2. 更好的方案是用文本

13.2*位运算

13.2-1按位运算

  1. C有这些按位运算的运算符:其实就是把整数的东西当做二进制来进行运算
·& 按位的与
·| 按位的或
·~ 按位取反
·^ 按位的异或
·<< 左移
·>> 右移

按位与&

  1. 其实就是两组二进制的数,对应的数字必须都为1,新形成的数对应的数才会是1,否则就是0
  2. F:1111 E:1110,FE的作用就是使得跟他对应形成新的数最低位为0

按位或|

  1. 也是两组二进制的数,对应的数字必须都为0,新形成的数对应的数才会是0,否则就是1。跟上面那个相反

按位取反~

#include

intmain(intargc,charconst*argv[])

{

   unsignedcharc=0xAA;

   printf("% c=%hhx\n",c);//aa

   printf("%~c=%hhx\n",(char)~c);//按位取反  55

   printf("%-c=%hhx\n",(char)-c);//补码   56

}

逻辑运算vs按位运算

  1. 对于逻辑运算,它只看到两个值:0和1
  2. 可以认为逻辑运算相当于把所有非0值都变成1,然后做按位运算
  1. 5&4——>4而5&&4——>1&1——>1
  2. 5|4——>5而5||4——>1|1——>1
  3. ~4——>3而!4——>!1——>0

按位异或^

  1. 两组二进制,上下位数值对应相等为0,上下不相等为1
  2. 做两次相同的异或运算数值就翻回去了

移位运算

左移<<

  1. i << j
  2. i中所有的位向左移动j个位置,而右边填入0
  3. 所有小于int的类型,移位以int的方式来做,结果是int
  4. x <<= 1 等价于x*=2
  5. x <<= n 等价于x*=2的n次方

#include

intmain(intargc,charconst*argv[])

{

   unsignedcharc=0xA5;

   printf("  c=%d\n",c);//165

   printf("c<<=%d\n",c<<2);//660

   return0;

}

右移>>

  1. i >> j
  2. 所有小于int的类型,移位以int的方式来做,结果是int
  3. 对于unsigned的类型,左边填入0
  4. 对于signed的类型,左边填入原来的最高位(保持符号不变)
  5. x >>= 1 等价于x/=2
  6. x >>= n 等价于x/=2的n次方

#include

intmain(intargc,charconst*argv[])

{

   inta=0x80000000;

   unsignedintb=0x80000000;

   printf("a=%d\n",a);//-2147483648

   printf("b=%u\n",b);//2147483648

   printf("a>>1=%d\n",a>>1);//-1073741824

   printf("b>>1=%u\n",b>>1);//1073741824

   return0;

}

no zuo no die

  1. 移位的位数不要用负数,这是没有定义的行为
  1. x<<-2 //!!NO!!

13.2-3位运算例子

输出一个数的二进制

#include

intmain(intargc,charconst*argv[])

{

   intnumber;

   scanf("%d",&number);

   number=0x55555555;//输出01010101...,其实就是16个01(32个值)

   unsignedmask=1u<<31;//int被省略但是其实是有生效的

   for(; mask ; mask>>=1 ){

       printf("%d",number&mask?1:0);

   }

   printf("\n");

   

   return0;

}

13.2-4位段

  1. 把一个int的若干位组合成一个结构

struct{

   unsignedintleading : 3;//冒号后面的数字表示占几个比特

   

   unsignedintFLAG1:1;

   

   unsignedintFLAG2:1;

   

   inttrailing:11;

};

  1. 可以直接用位段的成员名称来访问
  1. 比移位、与、或还方便
  1. 编译器会安排其中的位的排列,不具有可移植性
  2. 当所需的位超过一个int时会采用多个int
目录
相关文章
|
程序员
773.每周复盘-第十二周
773.每周复盘-第十二周
102 0
|
安全 Unix 编译器
第十二周:程序结构
你已经快坚持到了最后,很棒!
116 0
一周总结(十八)
基本上都是程序上的事情,周围的事情记得很少。 读Shiro源码,Shiro的Session管理,Shiro的多Realm多登陆页面。 读Mybatis源码,关于Cache的控制,Exector部分 学习了React的语法,React Nactive做了小Demo 周末看了加勒比海盗2,3.看了死侍。
一周总结(十六)
最近几周生活太类似了,想写的时候发现生活没什么变化。每天就是早上8点工作,到晚上11点钟,回来累了,点开一个视频看一会,然后睡觉,反复三个星期。 这段时间,App又完善了一些,产品方面的东西投入时间比较多,一直在进步。
|
缓存 Java 数据库连接
一周总结(十五)
每天都在优化程序,优化项目。增加一些小功能等等。好像编程机器一样。 事情 写程序,权限管理,后台优化操作,解决偶尔出现的问题。使用了阿里云的Memcache;使用Memcache代理;解决服务器偶尔出现的问题,磁盘空间被日志塞满了,无法保存session,及编辑文件;解决Mybatis-redis集成问题;研读Mybatis缓存源码。
一周总结(十四)
已经过去10天了,读书笔记还没写呢,每天确实是10点多就回去了,但是比预期的稍微晚一点,回去后基本在看看奇葩说。 事情 东西改善的地方没有很多,在做新的功能,有点慢 放假之前去老码头店吃火锅 平时听一听书,听的不多,看看奇葩说,奇葩说看了好几集。
一周总结(十二)
每周都是过的飞快,转眼就是十天左右的时间。 事情 面试了十几个技术人员,大部分是前端,3个Java工程师 不断的翻看淘宝开放平台的文档 App继续完善 去凯宾斯基酒店吃饭 感受 年龄越大,时间过的就越快,遇到了问题,几天时间眨眼间就过去了。
|
Web App开发 Java Spring
一周总结(十一)
距离上次总结过了两个星期了,时间过得真的很快。 上次总结,提到了自己做了Google Chrome浏览器插件,然后app基本可以使用了。毕竟之前有些闭门造车,没有拿出去给用户使用。