个人备案 可以做企业网站吗,自己怎么创建免费网站,开源 wordpress 主题,做网站15年参考#xff1a; 里科《C和指针》 perror
定义在stdio.h中。当一个库函数失败时#xff0c;库函数会在一个外部整型变量errno#xff08;在errno.h中定义#xff09;中保存错误代码#xff0c;然后传递给用户程序#xff0c;此时使用perror#xff0c;会在打印msg后再打…参考 里科《C和指针》 perror
定义在stdio.h中。当一个库函数失败时库函数会在一个外部整型变量errno在errno.h中定义中保存错误代码然后传递给用户程序此时使用perror会在打印msg后再打印出一条用于解释errno当前错误代码的信息。如果库函数成功运行errno的值不会被修改所以只有当运行失败时检查errno的值才有意义。
// 如果msg不是NULL且指向一个非空字符串perror会打印msg后跟一个分号和一个空格
// 再跟errno对应的信息
void perror(char const *msg);
exit
原型在stdlib.h。status返回给操作系统预定义符号EXIT_SUCCESS和EXIT_FAILURE分别提示成功和失败。通常在调用perrno后调用exit终止。
void exit( int status );标准I/O函数库
fflush迫使缓冲区的数据立即写入不管它是否已满。
流分为文本流和二进制流。文本流在不同系统中可能有不同的最大长度和文本行结束方式比如MS-DOS是\r\nUnix是\n。二进制流适合非文本数据或者不希望I/O函数修改文本文件的行末字符时。
stdio.h包含FILE结构的声明它用来访问一个流。如果同时激活了几个流每个流都有一个相应的FILE与之关联。为了在流上执行操作必须调用合适的函数并传递一个FILE参数。
对于每个ANSI C程序运行时系统必须提供至少三个流标准输入stdin标准输出stdout和标准错误stderr他们都是一个指向FILE结构的指针标准输入是缺省的输入来源比如键盘标准输出是缺省的输出设置比如终端。可以进行重定向比如下面是执行program时输入使用data输出保存到answer
$program data answerFOPEN_MAX指一个程序最多同时打开几个文件。与编译器有关 8
FILENAME_MAX指文件名最大长度
输入/输出函数家族
家族名目的可用于所有的流只用于stdin和stdout内存中的字符串getchar字符输入fgetc getcgetchar①putchar字符输出fputc putcputchar①gets文本行输入fgetsgets②puts文本行输出fputsputs②scanf格式化输入fscanfscanfsscanfprintf格式化输出fprintfprintfsprintf
①对指针使用下标引用或者间接访问操作从内存中获得一个字符或写出一个字符
②使用strcpy从内存读取文本行或向内存写出文本行
打开流
写入和添加的区别在于如果原本存在文件那么写入会先清空内容添加则不会。数据只能从文件的尾部写入。
fopen执行成功返回一个指向FILE结构的指针如果失败返回NULLerrno会解释原因。
需要始终检查fopen的返回值。
FILE *fopen( char const *name, char const *mode );FILE *input;
input fopen(data3, r);
if (input NULL) {perror(data3);exit(EXIT_FAILURE); // data3: No such file or directory
}读取(要求原先已经存在)写入(如果原来不存在创建如果原来存在删除内容)添加文本rwa二进制rbwbab
mode中a表示改文件打开用于更新允许读和写但如果已经读入了一些数据那么在写数据前必须先定位当已经写了一些数据又想读时需要调用fflush或者某个文件定位函数。
freopen
stream可以是一个先前从fopen返回的流也可以是stdin/stdout/stderr。freopen首先试图关闭stream然后用指定的文件和模式重新打开这个流如果失败返回NULL成功则返回stream。
FILE *freopen( char const *filename, char const *mode, FILE *stream );关闭流
fclose在文件关闭前会刷新缓冲区成功的话返回0否则返回EOF。
fclose也是可能失败的如果操作成功和操作失败需要执行不同的行为那么需要检查fclose的结果。
int fclose( FILE *f );字符I/O
字符输入是由getchar函数家族执行的如果读到了就返回否则返回EOF。返回int是因为如果返回字符的话256个字符中需要有一个指定为EOF那如果这个字符出现在文字内部读取就会中断
int fgetc( FILE *stream ); // 只能作为函数使用
int getc( FILE *stream ); // 是宏所以stream不能放表达式因为可能有副作用
int getchar( void ); // 始终从标准输入读取字符输出是由putchar函数家族执行的如果character放的是一个’abc’这样的字符串那么使用哪个字符是不一定的由编译器决定。如果函数失败返回EOF比如stream关闭了。
int fputc( int character, FILE *stream ); // 是真正的函数
int putc( int character, FILE *stream );
int putchar( int character ); // 始终放到标准输出fgetc和fputc是真正的函数getc、putc、getchar、putchar都是#define定义的宏不过实际操作中程序长度和执行速度都差别不大。
使用ungetc可以把一个先前读入的字符返回到流中后续可以被重新读入。每个流都允许至少一个字符被退回如果允许退回多个再读取时的顺序是退回时的反序。与一个流相关的外部存储不受ungetc的影响。
退回和流当前的位置有关如果用了fseek、fsetpos或rewind改变了流的位置所有退回的字符会被丢弃。
int ungetc( int character, FILE *stream );比如从标准输入读取一段字符如78xxs只读取数字并转化为整数
#include stdio.h
#include ctype.hint
read_int() {int value;int ch;value 0;// 遇到数字停下while( ( ch getchar() ) ! EOF isdigit( ch ) ) {value * 10;value ch - 0;}// 不是数字就退回ungetc( ch, stdin );return value;
}未格式化的行I/O
只是简单读取或写入字符串不做形式转换。gets和puts家族用于操作字符串。
char *fgets( char *buffer, int buffer_szie, FILE *stream );
char *gets( char *buffer ); // 允许兼容不会在buffer中存储结尾换行符
// gets不知道缓冲区长度所以长行放入短缓冲区会破坏内存但是声明巨大缓冲区也可能有
// 更长的行所以最好不用int fputs( char const *buffer, FILE *stream );
int puts( char const *buffer ); // 允许兼容会向输出添加换行符fgets从指定的流读取字符并复制到buffer中当读到一个换行符并存储到buffer后就停止读取。如果buffer内存储的字符数达到buffer_size-1个时也停止读取当下一次调用fgets时会从流的下一个字符开始读取。在任何情况下一个NUL字节会被添加到buffer所存储数据的末尾使之成为一个字符串。如果在任何字符读取前就到达了文件尾缓冲区就不需要做更改所以fgets返回NULL否则返回指向buffer的指针。
buffer_size是程序员要检查的因为缓冲区溢出不会报错如下例。
char myStr[3];
char* ptr myStr;
// 这里虽然不会报错但是编译器会有warning缓冲区溢出
ptr fgets(myStr, 4, stdin);
printf(string is:\n);
while (*ptr ! \0) {printf(%c, *ptr);ptr;
}
// 实际上myStr只能存1个非\n的字符因为先存一个字符然后存换行符此时就停止读取了传递给fputs的buffer必须包含一个字符串以NUL结尾写入是逐字写入换行符也会被写入。如果写入时出现错误返回EOF否则返回一个非负值。
// 其实这个定义主要影响行的计数因为不论大小都会被正常写出到另一个文件
// 但是如果缓冲区比较小fputs的次数就比较多那只能通过每行中的\n数目计算
#define MAX_LINE_LENGTH 1024/*
** 从一个文件向另一个文件复制行
*/
void
copylines( FILE *input, FILE *output)
{char buffer[MAX_LINE_LENGTH];while ( fgets(buffer, MAX_LINE_LENGTH, input) ! NULL )fputs( buffer, output );
}格式化的I/O
scanf家族
…表示可变长度的指针列表从输入转换来的值逐个存储到这些指针参数所指向的内存位置所以scanf的参数前要加因为传的是指针。
当格式化字符串到达末尾或者读取的输入不匹配格式时输入停止此时返回输入值的数目。如果在任何输入值被转换前文件已经到达尾部则返回EOF。
函数不会检查格式和指针参数是否匹配。
int fscanf(FILE *stream, char const *format, ... );
int scanf( char const *format, ... ); // 从stdin读取
int sscanf( char const *string, char const *format, ... ); // 从string中读取format格式
%[*][width][modifiers]格式字符1*表示不存储转换后的值直接丢弃用来跳过不需要的输入字符
2width指定当前读取的最大字符数如果不给出则连续读入直到遇到下一个空白字符
3modifiers如果不是int要用
格式字符hlLd,i,nshortlongo,u,xunsigned shortunsigned longe,f,gdoublelong double
scanf的格式字符
代码参数含义举例cchar*读取和存储单个字符前导空白字符不会跳过。字符后面不会添加一个NUL参数必须指向一个足够大的字符数组i dint *d是解释为十进制i可以读入8、10、16进制scanf(“%i”, i); // 输入0xAprintf(“%d”, i); // 输出10u o x Xunsigned *按无符号存储uox分别解释为10、8、16进制X和x同义e f g E F Gfloat *小数点非必需可以有前置/-可以有后置e/E。schar *遇到空白时输入即停止字符串后面自动加上NUL[xxx]char *匹配[]内的字符如果不匹配即停止字符串后自动加NUL%[abc]表示接受输入abc中任何一个字符%[^abc]指非abc]也可以用但必须放第一位如果是需要某个范围如%[a-z]因编译器而定pvoid *内存地址nint *%n转换的字符不计算在scanf的返回值内%与输入中的一个%匹配该%将被丢弃
printf家族
返回值是实际打印或存储的字符数。
int fprintf( FILE *stream, char const *format, ... ); // 输出到stream
int printf( char const *format, ... );
// 不知道buffer的长度但可以通过限制生成字符串的宽度来使buffer够大
int sprintf( char *buffer, char const *format, ... ); // 转换后存到buffer中format格式
%[flags][width][.precision][length]specifierflags
标志含义-值左对齐默认是右对齐0值右对齐时缺省情况下使用空格填充左边0表示用0填充如果diuox给出了精度0会被忽略如果某个有符号值是非负的会加一个。缺省不显示空格只用于转换有符号值的代码当值是非负前面会加一个空格。空格与是互斥的如果同时给出应用#选择某些代码的另一种转换形式
width是十进制整数用于指定将出现在结果中的最小字符数。对于diuoxX如果经过精度转换后值的长度还是小于宽度会在前面插入0如果值是0精度也是0转换后是空的没有数字
int i 0;
printf(*%.0d*, i); // 输出**如果用于表示字段宽度和或精度的十进制整数由*代替那么printf的下一个参数必须是整数且能提供宽度和或精度。
未指定精度时默认为1如果指定时不带值则假定为0
printf的格式字符
代码参数含义举例cint参数被裁剪为unsigned char并作为字符打印d,iintd:参数作为十进制整数打印如果给出了精度但值的位数少于精度位数前面用0填充-不占长度i是8和16进制u,o,x,Xunsigned int跟scanf的一样含义X是十六进制用A~Fe,Edouble打印指数形式。小数点后面的位数由精度决定缺省是66.023000e23是用e大写E则打印大写的fdouble打印浮点形式精度决定小数点后位数缺省6g,Gdouble参数以%f或%eG是%E形式打印。当指数大于等于-4但小于精度字段用%f否则用指数格式这个不太对比如double i 1,按%g输出是1不同于%f和%e。参考后面的例子更像是以更短的形式输出如果是整数就输出整数。schar *打印一个字符串。如果字符串超过宽度完全打印精度指定最多字符数pvoid *打印指针地址nint *不产生输出%打印一个%
例子
int i 10;
printf(%.3d, i); // 010
%.4d // -12 - -0012
%6.4d // 1 - **0001, *表示空格
%6.4d // -12 - *-0012 printf格式代码修改符
修改符号用于表示参数是hd,i,u,o,x,X一个short型整数hn一个指向short型整数的指针ld,i,u,o,x,Xlong型整数ln指向long型整数的指针Le,E,f,gGlong double
#的转换
用于含义举例o保证产生的值以0开头x,X在非0值前加0x前缀%X则是0Xe,E,f确保结果始终包含一个小数点即使它后面没有数字g,G确保有小数点。后缀0不会去除double i 0.230e5;printf(“%#g”, i); // 23000.0
实例
其中*表示空格
格式代码1.01.0001234512345.67896.023e23%f1.0000000.0100000.0012312345.678900602299999999999975882752.000000%10.2f******1.00******0.01******0.00**12345.68602299999999999975882752.00%e1.000000e001.000000e-021.234500e-041.234568e046.023000e23%.4e1.0000e001.0000e-021.2345e-041.2346e046.0230e23%g10.010.0001234512345.76.023e23
二进制I/O
buffer是一个指向保存数据的内存位置的指针size是buffer中每个元素的字节数count是读取或写入的元素数stream是读取或写入的流。返回值是实际读取或写入的元素数目。
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
size_t fwrite( void *buffer, size_t size, size_t count, FILE *stream );刷新和定位函数
需要立刻把输出缓冲区的数据进行物理写入时用fflush。例如调用fflush保证调试信息实际打印出来而不是保存在buffer中等候打印。
int fflush( FILE *stream );ftell返回流的当前位置在二进制流中表示的是当前位置距离文件起始位置之间的字节数在文本流中不一定表示字符数因为有的os会转换行末字符但是ftell的返回值总可以用在fseek中。
long ftell( FILE *stream );
int fseek( FILE *stream, long offset, int from );fseek的from参数说明
from含义说明SEEK_SET从流的起始位置起offset个字节offset≥0需要提前对同一个流调用ftell用那个值做offsetSEEK_CUR从流的当前位置起offset个字节offset可正可负文本流中from是cur或者endoffset必须是0SEEK_END从流的尾部位置起offset个字节offset可正可负二进制流中可能不被支持应避免
用fseek改变一个流的位置可能有副作用
行末只是字符被清除如果在fseek前使用ungetc把一个字符返回到流中那么这个被退回的字符会被丢弃定位允许从写入模式切换到读取模式或者回到打开的流以便更新
void rewind( FILE *stream ); // 将读/写指针设置回指定流的起始位置并清除流的错误提示标志
// fpos_t表示文件位置非标准定义安全的用法是fgetpos获取值然后传递给fsetpos
int fgetpos( FILE *stream, fpos_t *position ); // 替代ftell
int fsetpos( FILE *stream, fpos_t const *position ); // 替代fseek从一个文件读取一个特定的记录
#include stdio.h
#include student_info.hint
read_random_record( FILE *f, size_t rec_number, StudentInfo *buffer)
{fseek(f, (long)rec_number * sizeof( StudentInfo ), SEEK_SET );return fread( buffer, sizeof( StudentInfo ), 1, f );
}改变缓冲方式
setbuf设置了另一个数组buf对流进行缓冲这个数组的长度必须为BUFSIZstdio.h中定义。为一个流自行制定缓冲区可以防止I/O函数库为它动态分配一个缓冲区。如果bufNULLsetbuf回关闭流的所有缓冲方式
void setbuf( FILE *stream, char *buf );
// mode指定缓冲类型_IOFBF 完全缓冲的流_IONBF 不缓冲的流_IOLBF 行缓冲流
// 行缓冲指当换行符写入缓冲区时缓冲区刷新
// if bufNULL, size必须是0. 最好用长度为BUFSIZ的字符数组作缓冲区或者是其整数倍
int setvbuf( FILE *stream, char *buf, int mode, size_t size ); // 更通用流错误函数
如果流处于文件尾feof返回真这个状态可以通过对流执行fseek、rewind或fsetpos来清除。ferror是报告流的错误状态如果出现任何读/写错误函数就返回真。clearerr是重置指定流的错误标志。
int feof( FILE *stream );
int ferror( FILE *stream );
void clearerr( FILE *stream );临时文件
tmpfile可以创建一个文件当文件被关闭或者程序终止时这个文件回自动删除打开方式是wb因此可以用于二进制和文本数据。如果需要以其他模式打开或者由其他程序读取不能用tmpfile只能用fopenremove。
临时文件的名字可以用tmpnam创建如果nameNULL则返回值是一个指向静态数组的指针该数组包含了被创建的文件名否则就是name。只要调用次数不超过TMP_MAX次tmpnam每次调用时都能产生一个新名字
FILE *tmpfile( void );
char *tmpnam( char *name );文件的删除和重命名
如果remove被调用时文件处于打开状态其结果取决于编译器。rename如果新名字跟其他文件重名其结果也取决于编译器。
int remove( char const *filename );
int rename( char const *oldname, char const *newname );