一、标准输入、输出

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的标准输入中。

pipe() System call

二、格式化输出——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 <stdio.h>
#include <stdlib.h> 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 <stdio.h>
#include <stdarg.h> 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. 文件指针:

  • 在读写一个文件之前,必须通过库函数fopen打开该文件。fopen利用文件名建立与操作系统必要的连接和通信,返回一个可用于文件读写操作的指针FILE*。它指向一个包含文件信息的结构,这些信息包括:缓冲区的位置、缓冲区当前字符的位置、文件的读写状态等、是否出错或是否已经达到文件末尾等。

FILE* fopen(char* name, char* mode);

  • name是文件名,mode是访问模式,包括读(r)写(w)追加(a)。某些系统用b来区分文本文件和二进制文件。

2. 对文件的读写方法

int getc(FILE* fp) : 从文件指针fp指向的文件中中获取一个字符。

int putc(int c, FILE* fp) : 向指针写入一个字符c

3. 启动c程序时,操作系统打开的文件

  • 启动一个c语言程序时,操作系统负责打开三个文件,并将这三个文件的指针提供给该c程序。三个文件分别是标准输入、标准输出和标准错误,对应的指针为stdinstdoutstderr,包含在<stdio.h>。

  • 通常,stdin指向键盘、stdoutstderr指向显示器。

  • 由前述可知,stdinstdout可以重定向到管道。

4. 文件的格式化输入、输出

可以使用fscanf()fprintf(),比scanf()printf()相比,多了一个文件指针参数FILE* fp作为第一个参数。

  • 格式化输入

int fscanf(FILE* fp, char* format, ...);

  • 格式化输出

int fprintf(FILE* fp, char* format, ...);

  • 实现简单的cat程序: 将多个文件的内容输出。

cat.c

#include <stdio.h>
void filecopy(FILE* ifp, FILE* ofp){
int c;
while((c = getc(ifp)) != EOF){
putc(c, ofp);
}
} int main(int argc, char* argv[]) {
FILE* fp;
if(argc == 1){
filecopy(stdin, stdout);
}else{
while(--argc > 0){
if((fp = fopen(*++argv, "r")) == NULL){
printf("cat: can't open %s\n", *argv);
return 1;
}else{
filecopy(fp, stdout);
fclose(fp);
}
}
}
return 0;
}

1.txt

hello

2.txt

world

编译运行:

gcc cat.c -o cat

./cat 1.txt 2.txt

输出:

hello
world

六、错误处理——stderr和exit

1. 刚刚实现的cat程序错误处理并不完善。

如果因为某种原因造成某个文件无法访问,相应的诊断信息要在输出末尾打印出来,输出到屏幕可以接受,但输出到另一个文件或重定向到另一个程序时,就无法接受了。为了更好地处理这种情况,另一个输出流stderr以与stdinstdout相同的方式分派给程序。即使对标准输出进行了重定向,写到stderr的输出通常也会显示在屏幕上。

对cat程序进行修改,将错误信息写到标准错误文件中。

#include <stdio.h>
#include <stdlib.h>
void filecopy(FILE* ifp, FILE* ofp){
int c;
while((c = getc(ifp)) != EOF){
putc(c, ofp);
}
} int main(int argc, char* argv[]) {
FILE* fp;
char* prog = argv[0];
if(argc == 1){
filecopy(stdin, stdout);
}else{
while(--argc > 0){
if((fp = fopen(*++argv, "r")) == NULL){
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
exit(1);
}else{
filecopy(fp, stdout);
fclose(fp);
}
}
}
if(ferror(stdout)){
fprintf(stderr, "%s: error writing stdout\n", prog);
exit(2);
}
exit(0);
}

2. fprintf()函数将产生的诊断信息输出到stderr中

3. 使用exit()函数终止调用程序的执行。

在主程序main中,语句return expr相当于exit(expr)。但是exit函数的优点是可以在其他函数中调用。

4. ferror(FILE* fp)函数

int ferror(FILE* fp)

如果流fp中出现错误,该函数将返回一个非0值。

5. feof(FILE* fp)函数

如果指定的文件达到文件末尾,它将返回一个非0值。

七、行输入和行输出

1. fgets

char *fgets(char* line, int maxline, FILE* fp) 从fp指向的文件中读取下一个输入行,将它存在字符数组line中(以'\0'结尾),最多可读取maxline-1个字符。遇到文件结尾或发生错误,会返回NULL。

2. fputs

int fputs(char* line, FILE* fp) 将一个字符串line写入到fp指向的文件。发生错误时,返回EOF,否则返回一个非负值。

八、其它函数

1. 字符串

函数
strcat(s,t)
strcat(s, t, n)
srcmp(s, t)
strcmp(s, t, n)
strcpy(s, t)
strcpt(s, t, n)
strlen(s)
strchr(s, c) 在字符串s中查找c,若找到返回第一次出现的位置的指针,否则返回null
strrchr(s, c) 在字符串s中查找c,若找到返回最后一次出现的位置的指针,否则返回null。(反向查找)

2. 字符串测试和转换函数

函数
isalpha(c)
isupper(c)
islower(c)
isdigit(c)
isalnum(c)
isspace(c)
toupper(c)
tolower(c)

3.ungetc函数

int ungetc(int c, FILE* fp) 将字符c写回到文件fp中。如果执行成功,返回c,否则返回EOF。

4.命令执行函数

system(char* s)执行包含在字符串s中的命令,然后继续执行当前程序。比如system("date")将执行程序date, 在标准输出中打印当前的日期和时间。又比如system("pause")

5.存储管理函数

函数malloc和calloc用于动态分配内存。

  • malloc函数

