一、标准输入、输出

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. ABC352

    A link \(x\)停不到,\(y\)能停到. 要先判断是从前往后还是从后往前. 点击查看代码 #include<bits/stdc++.h> using namespace std; ...

  2. 搭建lnmp环境-nginx(第一步)

    建议: 本次lnmp采用yum形式安装,编译安装过于繁琐,操作不好还不如yum安装,所以不推荐. 全部安装在宿主机上,如果需要安装多个版本的软件才使用docker nginx无所谓版本了 刚安装好系统 ...

  3. “智能体风”吹进体育圈 粉丝手搓上百个智能体为中国健儿应援 太有AI了!粉丝手搓上百个智能体为中国健儿打CALL

    智能体的风吹进了体育竞技圈.近日,在百度文心智能体平台,出现了上百个充满"AI"的运动明星粉丝应援智能体,比如支持中国女子乒乓球运动员孙颖莎的"孙颖莎的小迷妹" ...

  4. 模型推理batch inference速度无明显提升、耗时线性增长问题排查

    模型推理batch inference速度无明显提升.耗时线性增长问题排查 现象描述 当模型在推理阶段使用batch inference时,推理速度并无明显提升,相比单帧多次推理收益不大.如笔者在Xa ...

  5. Android studio报错:Failed to allocate a 3213123 byte allocation with 31231 free bytes and 189MB ontil 0OM

    这个问题是运行内存超了 在AndroidManifest中加入 android:hardwareAccelerated="false"android:largeHeap= &quo ...

  6. 【Maxwell】03 定向监听&全量输出

    一.定向监听 定向监听,即只监听某一个特定的表,或者库 1.创建样本案例 -- 创建监听的库(演示样本) CREATE DATABASE `test-db-2` CHARACTER SET 'utf8 ...

  7. 【Vue】Re05 操作数组的API

    一.响应式处理的操作: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  8. 【转载】 TensorFlow - 框架实现中的三种 Graph图结构

    原文地址: https://zhuanlan.zhihu.com/p/31308381 -------------------------------------------------------- ...

  9. 如何在 Ubuntu18.04 server 服务器版本的操作系统下 配置IP

    如题,现有需求,为一个server版本的Ubuntu18.04配置 IP . 在网上查到了     Ubuntu18.04  桌面版本  的配置方法: https://www.cnblogs.com/ ...

  10. ubuntu系统conda下运行pytorch报错:ImportError: libopenblas.so.0: cannot open shared object file

    如题: ubuntu系统conda下运行pytorch报错:ImportError: libopenblas.so.0: cannot open shared object file 网上找了一些资料 ...