当前位置:网站首页>C语言程序设计笔记(浙大翁恺版) 第十三周:文件
C语言程序设计笔记(浙大翁恺版) 第十三周:文件
2022-08-09 14:23:00 【CS_Lee_】
按照中国大学MOOC上浙江大学翁恺老师主讲的版本所作,B站上也有资源。原课程链接如下:
https://www.icourse163.org/course/ZJU-9001
由于是大三抽空回头整理的,所以可能前五章会记的内容比较简略。此外,作为选学内容的A0:ACLLib的基本图形函数和链表两章也没有做。西电的考试是机试,理论上学到结构体就能够应付考试了,但为了以后的学习考虑建议全学。
其他各章节的链接如下:
文件
文件
格式化输入输出
格式化的输入输出
printf%[flags][width][.prec][hIL]type
scanf%[flag]type
%[flags][width][.prec][hIL]type




示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%9d\n", 123);
printf("%+9d\n", 123);
printf("%-9d\n", 123);
printf("%+-9d\n", 123);
printf("%-+9d\n", 123);
printf("%-+9d\n", -123);
printf("%-9d\n", -123);
printf("%09d\n", 123);
// printf("%-09d\n", -123);
return 0;
}
123
+123
123
+123
+123
-123
-123
000000123
示例2:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int len = 6;
printf("%*d\n", len, 123);
printf("%9.2f\n", 123.0);
return 0;
}
123
123.00
示例3:
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%hhd\n",12345);
return 0;
}

12345=0x3039,0x39=57
改为(char)12345不产生警告
示例4:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
printf("%hhd%n\n", (char)12345, &num);
printf("%d\n", num);
printf("%d%n\n", 12345, &num);
printf("%d\n",num);
printf("%dty%n\n",12345, &num);
printf("%d\n",num);
return 0;
}
57
2
12345
5
12345ty
7
%n表示printf到此时已经输出了多少字符,然后填到指针所指的变量里
scanf:%[flag]type


示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%*d%d", &num);
printf("%d\n", num);
return 0;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iy53sgdc-1659892983885)(C语言程序设计.assets/image-20220803165042678.png)]](/img/b6/b0762920ad3520b046f9142cee7c43.png)
-o选项指定编译产生的可执行文件名
示例2:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%i", &num);
printf("%d\n", num);
return 0;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cwjku7VR-1659892983887)(C语言程序设计.assets/image-20220803165454196.png)]](/img/e1/e08557d548df6caf438be623455b78.png)
[^.]
示例:

这是GPS模块产生的数据,以”$“开头,所有字段以”,“分隔,有时两个”,“之间可能没有内容,用scanf读入
%*[^.]表示省略到逗号之前的所有内容,%[^.]表示到逗号之前的所有内容作为字符串读入
printf和scanf的返回值分别是读入的项目数和输出的字符数
在要求严格的程序中,应该判断每次调用scanf或printf的返回值,从而了解程序运行中是否存在问题
示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
int i1 = scanf("%i", &num);
int i2 = printf("%d\n", num);
printf("%d:%d\n", i1, i2);
return 0;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Yh8Wa5M-1659892983889)(C语言程序设计.assets/image-20220803191517431.png)]](/img/7e/638f243221165a87a14bffd775b54c.png)
文本文件输入输出
用>和<做重定向
如果程序是用printf和scanf来做输入输出的,可以用程序运行时的重定向,<指定一个文件作为输入,>指定一个文件写入输出
示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
int i1 = scanf("%i", &num);
int i2 = printf("%d\n", num);
printf("%d:%d\n", i1, i2);
return 0;
}

