字符串的输入输出
文章目录
scanf与printf
scanf
原型:int scanf(char *format,…]);
头文件:stdio.h
返回值:返回成功读入的数据项的个数,读到文件末尾或者出错时则返回EOF(0xff = -1)。
如果scanf在开头遇到前次函数留下的空白符,scanf一律跳过, 继续运行;如果在中间遇到空白符,scanf将会停止,不读取空白符。
scanf()自动在读入字符串最后补’\0’,作为字符数组的最后一个字符,来结束字符串。
空白符:空格(space)、制表符(tab)和新行符(newline)。
printf
原型:int printf(char *format,…]);
头文件:stdio.h 返回值:printf实际控制输出的字符数 输出字符串,到’\0’之前。注意要遇到’\0’也就是字符结束符才停止,要保证需要输出的字符的末尾有’\0’。
cin与cout
与scanf和printf完全相同,cin还是不会读入字符串末尾的换行符。
getchar与putchar
getchar
原型:int getchar(void);
头文件:stdio.h
返回值:getchar是一个宏,它定义为getc(stdin),有一个int型的返回值,用于返回stdin输入流的下一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕。
getchar()函数的执行采用了行缓冲。程序调用getchar时,程序就等着用户按键,用户输入的字符被存放在输入缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中,会被下个getchar()读取)。当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符。如果用户在按回车之前输入了不止一个字符,其他字符会保留在输入缓存区中,等待后续getchar调用读取。也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才重新等待用户按键。
getchar函数通常用在scanf和gets混合使用的时候,用getchar吃掉scanf未读入的’\n’,然后用gets读取下一行字符串,如下例:
scanf("%d", &t);
getchar();
gets(s);
getchar函数还用在连续用2个getchar函数读取字符的时候,需要中间额外增加一个getchar来吃掉第一行字符剩下的回车,如下例:
scanf(“%d”, &t);
int a=getchar();
getchar();
int b=getchar();
putchar
putchar(c);
作用是向终端输出一个字符。
其中c可以是
-
被单引号(英文状态下)引起来的一个字符,
-
介于0~127之间的一个十进制整型数(包含0和127),它会被视为对应字符的ASCII代码,输出该 ASCII代码对应的字符;和getchar返回的int值搭配。
-
用char定义好的一个字符型变量。
返回值:
(1)当输出正确的时候,返回输出字符转换为的unsigned int 值;
(2)当输出错误的时候,返回 EOF(End of file)文件结束符
cin.get
和getchar基本没有分别。
其实cin.get()存在的基本目的,就是为了从c移植到c++的时候,直接用cin.get()代替getchar(),也正因因此,cin.get()的返回值跟其它cin.get成员函数返回cin对象不同,跟getchar()一样返回int。
gets与puts(被禁用)
gets
原型:char * gets(char * buffer);
参数:将读取的结果存放在buffer指针所指向的字符数组中
头文件:stdio.h
返回值:读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF或发生错误,返回NULL指针。
从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。
gets()能够接受空格、制表符TAB,并不会因为字符串中有空格或者TAB而结束字符的获取,它每读入换行符就会返回,即使是一开始就遇到一个换行符。返回后会将换行符变为’\0’。
gets是个不安全的函数,可以无限读取,不会判断上限,如果缓存溢出,多出来的字符将被写入栈中,覆盖了栈原先的内容,破坏一个或多个不相关变量的值,使程序崩溃。
对于gets来说,’\n’是一个特别的字符,而’\0’并无任何特别之处,如果读到’\0’就当作普通字符读入。如果文件中存在’\0’字符(或者0x00字节),调用gets之后就无法判断缓冲区中的’\0’究竟是从文件读上来的字符还是由gets自动转换的结束符,所以gets只适合读文本文件而不适合读二进制文件,并且文本文件中的所有字符都应该是可见字符,不能有’\0’。
puts
int puts(const char *string);
头文件:stdio.h
返回值:实际控制输出的字符数
输出字符串,到’\0’之前,将’\0’转换为’\n’换行。注意要遇到’\0’也就是字符结束符才停止,要保证需要输出的字符的末尾有’\0’。
getline
函数声明
一个是在string头文件中,定义的是一个全局的函数,函数声明是
istream& getline ( istream& is, string& str, char delim )
与
istream& getline ( istream& is, string& str );
另一个则是istream的成员函数,函数声明是
istream& getline (char* s, streamsize n )
与
istream& getline (char* s, streamsize n, char delim );
注意第二个getline是将读取的字符串存储在char数组中而不可以将该参数声明为string类型,因为C++编译器无法执行此默认转换。
如果规定了streamsize且保存位置为char数组,那么将只读入streamsize-1个字符,并且字符串保存到char数组后,字符串的末位将被自动修改为’\0’
它会生成一个包含一串从输入流读入的字符的字符串,直到以下情况发生会导致生成的此字符串结束。
- 到文件结束
- 遇到函数的定界符
- 输入达到最大限度(优化gets)
如果getline没有读入字符,将返回false,可用于判断文件是否结束。
该函数可读取一行字符直到定界符(包括定界符),定界符默认为换行符.
此点与gets相同,但是因为s的类型为string,以换行符为例,末尾不会将’\n’转换为’\0’,而是直接删去。定界符同理,直接删去.
举例如下
|
|
输入输出:
(input)slkdsa;34
slkd
4
sa;34
(input)hel#id
hel
id
函数流程
-
首先判断istream的failbit位是否为1,为1的话意味着输入流的状态有错误,则不进行读操作,getline函数结束执行
-
从当前位置开始从输入流中依次读取单个字符并拷贝到缓冲区,直到遇到下列条件满足时,循环结束。
(1)遇到文件尾时停止读操作,并设置流对象的结束标记为1
(2)读到调用者指定的分隔符时,此时将分隔符之前的字符拷贝到缓冲区中,但分隔符本身不拷贝进去,并且下次读操作将从分隔符后的下一个字符开始。
(3)已经读了n-1个字符(n是调用者传入的第二个实参_Count的初值),此时要把流对象的错误标志位置1
fgets与fputs
fgets
原型:char * fgets(char * s, int n, FILE *stream);
头文件:stdio.h
参数:
s: 字符型指针,指向存储读入数据的缓冲区的地址。
n: 从流中读入n-1个字符,第n个写入''表示字符串结束。
stream : 指向读取的流。
返回值:
1. 当n<=0 时返回NULL,即空指针。
2. 当n=1 时,返回空串""。
3. 如果读入成功,则返回缓冲区的地址。
4. 如果读入错误或遇到文件结尾(EOF),则返回NULL。
当遇到换行符或者缓冲区已满,fgets就会停止,返回读到的数据。注意’\n’会被保存,只是后面再加个’\0’。
注意,对于fgets来说,’\n’是一个特别的字符,而’\0’并无任何特别之处,如果读到’\0’就当作普通字符读入。如果文件中存在’\0’字符(或者0x00字节),调用fgets之后就无法判断缓冲区中的’\0’究竟是从文件读上来的字符还是由fgets自动添加的结束符,所以fgets只适合读文本文件而不适合读二进制文件,并且文本文件中的所有字符都应该是可见字符,不能有’\0’。
fputs
int fputs ( const char * str, FILE * stream );
fputs向指定的文件写入一个字符串。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为非负整数;否则返回EOF(符号常量,其值为-1)。
缓冲区s中保存的是以’\0’结尾的字符串,fputs将该字符串写入文件stream,但并不写入结尾的’\0’。
read与write
read
read是一个系统调用,其他函数会调用该函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
read 函数从 filedes 指定的已打开文件中读取 nbytes 字节到 buf 中。以下几种情况会导致读取到的字节数小于 nbytes :
-
读取普通文件时,读到文件末尾还不够 nbytes 字节。例如:如果文件只有 30 字节,而我们想读取 100 字节,那么实际读到的只有 30 字节,read 函数返回 30 。此时再使用 read 函数作用于这个文件会导致 read 返回 0 。
-
从终端设备(terminal device)读取时,一般情况下每次只能读取一行。
-
从网络读取时,网络缓存可能导致读取的字节数小于 nbytes 字节。
-
读取 pipe 或者 FIFO 时,pipe 或 FIFO 里的字节数可能小于 nbytes 。
-
从面向记录(record-oriented)的设备读取时,某些面向记录的设备(如磁带)每次最多只能返回一个记录。
-
在读取了部分数据时被信号中断。
注意:read不会自动加上’\0’;对于\n,它也是原封不动的读入,当做普通字符。
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
返回值:若成功,返回写的字节数;若出错,返回-1.
其返回值通常与参数nbytes的的值相同,否则表示出错,write出错的一个常见原因是磁带写满,或者超过了一个给定进程的文件长度限制。
对于普通文件,写操作从文件的当前偏移量开始。如果在打开该文件时,指出了O_APPEND选项,则在每次写操作之前,将文件偏移量设置为在文件当前结尾处。在一次成功写之前,该文件偏移量增加实际写的字节数。
注意:write不会自动加上’\0’;对于\n,它也是原封不动的输出,当做普通字符。
文章作者 Forz
上次更新 2017-06-23