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可以是

  1. 被单引号(英文状态下)引起来的一个字符,

  2. 介于0~127之间的一个十进制整型数(包含0和127),它会被视为对应字符的ASCII代码,输出该 ASCII代码对应的字符;和getchar返回的int值搭配。

  3. 用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’

它会生成一个包含一串从输入流读入的字符的字符串,直到以下情况发生会导致生成的此字符串结束。

  1. 到文件结束
  2. 遇到函数的定界符
  3. 输入达到最大限度(优化gets)

如果getline没有读入字符,将返回false,可用于判断文件是否结束。

该函数可读取一行字符直到定界符(包括定界符),定界符默认为换行符.

此点与gets相同,但是因为s的类型为string,以换行符为例,末尾不会将’\n’转换为’\0’,而是直接删去。定界符同理,直接删去.

举例如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <cstdio>

using namespace std;

int main(){

    char* s;
    s = new char[50]; //必须要分配空间
    cin.getline(s,5);
    int i = 0;
    while(s[i] != '\0'){
        cout<<s[i];
        i++;
    }
    cout<<endl<<i<<endl;
    cin.clear(); //当failbit位为1时需要clear,否则后面的getline读取为空字符串

    string str;
    getline(cin,str);
    cout<<str<<endl;
    getline(cin,str,'#');
    cout<<str<<endl;
    getline(cin,str);
    cout<<str<<endl;

    return 0;
    }

输入输出:

(input)slkdsa;34
slkd
4
sa;34
(input)hel#id
hel
id

函数流程

  1. 首先判断istream的failbit位是否为1,为1的话意味着输入流的状态有错误,则不进行读操作,getline函数结束执行

  2. 从当前位置开始从输入流中依次读取单个字符并拷贝到缓冲区,直到遇到下列条件满足时,循环结束。

    (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 :

  1. 读取普通文件时,读到文件末尾还不够 nbytes 字节。例如:如果文件只有 30 字节,而我们想读取 100 字节,那么实际读到的只有 30 字节,read 函数返回 30 。此时再使用 read 函数作用于这个文件会导致 read 返回 0 。

  2. 从终端设备(terminal device)读取时,一般情况下每次只能读取一行。

  3. 从网络读取时,网络缓存可能导致读取的字节数小于 nbytes 字节。

  4. 读取 pipe 或者 FIFO 时,pipe 或 FIFO 里的字节数可能小于 nbytes 。

  5. 从面向记录(record-oriented)的设备读取时,某些面向记录的设备(如磁带)每次最多只能返回一个记录。

  6. 在读取了部分数据时被信号中断。

注意: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,它也是原封不动的输出,当做普通字符。