用cat打开一个文件,重定向到一个文件从而可以往里写内容
FILE
stdio.h头文件里已经声明了FILE*类型
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMDPvLlf-1659892983893)(C语言程序设计.assets/image-20220803192741048.png)]](/img/3c/f41d87074598328f42a08c5fe37230.png)
打开文件的标准代码
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8XSOmH0-1659892983895)(C语言程序设计.assets/image-20220803192818031.png)]](/img/b4/2a4935831cff30970930418c410be5.png)
指针变量fp指向一个FILE结构,该结构代表了打开文件的一些信息
fopen没有打开文件会返回NULL
示例:
#include <stdio.h>
int main(int argc, char const *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;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GsEyz7eP-1659892983896)(C语言程序设计.assets/image-20220803193110607.png)]](/img/d6/07c5580d8e62aca88535e359c9c210.png)
fopen
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbfNsfAL-1659892983897)(C语言程序设计.assets/image-20220803193148189.png)]](/img/e5/3d4ead1ef8dccb7682aea24d86e8e5.png)
二进制文件
之前见的所有文件都是文本文件,输入输出都是文本方式。当printf一个int时实际上是把这个int格式化成人可读的字符串形式,该int在计算机内部是二进制形式,用4B表达。当输入一个int时,scanf扫描输入字符串从中识别出int填到一个int类型变量里
二进制文件
其实所有的文件最终都是二进制的,只不过文本文件表现为人可以阅读的形式,无非就是可以用最简单的方式读写
在Unix下,有很多简单的工具对文本文件进行操作,如可用more,tail,cat,vi打开和编辑文件。但是二进制文件,如可执行文件、JPG图片、MP3音频等需要专门的程序来查看和读写
文本 vs 二进制
Unix喜欢用文本文件来做数据存储和程序配置
- 交互式终端的出现使得人们可以喜欢用文本和计算机“talk”,输入和输出可见都是文本
- Unix的shell提供了一些可以读写的程序
Windows喜欢用二进制文件
- DOS是草根文化,并不继承和熟悉Unix文件
- PC刚开始的时候能力有限,DOS的能力更有先,二进制更接近底层
文本的优势是方便人类读写,而且跨平台。文本的缺点是程序输入输出需要格式化,开销大
二进制的的缺点是人类读写困难,而且不跨平台(int的大小不一致,大小端的问题 …)。二进制的优点是程序读写快
程序为什么要操作文件
配置:程序有配置信息,比如窗口大小、字体颜色等等。Unix传统用文本文件配置数据,直接用vi就能编辑。Windows传统将这些配置数据写在注册表里,注册表是一个非常大的二进制文件,整个Windows所有软件的配置信息都写在里面,需要用专门的工具如regedit注册表编辑器才能编辑
数据: 稍微有点量的数据都放数据库了。有数据库的接口库,用函数调用读写数据库
媒体:图片、声音、视频等肯定是二进制的
现实是,程序通过第三方库来读写文件,很少直接读写二进制文件了
二进制读写

ptr指向要读写的内存,size表示这块内存有多大,nitems表示有几个这样的内存,stream是文件指针
二进制文件的读写一般都是通过对一个结构变量的操作来进行的,要写的数据在一个结构里,一次写一个或多个结构。所以size其实指的是一个结构的大小,nitems就是用来说明这次读写几个结构变量
示例:





用图形工具打开二进制文件student.data,左边是二进制数据,右边试图把这些二进制数据变成字符串让用户看到
在文件中定位

示例:


可移植性
这样的二进制不具有可移植性。如在int为32位的机器上写成的数据文件无法直接在int为64位的机器上正确读出
解决方案之一是放弃使用int,而是typedef具有明确大小的类型
更好的方案是用文本
位运算
按位运算
按位运算
C有这些按位运算的运算符
&按位的与|按位的或~按位取反^按位的异或<<左移>>右移
按位与&
如果 ( x ) i = = 1 (x)_i ==1 (x)i==1并且 ( y ) i = = 1 (y)_i==1 (y)i==1,那么 ( x & y ) i = 1 (x\&y)_i=1 (x&y)i=1,否则 ( x & y ) i = 0 (x\&y)_i=0 (x&y)i=0
按位与常用于两种应用:
- 让某一位或某些位为0:
x & 0xFE - 去某一个数中的某一段:
x & 0xFF
按位或|
如果 ( x ) i = = 1 (x)_i ==1 (x)i==1或 ( y ) i = = 1 (y)_i==1 (y)i==1,那么 ( x ∣ y ) i = 1 (x|y)_i=1 (x∣y)i=1,否则 ( x ∣ y ) i = 0 (x|y)_i=0 (x∣y)i=0
按位或常用于两种应用:
- 让某一位或某些位为1:
x | 0x01 - 把两个数拼起来:
0x00FF & 0xFF00
按位取反~
( ∼ x ) i = 1 − ( x ) i (\sim x)_i=1-(x)_i (∼x)i=1−(x)i,把1位变0,0位变1
- 想得到全部位为1的数:
~0 - 7的二进制是0111,
x | 7使得低3位为1,而x & ~7就使得低3位为0
按位取反和算补码不一样,算补码要做减法

