c程序设计语言 by K&R(四)输入与输出


一、标准输入、输出

1. 简单的输入\输出机制

  • 从标准输入中一次读取一个字符:int getchar(void)
  • 将字符c送到标准输出中: int putchar(int)

2. 输入重定向

  • 如果程序prog中使用了getchar函数,那么 prog < infile,将使得程序prog从输入文件infile中读取字符。
  • 如果输入通过管道来自另一个程序,那么这种输入切换也是不可见的。如命令otherprog | prog将程序的otherprog的标准输出通过管道重定向到程序prog的标准输入中。

3. 输出重定向

  • 如果程序prog中使用了putchar函数,那么 prog > file, 将使得程序prog的标准输出重定向到file文件。
  • 如果系统支持管道,那么prog | anotherprog 将把程序的标准输出通过管道重定向到程序anotherprog的标准输入中。

二、格式化输出——printf函数

1. 完整形式

int printf(char* format, arg1, arg2, arg3,....);
  • '-',负号。指定被转换的参数按左对齐的形式输出。
  • 数(小数点之前)。指定最小字段宽度。字符长度不足,则填充空格。
  • 小数点。将字段宽度和精度分开。
  • 数(小数点之后)。指定字符串中要打印的最大字符数、浮点数小数点后的位数、整形最少输出的数字数目。

2. 基本的转换说明

字符 输出形式
d,i int,十进制数
o int,无符号八进制数
x int,无符号十六进制数
u int,无符号十进制数
c int类型,单个字符
s char* 类型,直到'\0'或打印了精度指定的字符数
f double类型,十进制小数,[-]m.dddddd ,d个数由精度指定
e,E double类型,[-]m.ddddd E [+-] xxx ,d个数由精度指定
g,G double类型,如果指数小于-4或大于等于精度,则使用%e、%E输出,否则用%f输出
p void* 类型;指针
int main() {
    double a = 100;
    printf("%e\n", a);
    return 0;
}

输出为:

1.000000e+002

3. 字符串输出的精度控制

#include 
#include 

int main(void) {
	char* s = "hello, world"; //12 char
	printf("-%s-\n",s); //用-指示宽度边界
	printf("-%10s-\n",s); 
	printf("-%.10s-\n",s);
	printf("-%-10s-\n",s); // - 左对齐
	printf("-%15s-\n",s);
	printf("-%-15s-\n",s);
	printf("-%15.10s-\n",s);
	printf("-%-15.10s-\n",s);

	int max = 5;
	printf("-%.*s-\n", max, s); //宽度或精度可通过星号*表示,其值可通过转换下一参数(必须为int类型)来计算。

	return 0;
}

输出

-hello, world-
-hello, world-
-hello, wor-
-hello, world-
-   hello, world-
-hello, world   -
-     hello, wor-
-hello, wor     -
-hello-

4. sprintf函数

int sprintf(char* string, char* format, arg1, arg2, ...);

按照format格式格式化序列参数arg1,arg2,...,将输出结果存放到string中。string的空间需要大到足以容纳结果。

三、 变长参数表

1. 几个va_宏定义

  • va_list : va_list ap; 用于声明一个变量ap(arg pointer),依次引用各参数。
  • va_start: va_start(ap, namedArg);将ap初始化为第一个无名参数的指针。使用ap之前,该宏必须被调用依次。参数表必须至少包含一个又名参数,va_start将最后一个有名参数作为起点。
  • va_arg:va_arg(ap, int)该函数将返回一个参数,并将ap指向下一个参数。va_arg使用一个类型名来决定返回的对象类型、指针移动的步长。
  • va_end:va_end(ap); 最后在函数返回之前,需调用va_end来完成一些必要的清理工作。

2. 实现一个miniprintf

void minprintf(char* fmt, ...){
    va_list ap;
    char* p, *sval;
    int ival;
    double dval;
    va_start(ap, fmt);

    for(p = fmt; *p; p++){
        if(*p != '%'){
            putchar(*p);
            continue;
        }
        switch(*++p){
            case 'd':
                ival = va_arg(ap, int);
                printf("%d", ival);
                break;
            case 'f':
                dval = va_arg(ap, double );
                printf("%f", dval);
                break;
            case 's':
                for(sval = va_arg(ap, char*); *sval; sval++){
                    putchar(*sval);
                }
                break;
            default:
                putchar(*p);
                break;
        }
    }
    va_end(ap);
}

3. 实现一个可变参数累加函数

long long int sum(int num, ...) 其中num为累加整数的数量。

#include 
#include 

long long int sum(int num, ...){
    long long int result = 0;
    va_list ap;
    va_start(ap, num);
    while(num--){
        result += va_arg(ap, int);
    }
    va_end(ap);
    return result;
}
int main() {
    printf("%lld", sum(3,2,3,4));
    return 0;
}

输出为:

9

四、格式化输入——scanf函数

scanfsscanf 的所有参数都必须是指针。

1. scanf: 从标准输入中读取字符序列。

int scanf(char* format, ...)

  • 其返回值可以用来确定已匹配的输入项的个数。

  • 如果达到文件的末尾,返回EOF。

  • 如果返回0, 表示下一个输入字符与格式串中的第一个格式说明不匹配。

2. sscanf: 从一个字符串而不是标准输入中读取字符序列。

int sscanf(char* string, char* format, arg1, arg2...)

按照格式参数format中规定的格式扫描字符串string,并把结果保存到arg1, arg2, ...

五、文件访问

1.