void* malloc(size_t n), 分配成功时,返回一个指向n字节长度的未初始化的存储空间,否则返回NULL。

  • calloc函数

void* calloc(size_t n, size_t size),分配成功时,该指针指向足以容纳由n个指定长度为size的对象组成的数组,否则返回NULL。

  • 例子:

以下例子进行了类型转换。

int* ip;
ip = (int*)calloc(n, sizeof(int));
  • free(p)函数释放p指向的空间,p必须是此前通过调用malloc和calloc函数得到的指针。

6. 数学函数

sin(x)cos(x)atan2(x)exp(x)log(x)log10(x)pow(x, y)sqrt(x)fabs(x)

7.随机数发生器函数

rand()生成介于0和RAND_MAX之间伪随机整数序列。

c程序设计语言 by K&R(四)输入与输出的更多相关文章

  1. C程序设计语言(K&R) 笔记2

    (1) #include <stdio.h> main(){ int c; while((c = getchar()) != EOF){ putchar(c); } } 注意,因为 != ...

  2. C程序设计语言(K&R) 笔记1

    当作复习... (1)将华氏度 换算成 摄氏度,公式: ℃=(5/9)(̧°F-32) #include <stdio.h> int transformTemprature(int F){ ...

  3. C语言中字符数据的输入和输出

    字符的输出 C语言中使用putchar函数来输出字符数据 #include <stdio.h> int main() { char a,b,c,d; //定义字符变量a,b,c,d a = ...

  4. c语言笔记4数据的输入和输出

    数据的输入和输出 知识点一 计算机的用途:数据的输入和输出. 分类: 字符:字符输入函数getchar().字符输出函数putchar(). 格式:格式输入函数scanf().格式输出函数printf ...

  5. 《c程序设计语言》读书笔记--首次输入不能是空符;最多10个字符

    #include <stdio.h> #define Num 10 int main() { int wor = 0; int arr[Num] = {0}; int c,count = ...

  6. c程序设计语言_习题1-13_统计输入中单词的长度,并且根据不同长度出现的次数绘制相应的直方图

    Write a program to print a histogram of the lengths of words in its input. It is easy to draw the hi ...

  7. javaIO流(四)--输入与输出支持

    一.打印流 如果现在要想通过程序实现内容的输出,核心的本质一定要依靠OutputStream类来支持但是OutputStream类有一个最大的缺点,这个类的数据输出操作功能有限,所有的数据一定要转为字 ...

  8. C语言基础(9)-字符串格式化输入和输出

    1.字符串在计算机内部的存储方式 字符串是内存中一段连续的char空间,以’\0’结尾 2.printf函数,putchar函数 putchar输出一个char printf是输出一个字符串 prin ...

  9. mybatis学习记录四——输入、输出映射

    6      输入映射 通过parameterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类型. 6.1.1     需求 完成用户信息的综合查询,需要传入查询条件很 ...

  10. C语言学习笔记4-数据输入和输出

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/50752127 作者:jadeshu   邮箱: jades ...

随机推荐

  1. Solo 开发者周刊 (第7期):Sora出世,或许又一行业将会消失?

    这里会整合 Solo 社区每周推广内容.产品模块或活动投稿,每周五发布.在这期周刊中,我们将深入探讨开源软件产品的开发旅程,分享来自一线独立开发者的经验和见解.本杂志开源,欢迎投稿. 好文推荐 sor ...

  2. tp5框架No input file specified

    最近从网上下载了一个项目,本地搭建好环境.访问页面出现No input file specified. 这个问题之前就遇到过,是因为权限的问题,导致nginx无法解析php文件,这次有点不一样所以记录 ...

  3. tp6 uniapp跨越问题

    自己写一个简单的中间件

  4. oeasy教您玩转vim - 27 - 文件类型

    ​ 文件类型 回忆上节课内容 上次了解了缩进的各种方式 正常模式下用 << 缩进 插入模式下用 tab 缩进 显示缩进情况 :set listchars=eol:$,tab:>-,s ...

  5. oeasy教您玩转vim - 49 - # 命令进阶

    ​ 命令进阶 回忆上节课内容 我们上次研究vim的历史 为什么会有行编辑器这种东西 竟然是当年 没有显示器只有纸的时代的无奈之举 vim进化到今天 依然还有好多人使用 而且ssh连接的时候直接vim就 ...

  6. C# 算术表达式求值(后缀法),看这一篇就够了

    一.种类介绍 算术表达式有三种:前缀表达式.中缀表达式和后缀表达式.一般用的是中缀,比如1+1,前后缀就是把操作符移到前面和后面,下面简单介绍一下这三种表达式. 1.前缀表示法 前缀表示法又叫波兰表示 ...

  7. css 蛇形排序

    先看效果 需求: 一个[ 4  * ?]的网格布局,奇数行 布局 从左往右,偶数行 布局 从右往左. 思路1: js将数组按4个每份进行分割,将偶数份进行反向,然后再将分割后的数据,重新组装.( 太麻 ...

  8. Git的存储原理

    目录 Git 设计原理 Git vs SVN Git 存储模型 .git 目录结构 Git 基本数据对象 Git 包文件 Git 引用 Git 设计原理 概括的讲,Git 就是一个基于快照的内容寻址文 ...

  9. java中的Context

    在java编程中,上下文(Context)是指程序运行时的环境和状态的集合.包括了类对象变量方法等运行时的相关数据 在类中,我们可以通过this获取当前类的变量.方法的上下文, 例如getset方法: ...

  10. Hyperledger Fabric 2.x 环境搭建

    一.说明 区块链网络的核心是分布式账本,在这个账本中记录了网络中发生的所有交易信息. Hyperledger Fabric是一个是开源的,企业级的,带权限的分布式账本解决方案的平台.Hyperledg ...