C程序设计语言读书笔记(7)

        这一章主要讲了C语言的输入输出函数。由于在此章之前,写的C程序就用到了输入输出函数,所以这章的内容显得很熟悉。

        先看看三个概念:
        标准输入在程序运行时由用户输入数据,程序运行产生的相关信息都由标准输出标准错误显示。
        这里有必要解释一下stdin stdout和stderr:
当我们启动一个C语言程序时,操作系统负责打开3个文件,并将这3个文件的指针提供给该程序。这3个文件分别为标准输入、标准输出和标准错误,相应的文件指针分别为stdin、stdout、stderr。
        我们也可以在程序中指定输入文件获得数据,但是如果我们不确定输入文件是什么,该怎么编程呢?实际上,我们可以先假设程序使用标准输入,在实际运行时在运用输入的重定向,把键盘输入替换为文件输入。同理,也可以进行输出的重定向。
        或者当程序的输出的内容太多时,我们也可以把标准输出重定向。

        看下重定向的命令:
        输出重定向命令 > 、>>。它们都将标准输出替换为文件输出。
        它们的区别是:前者清空的文件的内容再写;后者保留文本原先的内容,以追加的方式写入。

        输入重定向命令 < 。

        它将键盘输入替换为文本输入。

        重定向命令的用法:

        假设程序的名字为prog:

                      prog < infile    程序proginfile中读取字符

                      prog > infile   

                      prog >> infile    程序prog将标准输出定向到infile

        下面用实例(windows下)来说明如何使用这些重定向命令。

//prog.c 将命令行参数打印出来
int main(int argc, char *agrv[])  
{
	int i;
	for (i = 1;i < argc;i++)
	{
		printf("%s\n", agrv[i]);
	}
	return 0;
}
//anotherprog.c 将输入的名字前后加上“Hello”和“!”并打印。
#include <stdio.h>
int main ()
{
	char name[100];
	while (gets(name) != NULL)
	{
		printf("Hello %s !\n", name);
		fprintf(stderr, "test stderr\n");//测试stderr的效果
	}	
	return 0;
}

          将以上两个文件放到同一目录下,打开命令提示符到该目录,用cl命令(如果不能使用cl命令,请先配置环境变量)分别将它们编译——cl prog.c 和 cl anotherprog.c

        prog May John Mike Joe | anotherprog > out.txt

        将运行两个程序otherprog 和 prog,并将程序prog的标准输出通过管道重定向到程序anotherprog 的标准输入上。其中prog的命令行参数为May John Mike Joe,而且anotherprog的标准输出重定向到out.txt

        执行后会自动生成out.txt,里面会有anotherprog打印的信息。

        anotherprog < out.txt > outfile.txt

        运行anotherprog,标准输入重定向为out.txt,输出到outfile.txt

        anotherprog < out.txt >> outfile.txt

        和上条命令类似,不过这次不会清空outfile.txt,它保留文本原来的信息,并打印信息添加到后面。

        上面这个例子可以很清楚的看到stderr也标准输出的不同——即使对标准输出进行了重定向,写到stderr中的输出通常也显示在屏幕上。

        printf函数不多说了,直接看示例代码很清楚,还有其他的转换可以现查现用。

int main()
{
	char *s = "test%test";

	printf(":%s:\n", "hello, world");
	printf(":%10s:\n", "hello, world");
	printf(":%.10s:\n", "hello, world");
	printf(":%-10s:\n", "hello, world");
	printf(":%.15s:\n", "hello, world");
	printf(":%-15s:\n", "hello, world");
	printf(":%15.10s:\n", "hello, world");
	printf(":%-15.10s:\n", "hello, world");

	//宽度和精度可以用*表示,它们的值通过转化下个参数计算。
	printf(":%*s:\n", 15, "hello, world"); 
	printf(":%.*s:\n", 10, "hello, world");
	printf(":%*.*s:\n", 15, 10, "hello, world");

	printf(s); /* 如果字符串s含有字符% ,输出将出错。*/
	printf("%c", '\n');
	printf("%s", s); /* 正确*/
	return 0;
}

         sprintf函数执行的转换和函数printf相同,但它将输出保存在一个字符串中。

        scanf是用来输入数据的,也是很常用的了。

        当scanf函数扫描完其格式串,或者碰到某些输入无法与格式控制说明匹配的情况时,该函数终止。同时,成功匹配并赋值的输入项的个数将作为函数值返回。

        在scanf的格式串中,空格或制表符在处理过程中将被忽略。此外,在读取输入值时,它将跳过空白符(空格、制表符、换行符等等)。

        如果读取格式不固定的输入,最好每次读入一行,然后再用sscanf将合适的格式分离读入,它返回值也是成功读取的项数。

        观察printf的使用可知,printf函数的传人参数是不定的,这可以用变长参数表去实现。

        在vs2005中键入printf可以看到它的声明形式为:

        int printf(__in_z __format_string const char * _Format, ...);

        带有变长参数表的函数必须至少含有一个有名参数,而且变长参数要放到最后,但是我们应该怎么处理这些连名字都没有的变长参数表呢?下面通过编写一个接受变长参数的求和函数说明。

#include <stdarg.h>//包含一组宏定义,它们对如何遍历参数表进行了定义。
void cal(int *sum, ...)
{
	int i = -1; //给i赋非零值。
	va_list ap; //该变量将依次引用各参数。
	*sum = 0;
	va_start(ap, sum);//宏va_start将ap初始化为指向第一个无名参数的指针。
	while (i)
	{
		i = va_arg(ap, int); //假设没项都是int类型。
		*sum += i;
	}
	va_end(ap); //结束时的清理工作。
}
int main()
{
	int sum = 0;
	cal(&sum, 4, 555, 323, 23);
	printf("%d\n", sum);
	return 0;
}

        每次调用va_arg,该函数都将返回一个参数,并将ap指向下个参数。va_arg使用一个类型名来决定返回的对象类型、指针移动的补偿。最后在函数返回之前调用va_end,以完成一些必要的清理工作。

        stdio.h有这样一段:

#define fgetc(_stream)     (--(_stream)->_cnt >= 0 \
	? 0xff & *(_stream)->_ptr++ : _filbuf(_stream))
#define putc(_c,_stream)  (--(_stream)->_cnt >= 0 \
	? 0xff & (*(_stream)->_ptr++ = (char)(_c)) :  _flsbuf((_c),(_stream)))
#define getc(_stream)    fgetc(_stream)
#define getchar()         getc(stdin)
#define putchar(_c)       putc((_c),stdout)

          我们可以看到这些常用的函数都是用宏定义的,这样可以避免函数调用产生的开销。而且可以清楚的表面getchargetc 和 putcharputc的关系。

        gets函数在读取字符串时将删除结尾换行符('\n'),而puts函数在写入字符串时将在结尾添加一个换行符。

        当一个程序正常终止时,程序会自动为每个打开的文件调用fclose函数。但是当文件指针不再需要时就应该释放,因为大多数操作系统都限制了一个程序可以同时打开的文件数。

        函数system(char *s)执行包含在字符串s中的命令,然后继续执行当前程序。s的内容很大程度与所用的操作系统相关。比较常见的有system("pause"); system("date");

        在本章的最后,还第一次看到了calloc函数,它和malloc函数功能类似,都是用于动态分配存储块的。它与malloc不同的是calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。malloccalloc函数返回的指针满足正确的对齐要求。

#include <stdlib.h>
int main ()
{
	int n = 10;
	int *ap = (int *)calloc(n, sizeof(int));
	int *bp = (int *)malloc(sizeof(int) * n);
	return 0;
}

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值