c++语言的输入输出,C语言的输入与输出
C语言系列:7、输入输出文章目录C语言系列:7、输入输出1。标准输入/输出1.1标准输入1.2标准输出1.3打印f 1.4示例2。打印格式- printf函数3。可变长度参数表4。格式化输入-扫描功能5。文件访问6。错误处理- stderr和exit 7。线路输入和输出- fgets和fputs 8。其他职能。字符串操作函数8.2。字符类别测试和转换功能8.3。ungetc函数8.4。命令执行功能8.5。内存管理功能8.6。数学函数8.7。随机数发生器函数
I/O函数并不是C语言本身不可分割的一部分,所以到目前为止,我们并没有过多的强调它们。然而,程序和环境之间的交互比我们在前面部分描述的要复杂得多。本章将讲述标准库并介绍一些输入/输出函数、字符串处理函数、存储管理函数和数学函数,以及C语言程序的其他函数。本章将集中讨论输入/输出。
ANSI标准精确地定义了这些库函数,所以在任何可以使用C语言的系统中都有这些函数的兼容形式。如果程序的系统交互部分只使用标准库提供的功能,可以不加修改地从一个系统移植到另一个系统。
这些库函数的属性都是在十几个头文件中声明的,有些是以前遇到过的,比如stdio.h,string.h和ctype.h我们这里不打算列出整个标准库,因为我们更关心的是如何使用标准库编写C语言程序。附录B详细描述了标准库。
1.标准输入/输出。正如我们在第一章中所说的,标准库实现了一个简单的文本输入/输出模式。流由一系列行组成,每行末尾有一个换行符。如果系统不遵循这种模式,标准库将通过一些措施使系统适应这种模式。例如,标准库可以在输入端将回车符和换行符都转换成换行符,在输出端则相反。
1.1标准输入最简单的输入机制是使用getchar函数从标准输入(通常是键盘)中一次读取一个字符:
Getchar (void) getchar函数每次被调用时都返回下一个输入字符。如果遇到文件结尾,则返回EOF。头文件stdio.h中定义了符号常量EOF,其值一般为-1。但是程序中要用e of来测试文件是否结束,这样才能保证程序与EOF的具体值无关。
在许多环境中,可以使用符号来实现输入重定向,这将使用文件输入来代替键盘输入:如果在程序prog中使用函数getchar,命令行
prog会让程序Prog从输入文件infile中读取字符,而不是键盘。其实程序prog本身并不关心输入方式的改变,argv的命令行参数中也没有包含字符串‘infile’。如果输入通过管道机制来自另一个程序,那么这种输入切换也是不可见的。例如,在某些系统中,以下命令行:
Otherprog 会运行Otherprog和prog两个程序,通过管道将otherprog的标准输出重定向到prog的标准输入。
1.2标准输出功能
Int putchar(int)用于输出数据。Putchar将字符C发送到标准输出,默认显示在屏幕上。如果没有错误,putchar函数将返回输出字符;如果出现错误,将返回EOF。同样,一般情况下,您也可以使用“输出文件名”的格式将输出重定向到一个文件。例如,如果程序prog调用函数putchar,那么命令行
prog输出文件名将程序Prog的输出从标准输出设备重定向到文件。如果系统支持管道,则命令行
Prog anotherprog会通过管道将程序Prog的输出从标准输出重定向到程序anotherprog的标准输入。
1.3 printf函数printf也将数据输出到标准输出设备。在我们的程序中,我们可以交叉调用函数putchar和printf,输出将按照函数调用的顺序生成。
每个使用输入/输出库函数的源程序文件在引用这些函数之前必须包含以下语句
# includesdio.h当文件名用一对尖括号和括起来时,预处理器将在特定实现定义的相关位置查找指定的文件(例如,在UNIX系统中,文件一般放在目录/usr/include中)。
1.4示例许多程序只从一个输入流读取数据,并将数据输出到一个输出流。对于这样的程序,我们只需要使用函数getchar、putchar和printf来实现输入/输出,对于程序来说就足够了。特别是,如果一个程序的输出通过重定向连接到另一个程序的输入,只使用这些函数就足够了。例如,考虑下面的程序lower,它用于将输入转换为小写字母:
#包含stdio.h
#包含ctype.h
main() /* lower:将输入转换为小写*/
{
背包容量
while ((c=getchar())!=EOF)
putchar(to lower(c));
返回0;
}头文件ctype.h中定义了tolower函数,该函数将大写字母转换为小写字母,并将其他
字符按原样返回。我们前面提到过,头文件stdio.h中的getchar和putchar“函数”
和ctype.h中的to lower“function”一般都是宏,因此避免了为每个字符进行函数调用的开销。我们将在8.5节介绍它们的实现方法。无论ctype.h中的函数是如何在给定的机器上实现的,使用这些函数的程序都不需要知道字符集。
2.打印格式printf函数输出函数printf将内部数值转换成字符形式。该功能已在前面的章节中使用过。
下面只描述该函数最典型的用法,附录b给出了该函数的完整描述。
int printf(char *format,arg1,arg2,);printf函数在输出格式format的控制下对其参数进行转换和格式化,并在标准输出设备上打印出来。它的返回值是打印的字符数。
该格式包含两种类型的对象:普通字符和转换指令。输出时,普通字符会按原样复制到输出流中,而转换指令不是直接输出到输出流中,而是用来控制printf中参数的转换和打印。每个转换指令都以百分号字符(即%)开始,以转换字符结束。字符%和转换字符中间可能包含以下成分:
负号,用于指定转换后的参数以左对齐的形式输出。指定最小字段宽度的数字。转换后的参数将打印不小于最小字段宽度的字段。如有必要,字段左侧(或右侧,如果使用左对齐方法)的冗余字符位置用空格填充,以确保最小字段宽度。小数点,用于分隔字段宽度和精度。Number,用于指定精度,即指定字符串中要打印的最大字符数,浮点数小数点后的位数,以及至少按整数输出的位数。字母h或l,字母h不将整数打印为短类型,字母l表示将整数打印为长类型。表7-1列出了所有转换字符。如果%后面的字符不是转换描述,则行为未定义。
表7-1 printf函数基本转换描述
性格;角色;字母
类型:输出形式
d,我
Int类型;小数
o
Int类型;无符号八进制数(无前导0)
X,X
Int类型;无符号十六进制数(无前导0x或0X),10 ~ 15分别用abcdef或ABCDEF表示。
u
Int类型;无符号十进制数
c
Int类型;单字符
s
Char * type打印序列字符串中的字符,直到遇到 \0 或打印完precision指定的字符数。
f
类型doubleDecimal decimal [-]m.dddddd,其中D的个数由精度指定(默认值为6)
E,E
类型double[-] m. dddddd e xx或[-] m. dddddd e xx,其中d的个数由精度指定(默认值为6)
G,G
类型double如果指数小于-4或大于等于精度,将以%e或%E格式输出,否则,将以%f格式输出。不打印尾随的0和小数点。
p
Void * type指针(取决于实现)
%
参数不被转换;打印百分号%。
在转换描述中,宽度或精度可以用星号*表示。在这种情况下,宽度或精度的值通过转换下一个参数(必须是int类型)来计算。例如,为了打印字符串s中的最大字符数,可以使用以下语句:
printf(%。*s ,max,s);大部分的格式转换在前一章已经介绍过了,但是与字符串相关的精度还没有介绍。下表说明了在打印字符串“hello,world”(12个字符)时,不同转换指令产生的不同结果。
我们在每个字段的左右两边加上冒号,可以清楚的表示字段的宽度。
:%s:你好,世界:
:s:你好,世界:
:%.10s:您好,wor:
:%-10s:你好,世界:
:%.15s:你好,世界:
:%-15s:你好,世界:
:.10s:你好,沃尔:
:%-15.10s:hello,wor:注意:函数printf使用第一个参数判断后面参数的个数和类型。如果参数个数不够或者类型不对,就会得到错误的结果。请注意以下两个函数调用之间的区别:
printf/*如果s包含% */
printf(%s ,s);/* SAFE */函数sprintf执行与函数printf相同的转换,但它将输出保存到字符串中:
int sprintf(char *string,char *format,arg1,arg2,);像printf函数一样,sprintf函数格式化参数序列arg1、arg2,
但是,它将输出结果存储在字符串中,而不是输出到标准输出。当然,字符串必须足够大以存储输出结果。
3.可变长度参数表。本节以函数printf的最简单版本为例,介绍如何编写一个能够以可移植的方式处理变长参数表的函数。因为我们侧重于参数的处理,所以minprintf函数只处理格式字符串和参数,格式转换是通过调用printf函数来实现的。
printf函数的正确声明形式是:
Int printf(char *fmt,)其中省略号表示参数表中参数的数量和类型是可变的。省略号只能出现在参数列表的末尾。因为minprintf函数不需要像printf函数那样返回实际输出的字符数,所以我们用下面的形式声明它:
Void minprintf(char *fmt,)写函数minprintf的关键是如何处理一个连名字都没有的参数表。标准头文件stdarg.h)包含一组定义如何遍历参数表的宏定义。这个头文件的实现因机器而异,但是提供的接口是一致的。
va_list类型用于声明一个变量,这个变量将依次引用每个参数。在minprintf函数中,
我们把这个变量叫做ap,意思是“参数指针”。宏va_start将ap初始化为指向第一个未知参数的指针。在使用ap之前,这个宏必须被调用一次。参数表必须包含至少一个命名参数,va_start以最后一个命名参数作为起点。
每次调用va_arg,这个函数都会返回一个参数,并将ap指向下一个参数。va_arg的使用
确定返回对象类型和指针移动步长的类型名。最后,在函数返回完成一些必要的清理工作之前,必须调用va_end。
基于以上讨论,我们实现的简化printf函数如下:
#包含stdarg.h
/* minprintf:带有可变参数列表的最小printf
void minprintf(char *fmt,)
{
va _ list ap/*依次指向每个未命名的参数*/
char *p,* sval
国际间;
双dval
va_start(ap,fmt);/*使ap指向第一个未命名的参数*/
for(p=fmt;* p;p ) {
if (*p!=%) {
putchar(* p);
继续;
}
开关(* p) {
案例“d”:
ival=va_arg(ap,int);
printf(%d ,ival);
打破;
案例“f”:
dval=va_arg(ap,double);
printf(%f ,dval);
打破;
案例:
for (sval=va_arg(ap,char *);* svalsval)
putchar(* sval);
打破;
默认值:
putchar(* p);
打破;
}
}
va _ end(AP);/*完成后清理*/
}4.格式输入scanf函数输入函数scanf对应于输出函数printf,后者提供与后者相反方向的相同转换函数。变长参数表函数scanf的声明形式如下:
Intscanf (char *格式,)scanf函数从标准输入中读取字符序列,根据格式中的格式指令解释字符序列,并将结果保存到其余参数中。格式参数format将在下面的内容中讨论。所有其他参数必须是指针,以指定格式转换后相应输入的保存位置。就像上一节关于printf的内容一样,这一节只介绍了scanf函数的一些最有用的特性,但不是全部。
当scanf函数扫描其格式字符串,或遇到某些输入与格式控制描述不匹配的情况时,该函数将被终止。同时,成功匹配并赋值的输入项的个数将作为函数值返回,因此可以用函数的返回值来确定匹配的输入项的个数。如果到达了文件的末尾,函数将返回EOF。请注意,返回的EOF不同于0,这意味着下一个输入字符与格式字符串中的第一个格式描述不匹配。对scanf函数的下一次调用将从上次转换的最后一个字符的下一个字符开始继续搜索。
还有另一个输入函数sscanf,用于从字符串中读取字符序列(而不是标准输入):
Intsscanf (char * string,char * format,arg1,arg2,)它根据format参数format中指定的格式扫描字符串string,并将结果保存到arg1、arg2、这些参数分别。这些参数必须是指针。
格式字符串通常包含转换指令,用于控制输入的转换。格式字符串可能包含以下部分:
、或空格或制表符将在处理过程中被忽略。普通字符(不包括%)用于匹配输入流中的下一个非空白字符。转换描述,依次由%号、可选赋值禁止字符*、可选数值(指定最大字段宽度)、可选H、L或L字符(指定目标对象的宽度)和转换字符组成。描述控制下一个输入字段的转换。一般来说,转换结果存储在相应参数所指向的变量中。但是,如果转换描述中有一个分配禁止字符*,则输入字段将被跳过,不会进行分配。输入字段被定义为不带空格的字符串,其边界被定义为下一个空格或指定的字段宽度。这表明scanf函数将跨行边界读取输入,因为换行符也是一个空白字符。(空白字符包括空格字符、水平制表符、换行符、回车符、垂直制表符和换页符)。
转换字符指定输入字段的解释。对应的参数必须是指针,这也是C语言通过值调用语义所要求的。这些转换字符在表7-2中列出。
表7-2 SCANF功能基本转换描述
性格;角色;字母
输入数据;参数类型
d
十进制整数;Int * type
我
整数;Int * type,可以是八进制(从0开始)或十六进制(从0x或0X开始)
o
八进制整数(可以从0开始,也可以不从0开始);Int * type
u
无符号十进制整数;无符号int * type
x
十六进制整数(可能以0x或0X开头,也可能不以0X开头);Int * type
c
人物;Char * type,在指定位置存储以下输入字符(默认为1个字符)。这个转换规范通常不会跳过空白。如果需要读入下一个非空白字符,可以使用%1s。
s
字符串(不带引号);Char * type,指向足以容纳字符串的字符数组(包括尾随字符 \0 )。字符串末尾将添加一个终止符 \0 。
英、法、格
浮点数,可以包括符号(可选)、小数点(可选)、指数部分(可选);浮点*类型
%
字符%;没有任何赋值操作。
解释字符h或l可以加在d,I,o,u和X前面.前缀h表示参数表的相应参数。
是指向短类型而不是int类型的指针,前缀L表示参数表对应的参数是指向长类型的指针。同样,可以在转换描述E、F、G的前面加上前缀L,表示参数表对应的参数是指向double类型而不是float类型的指针。
看第一个例子。我们通过函数scanf执行输入转换,重写了第4章中的简单计算器程序,如下所示:
#包含stdio.h
main() /*基本计算器*/
{
双和,v;
sum=0;
while (scanf(%lf ,v)==1)
printf(\t%.2f\n ,sum=v);
返回0;
}假设我们要读取具有以下日期格式的输入行:
2DEC1988相应的scanf语句可以写成这样:
int日,年;
char month name[20];
scanf(%d %s %d ,日,月,名,年);因为数组名本身就是指针,所以monthname前面没有地址操作符。
字符文字也可以出现在scanf的格式字符串中,它们必须匹配输入中的相同字符。因此,我们可以使用下面的scanf语句读入mm/dd/yy格式的日期数据:
int日、月、年;
scanf(%d/%d/%d ,月,日,年);scanf函数忽略格式字符串中的空格和制表符。此外,在读取输入值时,它会跳过空白(空格、制表符、换行符等。).如果要读取非固定格式的输入,最好是一次读取一行,然后用sscanf分出合适的格式读取。例如,假设我们需要读取一些包含日期数据的输入行,日期的格式可能是上述任何一种形式。我们可以这样写程序:
while (getline(line,sizeof(line)) 0) {
if (sscanf(line, %d %s %d ,day,monthname,year)==3)
printf(有效:%s\n ,行);/* 1988年12月25日表格*/
else if (sscanf(line, %d/%d/%d ,month,day,year)==3)
printf(有效:%s\n ,行);/*年/月/日格式*/
其他
printf(无效:%s\n ,行);/*无效格式*/
}scanf功能可以与其他输入功能混合使用。无论调用哪个输入函数,下一个输入函数的调用都将从scanf未读取的第一个字符开始读取数据。
请注意,scanf和sscanf函数的所有参数都必须是指针。最常见的错误是按以下形式编写输入语句:
scanf(%d ,n);正确的形式应该是:
scanf(%d ,n);通常,编译器在编译时无法检测到这样的错误。
5.文件访问到目前为止,我们讨论的例子是从标准输入中读取数据和将数据输出到标准输出。标准输入和标准输出由操作系统自动提供,用于程序访问。
接下来我们写一个程序访问文件,它访问的文件和程序是不相连的。程序cat可以用来解释这个问题。它连接一批命名文件,并将它们输出到标准输出。对于那些不能通过名字访问文件的程序,Cat可以用来在屏幕上打印文件。它也可以用作通用输入采集器。例如,下面的命令行:
卡特彼勒将在标准输出上打印文件X.C .和Y.C .的内容。
问题是,如何设计命名文件的读取过程?换句话说,如何将用户需要使用的文件的外部名称与读取数据的语句相关联。
其实方法很简单。在读取或写入文件之前,必须用库函数fopen打开它。Fopen使用类似X.C .或Y.C .这样的外部名称与操作系统进行一些必要的连接和通信(我们不必关心这些细节),并返回一个指针,该指针随后可用于文件读写操作。
这个指针叫做文件指针,它指向一个包含文件信息的结构,包括:缓冲区的位置,缓冲区中当前字符的位置,文件的读或写状态,是否有错误或者是否已经到达文件的末尾等等。用户不必关心这些细节,因为在stdio.h中已经定义了一个包含这些信息的结构文件,你只需要在程序中声明一个文件指针如下:
FILE * fp
FILE *fopen(char *name,char * mode);在这个例子中,fp是指向结构文件的指针,fopen函数返回指向结构文件的指针。注意,FILE和int一样,是一个类型名,而不是一个结构标记。它是由typedef定义的(fopen在UNIX系统中的实现细节将在8.5节讨论)。
在程序中,你可以像这样调用fopen函数:
fp=fopen(名称,模式);fopen的第一个参数是一个字符串,它包含文件名。第二个参数是访问模式,它也是一个字符串,用于指定如何使用文件。允许的模式包括:读(“R”)、写(“W”)和追加(“A”)。有些系统还区分文本文件和二进制文件,访问后者需要在模式字符串中添加字符“b”。
如果打开一个不存在的文件进行写入或追加,将会创建该文件(如果可能)。当现有文件作为写操作打开时,文件的原始内容将被覆盖。但是,如果以追加方式打开文件,文件的原始内容将保持不变。读取不存在的文件会导致错误,其他操作也可能导致错误,例如试图读取没有读取权限的文件。如果出现错误,fopen将返回NULL。
(您可以进一步定位错误的类型。具体方法请参考附录B.1中关于错误处理函数的讨论。)
文件打开后,需要考虑使用哪种方法读写文件。有很多方法可以考虑,其中getc和putc函数是最简单的。Getc返回文件中的下一个字符。它需要知道文件指针,以确定对哪个文件执行操作:
getc (file * fp) getc函数返回fp指向的输入流中的下一个字符。如果到达了文件的末尾或者发生了错误,这个函数将返回EOF,
Putc是一个输出函数,如下:
Int putc(int c,FILE *fp)这个函数将字符C写入fp指向的文件,并返回写入的字符。如果出现错误,将返回EOF。与getchar和putchar类似,getc和putc是宏而不是函数。
当启动一个C语言程序时,操作系统环境负责打开三个文件,并向程序提供指向这三个文件的指针。这三个文件分别是标准输入、标准输出和标准错误,对应的文件指针分别是stdin、stdout和stderr,在stdio.h中声明,大多数环境下,stdin指向键盘,stdout和stderr指向显示器。从7.1节的讨论中我们知道,stdin和stdout可以被重定向到文件或管道。
Getchar和putchar函数可以由getc、putc、stdin和stdout定义,如下所示:
#define getchar() getc(标准输入)
# define putchar (c) putc ((c),stdout)对于文件的格式化输入或输出,可以使用函数fscanf和fprintf。它们与scanf和
printf函数的区别在于,第一个参数是指向要读写的文件的指针,第二个参数是格式字符串。如下所示:
int fscanf(FILE *fp,char *格式,)
Intrintf(文件* FP,字符*格式,)掌握了这些初步知识后,我们现在就可以编写一个连接多个文件的cat程序了。这个程序的设计思路和很多其他程序类似。如果有命令行参数,参数将被解释为文件名,并按顺序逐个处理。如果没有参数,则处理标准输入。
#包含stdio.h
/* cat:连接文件,版本1 */
main(int argc,char *argv[])
{
FILE * fp
void filecopy(FILE *,FILE *)
if (argc==1) /*无参数;复制标准输入*/
filecopy(标准输入,标准输出);
其他
while( - argc 0)
if ((fp=fopen(* argv, r )==NULL){
printf(cat:打不开%s\n,* argv);
返回1;
}否则{
filecopy(fp,stdout);
fclose(FP);
}
返回0;
}
/* filecopy:将文件ifp复制到文件ofp */
void filecopy(FILE *ifp,FILE *ofp)
{
int c;
while ((c=getc(ifp))!=EOF)
putc(c,ofp);
}文件指针stdin和stdout都是FILE *类型的对象。但它们是常数,不是变量。因此,不能给它们赋值。
功能
Intlose (file * FP)执行与fopen相反的操作。它打破了fopen函数建立的文件指针与外部名称之间的联系,为其他文件释放了文件指针。因为大多数操作系统都限制一个程序可以同时打开的文件数量,所以当不再需要文件指针时释放它是一个很好的编程习惯,就像我们在cat程序中所做的那样。对输出文件执行fclose还有另一个原因:它会将缓冲区中putc函数正在收集的输出写入文件。当程序正常终止时,程序会自动为每个打开的文件调用fclose函数。(如果不需要使用stdin和stdout,可以关闭。您也可以通过库函数freopen重新指定它们。)
6.错误处理——stderr和exitcat程序的错误处理功能并不完善。问题是,如果其中一个文件由于某种原因无法访问,那么相应的诊断信息就无法打印出来,直到连接的输出结束。这种处理方法在输出到屏幕上时是可以接受的,但在通过管道输出到文件或另一个程序时是不可接受的。
为了更好地处理这种情况,以与stdin和stdout相同的方式,将另一个输出流分派给程序,即stderr。即使标准输出被重定向,写入stderr的输出通常也会显示在屏幕上。
让我们重写cat程序,并将其错误信息写入标准错误文件。
#包含stdio.h
/* cat:连接文件,版本2 */
main(int argc,char *argv[])
{
FILE * fp
void filecopy(FILE *,FILE *);
char * Prog=argv[0];/*错误的程序名*/
if (argc==1 ) /*无参数;复制标准输入*/
filecopy(标准输入,标准输出);
其他
while ( - argc 0)
if ((fp=fopen(* argv, r )==NULL){
fprintf(stderr, %s:无法打开%s\n ,
prog,* argv);
出口(1);
}否则{
filecopy(fp,stdout);
fclose(FP);
}
if (ferror(stdout)) {
fprintf(stderr, %s:写入stdout\n ,prog时出错);
出口(2);
}
退出(0);
}程序以两种方式发出错误信息。首先,fprintf函数生成的诊断信息输出到
Stderr,因此诊断信息将显示在屏幕上,而不仅仅是输出到管道或输出文件。诊断信息包含argv[0]中的程序名,因此当该程序与其他程序一起运行时,可以识别错误的来源。
其次,程序使用了标准的库函数exit,在被调用时会终止调用程序的执行。任何调用这个程序的进程都可以得到exit的参数值,因此,以这个程序为子进程的另一个程序可以测试这个程序的执行是否成功。按照惯例,返回值0表示一切正常,而不是0的返回值通常表示异常情况。Exit为每个打开的输出文件调用fclose函数,将缓冲区中的所有输出写入相应的文件。
在主程序main中,语句return expr等效于exit(expr)。但是,使用函数exit
有一个优点是它可以被其他函数调用,这些调用可以被一个类似于第五章中描述的模式查找器找到。
如果流fp中出现错误,函数ferror将返回一个非零值。
尽管很少出现输出错误,但Int ferror(FILE *fp)仍然存在(例如,当磁盘已满时)。因此,成熟的产品程序应该检查这种类型的错误。
函数feof(FILE *)类似于ferror。如果指定的文件到达文件的结尾,它将返回一个非
0值。
Int feof(FILE *fp)在上面的小程序中,我们的目的是说明问题,所以不太在意程序的退出状态,但是对于任何重要的程序,我们都应该让程序返回一个有意义的有用的值。
7.行输入和行输出——fgets和fputs标准库提供了一个输入函数fgets,它类似于前面章节中使用的函数getline。
Char * fgets (char * line,int max line,file * fp)fgets函数从FP指向的文件中读取下一个输入行(包括换行符)并存储在字符数组行中。它最多可以读取maxline-1个字符。读取的行将保存到以“\0”结尾的数组中。通常情况下,fgets返回line,但是如果遇到文件结尾或者出现错误,则返回NULL(我们写的getline函数返回行的长度,比较有用。当它为0时,意味着已经到达文件的结尾)。
输出函数fputs将字符串(不需要包含换行符)写入文件:
Intuts (char * line,file * FP)如果出现错误,该函数将返回EOF,否则将返回一个非负值。
gets和puts库的功能类似于fgets和fputs,但是它们是用于stdin和stdout的。
进行手术。我们需要注意的一点是,gets函数在读取字符串时会删除末尾的换行符( \n ),而puts函数在写入字符串时会在末尾添加一个换行符。
以下代码是标准库中fgets和fputs函数的代码。如您所见,这两个函数不是
它有些特别。代码如下:
/* fgets:从iop中获取最多n个字符*/
char *fgets(char *s,int n,FILE *iop)
{
寄存器int c;
寄存器char * cs
cs=s;
而(- n 0 (c=getc(iop))!=EOF)
if ((*cs=c)==\n )
打破;
* cs= \ 0
return (c==EOF cs==s)?NULL:s;
}
/* fputs:将字符串s放在文件iop上*/
int fputs(char *s,FILE *iop)
{
int c;
while (c=*s)
putc(c,IOP);
返回ferror(iop)?EOF:0;
}ANSI标准规定出错时Ferrer返回非零值,出错时fputs返回EOF,
其他情况返回非负值。
使用fgets函数很容易实现getline函数:
/* getline:读取一行,返回长度*/
int getline(char *line,int max)
{
if (fgets(line,max,stdin)==NULL)
返回0;
其他
返回strlen(行);
}8.其他函数标准库提供了许多功能不同的函数。本节将简要概述特别有用的功能。
有关更多详细信息和许多其他未介绍的功能,请参考附录B。
8.1.字符串操作函数字符串函数strlen,strcpy,strcat,strcmp前面都提到过,都在头文件里。
在以下函数中的string.h中定义,s和t是char *类型,c和n是int类型。
Strcat(s,T)将T指向的字符串连接到s指向的字符串的末尾。
Stcat (s,T,N)将T指向的字符串中的前N个字符连接到s指向的字符串的末尾。
stmp (s,t)根据s指向的字符串小于(s t),等于(s==t)或大于(s t) t。
针对字符串的不同情况,分别返回负整数、0或正整数。
Rncmp (s,t,n)与strcmp相同,但只是在前n个字符中进行比较。
Strcpy(s,t)将t指向的字符串复制到s指向的位置。
Stcpy (s,T,N)将T指向的字符串中的前N个字符复制到s指向的位置。
返回s指向的字符串的长度。
Strchr(s,c)在s指向的字符串中查找c,如果找到,则返回指向其第一次出现的位。
设置指针,否则返回NULL。
Strrchr(s,c)在s指向的字符串中查找c,如果找到,则返回指向它最后一次出现的字符串。
的位置指针,否则返回NULL。
8.2.字符类别测试和转换函数头文件ctype.h定义了一些字符测试和转换的函数。在下面的函数中,c是一个int对象,可以表示为无符号char类型或EOF。这个函数的返回值类型是int。
如果c是字母,Isalpha返回非零值,否则返回0。
Isupper如果C是大写字母,则返回非零值,否则返回0。
Islower如果c是小写字母,则返回非零值,否则返回0。
如果c是一个数字,Isdigit返回一个非零值,否则返回0。
如果isalpha或isdigit,Isalnum返回非零值,否则返回0。
如果c是空格、水平制表符、换行符、回车符、换页符或垂直制表符,
则返回非零值。
Toupper返回c的大写形式。
Tolower返回c的小写形式。
8.3.ungetc函数标准库提供了一个名为UnGETC的函数,它的函数比第四章写的函数ungetch更有限。
Int ungetc(int c,FILE *fp)这个函数将字符c写回文件fp。如果执行成功,则返回C,否则返回EOF。每个文件只能接收一个写回字符。etc函数可用于任何输入函数,如scanf、getc或getchar。
8.4.命令执行功能系统(char* s)执行字符“s”中包含的命令,然后继续执行当前程序。S
内容很大程度上与使用的操作系统有关。让我们看一个UNIX操作系统环境的小例子。句子
系统(“日期”);执行程序date,它将在标准输出中打印日期和时间。系统函数返回一个整数状态值,该值来自执行的命令,与特定系统相关。在UNIX系统中,返回的状态是exit的返回值。
8.5.内存管理函数malloc和calloc用于动态分配内存块。函数malloc的声明如下:
Void *malloc(size_t n)分配成功时,返回一个指针。让指针指向N字节的未初始化存储空间,否则返回NULL。calloc函数的声明是
Void *calloc(size_t n,size_t size)当分配成功时,返回一个指针,指针指向的空闲空间足够容纳一个指定长度的N个对象的数组,否则返回NULL。存储空间被初始化为0。
根据所请求的对象类型,由malloc或calloc函数返回的指针满足正确的对齐要求。下面的示例执行类型转换:
int * ip
ip=(int *) calloc(n,sizeof(int));free函数释放p所指向的存储空间,这里p以前叫malloc或calloc函数。
获取数字的指针。对存储空间的释放顺序没有限制,但是释放一个不是通过调用malloc或calloc函数获得的指针所指向的存储空间将是一个严重的错误。
使用释放的存储空间也是错误的。下面的代码是一个典型的错误代码段,它通过一个循环释放列表中的项目:
for (p=头;p!=NULLp=p- next) /*错误*/
免费(p);正确的方法是在发布项目之前保存所有必要的信息,如下所示:
for (p=头;p!=NULLp=q) {
q=p-next;
免费(p);
} 8.7节给出了类似于malloc函数的存储分配器的实现。由内存分配程序分配的内存块可以以任何顺序释放。
8.6.数学函数的头文件math.h中声明了20多个数学函数。下面是一些常用的数学函数。每个函数接受一个或两个double参数,并返回一个double值。
sin(x)x的正弦函数,其中x以弧度表示
cos(x)x的余弦函数,其中x以弧度表示
atan2(y,x) y/x的反正切函数,其中x和y以弧度表示。
指数函数ex
log(x)x的自然对数(以e为底),其中x 0
Log10(x) x的常用对数(以10为底),其中x 0
计算xy的值
sq (x) x的平方根(x0)
晶圆厂的绝对值(x) x
8.7.随机数生成器函数rand()生成一个介于0和RAND_MAX之间的伪随机整数序列。其中RAND_MAX是头文件stdlib.h中定义的符号常量。下面是一种生成大于或等于0但小于1的随机浮点数的方法:
# define frand()((double)rand()/(rand _ max 1.0))(如果使用的库中已经提供了生成浮点随机数的函数,那么它可能比上述函数具有更好的统计特性。)
函数srand(unsigned)设置rand函数的种子数量。在2.7节中,我们给出了符合标准的
以及rand和srand函数的可移植实现。
否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。