示例:
0xAA的按位取反和做补码
#include <stdio.h>
int main(int argc, char const *argv[])
{
unsigned char c = 0xAA;
printf(" c=%hhx\n", c);
printf("~c=%hhx\n", (char)~c);
printf("-c=%hhx\n", (char)-c);
return 0;
}
c=aa
~c=55
-c=56
有符号数求相反数的实现就是求补码
按位取反和做补码计算结果是int,期望作为一个字节大小的整数输出,所以类型转换为char
逻辑运算 vs 按位运算
对于逻辑运算,它只看到两个值:0和1
可以认为逻辑运算相当于把所有非0值都变成1,然后做按位运算
示例:
5 & 4 —> 4 而 5 && 4 —> 1 & 1 —> 1
5 | 4 —> 5 而 5 || 4 —> 1 | 1 —> 1
~4 —> 3 而 !4 —> !1 —> 0
按位异或^
如果 ( x ) i = = ( y ) i (x)_i ==(y)_i (x)i==(y)i,那么 ( x ^ y ) i = 0 (x \verb|^| y)_i=0 (x^y)i=0,否则 ( x ^ y ) i = 1 (x \verb|^| y)_i=1 (x^y)i=1
- 如果
x和y相等,那么x ^ y的结果为0 - 对一个变量用同一个值异或两次,等于什么也没做:
x ^ y ^ y等于x
移位运算
左移<<
i << ji中所有的位向左移动j个位置,而右边填入0
所有小于int的类型,移位以int的方式来做,结果是int
x << 1等价于 x = x × 2 x=x\times2 x=x×2,x << n等价于 x = x × 2 n x=x\times 2^n x=x×2n,最多可以移多少位取决于int有多大
示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
unsigned char c = 0xA5;
printf(" c=%hhx\n", c);
printf("c<<2=%hhx\n", c<<2);
return 0;
}
编译时会产生warning,当前编译器所有的按位运算结果都被当作是int
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9iKhB54-1659892983920)(C语言程序设计.assets/image-20220804161144291.png)]](/img/52/e55f1b066c39c64205a9e986e12547.png)
如果将printf("c<<2=%hhx\n", c<<2)改为printf("c<<2=%x\n", c<<2)按照int的方式输出,得
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uk6F5xZx-1659892983921)(C语言程序设计.assets/image-20220804161509678.png)]](/img/18/edd3549c272c3ecd96dbd882e0e6bd.png)
如果改为printf(" c=%d\n", c)和printf("c<<2=%d\n", c<<2)当作十进制输出,得

