C语言 笔记5

OrzMiku / 2023-08-20 / 原文

格式化输入输出

输入 - printf

printf("%[flags][width][.prec][hlL]type...",参数表...);

返回值

输出的字符数

flag

Flag 含义
- 左对齐
+ 给一个正数强制加一个+号
(space) 正数留空
0 左边补零,不能和左对齐同时使用

width和prec

width 含义
number 最小字符数(整个输出,包括小数点和小数点后的数)
* 下一个参数是字符数
prec 含义
.number 小数点后的位数
.* 下一个参数是小数点后的位数
/* 关于"*" */
printf("%*d",6,10); // 6会被填到*的位置,然后按%6d的格式print 10

修饰类型

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

type

type 用于 type 用于
i 或 d int g float
u unsigned int G float
o 八进制 a 或 A 16进制浮点数
x 十六进制 c char
X 字母大写的十六进制 s string
f 或 F float.6 P 指针
e 或 E 指数 n 读入/写出的个数

关于 %n 的一个例子:

int num = 0;
printf("12345%s%n\n","hello",&num);
printf("%d\n",num);

输出结果:

12345hello
10

输出 - scanf

scanf("%[flag]type...",参数表...);

返回值

读入的项目数(不是读入的字符数)

flag

flag 含义 flag 含义
* 跳过 l long, double
数字 最大字符数 ll long long
hh char L long double
h short

关于 * 的一个例子:

int num = 0;
scanf("%*d%d",&num);
printf("%d\n",num);

输入:

123 456	

输出:

456

type

type 用于 type 用于
d int s 字符串(单词)
i 正数,可能为非十进制 [...] 所允许的字符
u unsigned int p 指针
o 八进制
x 十六进制
a,e,f,g float
c char

关于 i 的一个例子

int num = 0;
for(int i = 0; i < 3; i++){
	scanf("%i",&num);
    printf("%d\n",num);
}

输入:

12
012
0x12

输出:

12
10
18

文件输入输出

重定向方式

使用>和<做输出输入重定向.假设有这样一个程序(可执行程序名:test):

#include<stdio.h>

int main(void){
    int num = 0;
    scanf("%d",&num);
    int cnt = 1;
    while(num/10 != 0){
        num /= 10;
        cnt++;
    }
    printf("这个数有%d位\n",cnt);
    return 0;
}

如果我们想将输出结果存在result.txt文件中,可以:

./test > result.txt
123

result.txt:

这个数有3位

如果我们想从一个input.txt文件输入,可以:

input.txt:

123
./test < input.txt
这个数有3位

FILE

stdio.h中,声明了一种类型FILE(一种结构,里面包含了打开文件的一些信息).

可以使用fopen()来打开一个文件.他的用法如下:

FILE *xxx = fopen("文件名","打开方式");
打开方式 含义
r 只读,从文件头开始
r+ 读且可写,从文件头开始
w 只写,不存在则新建,存在则清空原有内容
w+ 写且可读,不存在则新建,存在则清空原有内容
a 追加,不存在则新建,存在则在文件尾追加
x 只新建,如果文件存在则不能打开(与w和w+配合使用可以保护文件不被破坏)

打开文件后可以使用fscanf()来做输入.

fscanf(文件指针,"输入格式",参数表);

使用fprintf()来做输出.

fprintf(文件指针,"输出格式",参数表);

使用完文件后,记得用fclose()来关闭文件.

fclose(文件指针);

下面是一个示例程序:

#include<stdio.h>
typedef struct _studentInfo{
    char name[20];
    char sex[3];
    int age;
} stuInfo;
int main(void){
    FILE *db = fopen("studentInfo.db","w");
    int n = 0;
    scanf("%d",&n);
    stuInfo list[n];
    int cnt = 0;
    while(n--){
        printf("请输入第%d个学生的信息:\n",cnt+1);
        printf("%10s\n","姓名:");
        scanf("%s",list[cnt].name);
        getchar();
        printf("%10s\n","性别:");
        scanf("%s",list[cnt].sex);
        printf("%10s\n","年龄:");
        scanf("%d",&list[cnt].age);
        fprintf(db,"姓名:%s|性别:%s|年龄:%d\n",\
                list[cnt].name,list[cnt].sex,list[cnt].age);
        cnt++;
    }
    fclose(db);
    return 0;
}

输入:

2
请输入第1个学生的信息:
   姓名:
orzmiku
   性别:
+  
   年龄:
18
请输入第2个学生的信息:
   姓名:
dzoer
   性别:
+
   年龄:
15

输出 (studentInfo.db) :

orzmiku@MikuNet(~/Study/文件)$ cat studentInfo.db
姓名:orzmiku|性别:+|年龄:18
姓名:dzoer|性别:+|年龄:15

二进制文件

可以使用fread和fwrite对二进制文件进行操作.

fwrite 和 fread函数的用法小结 | 菜鸟教程 (runoob.com)

位运算

位运算符 含义
&
|
~
^ 异或
<< 左移
>> 右移

按位运算

按位与 &

01011010 & 11110101 = 01010000

常用应用:

  • 让某一位或者某些位为0

    • 11111110 & xxxxxxxx , 让前七位原封不动,最后一位无论是1还是0都变成0
  • 取一个数中的一段

    • 00011000 & xxxxxxxx, 只要中间两个数,其余数变成0

按位或 |

01011010 & 01010101 = 01011111

常用应用:

  • 让某一位或者某些位为0
    • 00000001 | xxxxxxxx , 让前七位原封不动,最后一位无论是1还是0都变成1
  • 将两个数拼起来
    • 如: 11000011 | 00111100 = 11111111

按位取反 ~

~ 00001111 = 11110000

按位异或 ^

10101100 ^ 01011100 = 00001111

  • 如果两个相等的数进行异或运算,结果为0

  • 对于同一值异或两次,原数值不变

按位异或有一个应用,可以不创建第三个变量来交换两个变量的值:

int a = 1;
int b = 2;
// a => 1; b => 2;
a = a^b;
b = a^b;
a = a^b;
// a -> 2; b => 1;

位移运算

左移 <<

  • i << j
    • i中所有的位向左移动j位,右边填0
    • 所有小于int的类型,位移以int的方式来做
  • x <<= 1 <==> x *= 2
  • x <<= n <==> x *= pow(2,n)
  • 上面这两点可以用二进制的按权展开来理解

右移 >>

  • i >> j
    • i中所有的位向右移动j位
    • 所有小于int的类型,位移以int的方式来做
    • 对于unsigned类型,左边填0
    • 对于sign类型,由于最左边的那一位是符号位,因此符号位不变
  • x >>= 1 <==> x *= 1/2
  • x >>= n <==> x *= 1/pow(2,n)
  • 上面这两点可以用二进制的按权展开来理解