478 lines
8.9 KiB
Markdown
478 lines
8.9 KiB
Markdown
# 目录
|
||
- [目录](#目录)
|
||
- [第三章 输入输出专题](#第三章-输入输出专题)
|
||
- [内容](#内容)
|
||
- [格式化输入输出函数](#格式化输入输出函数)
|
||
- [`printf`](#printf)
|
||
- [`scanf`](#scanf)
|
||
- [字符输入输出函数](#字符输入输出函数)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# 第三章 输入输出专题
|
||
|
||
input & output -> I/O(标准IO,文件IO)
|
||
|
||
|
||
|
||
## 内容
|
||
|
||
1. 格式化输入输出函数:`scanf`, `printf`
|
||
2. 字符输入输出函数:`getchar`, `putchar`
|
||
3. 字符串输入输出函数:`gets(!)`,`puts`
|
||
|
||
|
||
|
||
## 格式化输入输出函数
|
||
|
||

|
||
|
||

|
||
|
||
### `printf`
|
||
|
||
```c
|
||
int printf(const char *format, ...);
|
||
format: "%【修饰符】格式字符",参照图片标准输出修饰符和格式字符
|
||
```
|
||
|
||
|
||
|
||
- 有关`l`修饰符的提醒
|
||
|
||
```C
|
||
int main()
|
||
{
|
||
FILE *fp;
|
||
long a = 11;
|
||
|
||
fp = fopen();
|
||
|
||
// 可行,a定义了long型,与函数要求一致
|
||
func(fp, a);
|
||
|
||
// 早期的编译器不认可,这个12没有单位,不同编译器默认类型不同
|
||
// 需要加上L修饰符
|
||
func(fp, 12);
|
||
func(fp, 12L);
|
||
// 对于func(FILE *fp, long long i)
|
||
func(fp, 12LL);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
传输一个5G的文件
|
||
|
||
```c
|
||
5LL*1204LL*1204LL*1204LL
|
||
```
|
||
|
||
|
||
|
||
定义一个宏,表示一年有多少秒
|
||
|
||
```c
|
||
// 定义一年有多少秒
|
||
#define SEC_YEAR (60LL * 60LL * 24LL * 365LL)
|
||
```
|
||
|
||
|
||
|
||
- 函数 变参与定参重载的区别
|
||
|
||
- 变参:编译器只报警告,函数自己都不知道自己有多少个参数
|
||
|
||
- 定参重载:编译报错
|
||
|
||
|
||
|
||
- `\n`的作用
|
||
|
||
强制刷新缓冲区,以死循环调试举例。
|
||
|
||
```c
|
||
// 不加\n,before while()存入了缓冲区,故不输出
|
||
// printf("[%s:%d]before while().", __FUNCTION__, __LINE__);
|
||
printf("[%s:%d]before while().\n", __FUNCTION__, __LINE__);
|
||
while (1)
|
||
{
|
||
}
|
||
// printf("[%s:%d]after while().", __FUNCTION__, __LINE__);
|
||
printf("[%s:%d]after while().\n", __FUNCTION__, __LINE__);
|
||
```
|
||
|
||
|
||
|
||
- 完整代码
|
||
|
||
```c
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
/***
|
||
* printf("%[修饰符]格式字符", 输出表项);
|
||
*
|
||
*/
|
||
|
||
#define STRSIZE 10
|
||
|
||
int main()
|
||
{
|
||
// printf("hello world\n");
|
||
|
||
// char ch = 65;
|
||
// printf("%c\n", ch);
|
||
// out: A
|
||
|
||
int i = 255;
|
||
float f = 123.45678;
|
||
char str[STRSIZE] = "helloworld";
|
||
double dou = 123.456;
|
||
long long l = 123456;
|
||
// 不加\n,before while()存入了缓冲区,故不输出
|
||
// printf("[%s:%d]before while().", __FUNCTION__, __LINE__);
|
||
printf("[%s:%d]before while().\n", __FUNCTION__, __LINE__);
|
||
while (1)
|
||
{
|
||
}
|
||
// printf("[%s:%d]after while().", __FUNCTION__, __LINE__);
|
||
printf("[%s:%d]after while().\n", __FUNCTION__, __LINE__);
|
||
// printf("f = %8.1f\n", f);
|
||
// out:f = 123.5
|
||
// printf("i = %2d\n", i);
|
||
// out: i = 123
|
||
|
||
// printf("%-10.5s[over]\n", str);
|
||
// printf("%+10.5s[over]\n", str);
|
||
// out:
|
||
// hello [over]
|
||
// hello[over]
|
||
|
||
// 同样对于i进行八进制核对十六进制的输出
|
||
// printf("i = %#o\n", i);
|
||
// out: i = 0377
|
||
// printf("i = %#x\n", i);
|
||
// out: i = 0xff
|
||
|
||
// printf("dou = %lf\n", dou);
|
||
// printf("l = %ld\n", l);
|
||
// out:
|
||
// dou = 123.456000
|
||
// l = 123456
|
||
|
||
// printf("hello world!\n");
|
||
// 实参过多或者过少都会警告
|
||
// printf("#d #e\n", i);
|
||
// printf("#d #e\n", i, f, l);
|
||
|
||
exit(0);
|
||
}
|
||
|
||
#if 0
|
||
func(FILE *fp, long i)
|
||
{
|
||
}
|
||
|
||
int main()
|
||
{
|
||
FILE *fp;
|
||
long a = 11;
|
||
|
||
fp = fopen();
|
||
|
||
// 可行,a定义了long型,与函数要求一致
|
||
func(fp, a);
|
||
|
||
// 早期的编译器不认可,这个12没有单位,不同编译器默认类型不同
|
||
// 需要加上L修饰符
|
||
func(fp, 12);
|
||
func(fp, 12L);
|
||
// 对于func(FILE *fp, long long i)
|
||
func(fp, 12LL);
|
||
}
|
||
#endif
|
||
|
||
// 定义一年有多少秒
|
||
#define SEC_YEAR (60LL * 60LL * 24LL * 365LL)
|
||
```
|
||
|
||
|
||
|
||
### `scanf`
|
||
|
||
```c
|
||
int scanf(const char *format, 地址表);
|
||
format:抑制符*
|
||
%s非常危险,因为不知道储存空间的大小
|
||
放在循环结构中时要注意能否接收到正常内容
|
||
```
|
||
|
||
|
||
|
||
- 完整代码
|
||
|
||
```c
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
/**
|
||
* int scanf(const char *format, 地址表);
|
||
*/
|
||
|
||
// #define STRSIZE 32
|
||
#define STRSIZE 3
|
||
// 除掉尾0占一个
|
||
// 相当于只能两个字符
|
||
// 但是这时候运行输入hello,不会报错
|
||
// 实际上是越界了
|
||
|
||
int main()
|
||
{
|
||
int i;
|
||
float f;
|
||
char str[STRSIZE];
|
||
int ret;
|
||
char ch;
|
||
|
||
printf("Please enter:\n");
|
||
|
||
// scanf("%d", &i);
|
||
// ch = getchar();
|
||
|
||
// printf("i = %d, ch = %c\n", i, ch);
|
||
/*
|
||
out:
|
||
Please enter:
|
||
4 h
|
||
i = 4, ch =
|
||
ch被吞掉了
|
||
*/
|
||
|
||
// scanf("%d", &i);
|
||
// scanf("%*c%c", &ch);
|
||
// 用 '%*c' 吃掉回车
|
||
/*
|
||
out:
|
||
Please enter:
|
||
5
|
||
h
|
||
i = 5, ch = h
|
||
*/
|
||
|
||
printf("i = %d, ch = %c\n", i, ch);
|
||
|
||
#if 0
|
||
// 输入a直接卡死,scanf直接放在循环中很危险
|
||
// 需要加入校验,用ret接收scanf返回值
|
||
while (1)
|
||
{
|
||
// scanf("%d", &i);
|
||
|
||
ret = scanf("%d", &i);
|
||
if (ret != 1)
|
||
{
|
||
printf("Enter Error!\n");
|
||
break;
|
||
}
|
||
|
||
printf("i = %d\n", i);
|
||
}
|
||
#endif
|
||
|
||
// printf("Please enter fot str:\n");
|
||
// 这种情况下,不能有任何间隔符
|
||
// 输入hello world,只会得到hello
|
||
// 对于scanf,不建议'%s'
|
||
// scanf("%s", str);
|
||
// printf("%s\n", str);
|
||
|
||
// printf("Please enter for i[int]:\n");
|
||
// 这里两个数字之间有',',输入就一定要有','
|
||
// 最好不加,空格符可以是空格 回车 tab
|
||
// scanf("%d,%f", &i, &f);
|
||
// printf("i = %d\n", i);
|
||
// printf("f = %f\n", f);
|
||
|
||
exit(0);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
## 字符输入输出函数
|
||
|
||
```c
|
||
int getchar(void);// 返回int型是考虑出错的情况
|
||
int putchar(int c);
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
int main()
|
||
{
|
||
int ch;
|
||
ch = getchar();
|
||
putchar(ch);
|
||
|
||
exit(0);
|
||
}
|
||
```
|
||
|
||
## 字符串输入输出函数
|
||
|
||
```c
|
||
char *gets(char *s);
|
||
// 从标准输入读到内容放到s指针指向的缓冲区
|
||
// 停止条件:换行或者EOF
|
||
// 尾部会追加'\0'
|
||
|
||
int puts(const char *s);
|
||
// 将s指针缓冲区内容往外写
|
||
// 以换行符中止
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
#define STRSIZE 32
|
||
j
|
||
int main()
|
||
{
|
||
char str[STRSIZE];
|
||
gets(str);
|
||
puts(str);
|
||
|
||
exit(0);
|
||
}
|
||
```
|
||
|
||
`gets`非常危险,不会检查是否越界。使用的话用`fgets`来代替。
|
||
|
||
```c
|
||
char *fgets(char *s, int size, FILE *stream);// 最多读到'size-1'个
|
||
```
|
||
|
||
`getline`是`GNU libc`的方言,可以动态内存保证读取一整行。
|
||
|
||
|
||
|
||
## 练习专题
|
||
|
||
### 夸脱水
|
||
|
||
> 一个水分子3.0e-23g,一夸脱水约950g。
|
||
>
|
||
> 变成,输入水的夸脱数,输出其包含的水分子质量。
|
||
|
||
```c
|
||
static void water(void)
|
||
{
|
||
float num;
|
||
float sum;
|
||
|
||
printf("Please input for num:");
|
||
scanf("%f", &num);
|
||
|
||
sum = num * KQ / WEIGHT;
|
||
|
||
printf("Total = %e\n", sum);
|
||
|
||
return;
|
||
}
|
||
```
|
||
|
||
### 三角形面积
|
||
|
||
> 输入三角形的三边长,求三角形面积。
|
||
|
||
```c
|
||
static void area(void)
|
||
{
|
||
float a, b, c;
|
||
float s, area;
|
||
|
||
printf("Please input:");
|
||
scanf("%f%f%f", &a, &b, &c);
|
||
// 对scanf做好校验是好习惯
|
||
if (a + b <= c || b + c <= a || a + c <= b)
|
||
{
|
||
fprintf(stderr, "EINVAL!\n");
|
||
exit(0);
|
||
}
|
||
|
||
printf("a = %f\n", a);
|
||
printf("b = %f\n", b);
|
||
printf("c = %f\n", c);
|
||
|
||
// s = 1 / 2 * (a + b + c);
|
||
s = 1.0 / 2 * (a + b + c);
|
||
printf("s = %f\n", s);
|
||
// s=0.000000
|
||
// 1 / 2是int型计算,得到的是商0余1
|
||
|
||
area = sqrt(s * (s - a) * (s - b) * (s - c));
|
||
printf("area = %f\n", area);
|
||
}
|
||
|
||
```
|
||
|
||
编译需要`-lm`。`makefile`如下,千万要注意`makefile`要使用**制表符**缩进,而非空格。
|
||
|
||
```makefile
|
||
CC=cc
|
||
CFLAGS=
|
||
LDFLAGS=-lm
|
||
TARGET=test
|
||
SRC=test.c
|
||
OBJ=$(SRC:.c=.o)
|
||
|
||
$(TARGET): $(OBJ)
|
||
$(CC) -o $@ $^ $(LDFLAGS)
|
||
|
||
%.o: %.c
|
||
$(CC) $(CFLAGS) -c $< -o $@
|
||
|
||
clean:
|
||
rm -f $(TARGET) $(OBJ)
|
||
```
|
||
|
||
### 求根公式
|
||
|
||
> ax^2^ + bx + c = 0,假设b^2^ - 4ac >0
|
||
>
|
||
> x~1~ = (-b + sqrt( b*b - 4ac )) / 2a
|
||
>
|
||
> x~2~ = (-b - sqrt( b*b - 4ac )) / 2a
|
||
|
||
```C
|
||
void root(void)
|
||
{
|
||
float a, b, c;
|
||
float disc;
|
||
float p, q;
|
||
float x1, x2;
|
||
|
||
printf("Please input :\n");
|
||
scanf("%f%f%f", &a, &b, &c);
|
||
|
||
if (b * b - 4 * a * c < 0)
|
||
{
|
||
fprintf(stderr, "EINVAL\n");
|
||
exit(1);
|
||
}
|
||
disc = b * b - 4 * a * c;
|
||
p = -b / 2 * a;
|
||
q = sqrt(disc) / 2 * a;
|
||
|
||
x1 = p + q;
|
||
x2 = p - q;
|
||
|
||
printf("x1 = %f\n", x1);
|
||
printf("x2 = %f\n", x2);
|
||
}
|
||
```
|
||
|