165和660之间是4倍关系
右移>>
i >> ji中所有的位向右移j位
所有小于int的类型,移位以int的方式来做,结果是int
对于unsigned的类型,左边填入0。对于signed的类型,左边填入原来的最高位(保持符号不变)
x >> 1等价于 x = x / 2 x=x/2 x=x/2,x << n等价于 x = x / 2 n x=x /2^n x=x/2n
示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 0x80000000;
// 1000000000000...000
// 11000000...00000000
unsigned int b = 0x80000000;
printf("a=%d\n", a);
printf("b=%u\n", b);
printf("a>>1=%d\n", a>>1);
printf("b>>1=%u\n", b>>1);
return 0;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-he7AvTqu-1659892983923)(C语言程序设计.assets/image-20220804162952243.png)]](/img/96/c8f62657cecf1b6b3f6aa601a4554f.png)
如果将printf("a>>1=%d\n", a>>1)和printf("b>>1=%u\n", b>>1)改为printf("a<<1=%u\n", a<<1)和printf("b<<1=%u\n", b<<1)做左移
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HDjUOVAK-1659892983924)(C语言程序设计.assets/image-20220804163437029.png)]](/img/a1/ab387f9e8e82f9218f609e2b9e2dae.png)
移位的位数不要用负数,这是没用定义的行为
位运算例子
输出一个数的二进制
示例:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int number;
scanf("%d", &number);
unsigned mask = 1u<<31;
for ( ; mask ; mask >>=1 ) {
printf("%d", number & mask?1:0);
}
printf("\n");
return 0;
}
unsigned mask会被编译器理解为unsigned int mask
1u表示最低位为1的unsigned数
按照器件手册在单片机程序中用位运算设置特殊功能寄存器(SFR)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGN8Zm89-1659892983924)(C语言程序设计.assets/image-20220804164624457.png)]](/img/e4/d1d29d6a86522c38854e83b334f732.png)
位段
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcZDfb1R-1659892983925)(C语言程序设计.assets/image-20220804170602373.png)]](/img/e6/22206b8236fa72b246019e95995890.png)
位段
为了简单地控制多个bit,把一个int的若干位组合成一个结构
示例:
struct {
unsigned int leading : 3;
unsigned int FLAG1 : 1;
unsigned int FLAG2 : 1;
int trailing : 11;
};
unsigned int leading : 3;表示这个成员占3个bit,最后可能所有成员放在一个int里,而每一个成员占据其中的某些bit
示例2:
#include <stdio.h>
void prtBin(unsigned int number);
struct U0 {
unsigned int leading : 3;
unsigned int FLAG1 : 1;
unsigned int FLAG2 : 1;
int trailing : 27;
};
int main(int argc, char const *argv[])
{
struct U0 uu;
uu.leading = 2;
uu.FLAG1 = 0;
uu.FLAG2 = 1;
uu.trailing = 0;
printf("sizeof(uu)=%lu\n", sizeof(uu));
prtBin(*(int*)&uu);
return 0;
}
void prtBin(unsigned int number)
{
unsigned mask = 1u<<31;
for ( ; mask ; mask >>=1 ) {
printf("%d", number & mask?1:0);
}
printf("\n");
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CX3AuUyc-1659892983927)(C语言程序设计.assets/image-20220804171714574.png)]](/img/0a/7a7d88cc49cadef5640bbb0d0bc008.png)
如果注释掉int trailing : 27;和uu.trailing = 0,得
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zxxKbe2P-1659892983927)(C语言程序设计.assets/image-20220804171902184.png)]](/img/9b/4af22f7094a92e505aece63931c5a2.png)
前面的部分没有赋初值
如果将int trailing : 27;改为int trailing : 32;,得
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ybii7183-1659892983928)(C语言程序设计.assets/image-20220804172030296.png)]](/img/61/df9d6157c5ebb7b094ea58c3c121d1.png)
此时所有的位数加起来已经超过了32,所以需要两个int来表达这个位段
可以直接用位段的成员名称来访问,比移位、与、或还方便
编译器会安排其中的位的排列,不具有可移植性,在演示的编译器上从最右边排起,可能别的就是从最左边排起
当最所需的位超过一个int时会采用多个int
边栏推荐
- MySQl表的增删查改(聚合查询+联合查询)
- 除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效
- *1-5 OJ 642 Russian Multiplication
- Simulink simulation pid control servo system
- 看完腾讯大佬90天整理的“Redis深度笔记”,我直接当场膜拜
- A wave of Versailles: assault by the ali interview guide, I've got nine of the Offer
- 网站小程序开发有哪些步骤?
- 外贸软件如何提升进出口公司业绩 实现降本增效
- 下班后用微信工作发病是否属于工伤?法院这样判
- 在Word中如何调整编号和文字之间的间距?
猜你喜欢

The code implementation of chess

概率论基础知识整理 | 随机向量

项目小操作:form表单的校验,以及第二次显示提示校验内容等问题

A wave of Versailles: assault by the ali interview guide, I've got nine of the Offer

table中 You may have an infinite update loop in a component render function问题解决

RHCE Course Summary

从TRPO到PPO(理论分析与数学证明)

*2-1 OJ 254 Flip Pancakes

Use Baidu EasyDL to realize intelligent identification of health code/travel code in 30 minutes

* 2-2 OJ 1163 missile interception of beta
随机推荐
#25-1 OJ 78 Calculate birthday day of the week
[Video coding learning] - SAD and SATD
RHCE Course Summary
不要小看一个Redis!从头到尾全是精华,阿里Redis速成笔记太香了
*3-1 CCF 2014-09-1 Adjacent pairs
论文笔记CIRS
跨境电商独立站?Lighthouse: WooCommerce!
Refuse to "reinvent the wheel", Baidu EasyDL lets you play with AI custom development
RHCE Course Summary
同事的接口文档我每次看着就头大,毛病是真的多多多。。。
SwiftUI 导航教程之如何实现没有 Navigation View的 SwiftUI 导航功能
resNet_model—定义残差网络模型
Unity Obi插件修改到支持URP
The rising star DPU is revolutionizing the data center!
The RHCE course summary
Zero Time Technology | Nomad cross-chain bridge theft of 180 million US dollars incident analysis
运维--常用中间件
[Serilog] Simple .NET logging with fully structured events
ArcGIS在国土空间·城乡规划中的实战应用
新起之秀 DPU,正在掀起数据中心变革!