Better reading experience\huge{\color{red}{better reading experience}}better reading experience
Article Directory
0. Stack armor, pass
My level is limited, and my language organization ability is low. I do not guarantee an excellent reading experience, nor do I guarantee that the content is completely accurate. If you have any mistakes or suggestions, please point them out. No wonder .
1. Talk about input and output buffers
1.1 Basic concepts
Don't worry, I know you are in a hurry, but don't worry, so don't worry .
When understanding the input and output buffers, the following basic concepts need to be clarified:
- I/O stream
- standard input and output stream
- file input and output stream
I/O stream
- The input and output stream is a concept of data transmission.
- One of the components that make up a computer is
I/O
a device, which refers to a device (mouse, keyboard, etc.) used to transfer data from inside the program to an external device (screen, printer, etc.) or from an external device to the inside of the program; - The data interaction between the computer and the user is carried out through the
I/O
device, and in order to adapt to the transmission of data between different devices, the concept of input and output streams is proposed. - That is, the input and output stream is a unified data input and output protocol, which provides a consistent interface for transferring data between different devices .
standard input and output stream
- The standard input and output stream refers to the input and output between the program and external devices (such as keyboards and monitors)
- In
C
language:- In
C
the standard library, the standard input and output streams arestdin
and , respectivelystdout
, as well as the standard error streamstderr
. - Use the functions and functions
<stdio.h>
in the header file .scanf()
printf()
- In
- In
C++
language:- In
C++
the standard library, there is nostdin
such standard input stream, instead usestd::cin
andstd::out
for standard input and standard output. - Use the function
<iostream.h>
in the header filegetline()
or>>
the and<<
operator.
- In
- In summary, in
C++
, the use of input and output streams is usuallyiostream
implemented through the library, while in , it is implementedC
through the library.stdio
file input and output stream
- The file input and output stream saves data in a file on the disk. By opening and closing the file, the program can use the file input and output stream to read and write data.
- In
C
language:- File input and output streams are implemented using
C
file pointers in the standard libraryFILE*
. - Operation functions include
fopen()
,fclose()
,fread()
,fwrite()
and so on.
- File input and output streams are implemented using
- In
C++
language:- The file input and output stream is
C
encapsulated based on the file operation functions in the standard library, that is,fstream
the class. - Specifically, implemented by
std::ifstream
and classes, which are derived classes of and classes.std::ofstream
std::istream
std::ostream
- The file input and output stream is
Compared with the standard input and output stream, the file input and output stream needs to explicitly specify the file to be read and written , so it is more cumbersome to use, but it is also more flexible: the file input and output stream can handle any type of file, including text files and binary files , while standard input and output streams can only handle character streams. In addition, the file input and output stream can read and write files through random access to the file, while the standard input and output stream can only read and write sequentially.
1.2 Input and output buffer
What is an input and output buffer?
As the name implies, the input and output buffer is the area of the input and output buffer .
In C/C++
, the input and output buffer is a temporary storage area used to store input and output data :
- An input buffer is a temporary storage area where input data is stored prior to data stream input.
- An output buffer is a temporary storage area where output data is stored until the data stream is output.
In human terms: The input and output buffer is a piece of memory temporarily opened up to save these input and output streams .
Why set the input and output buffers?
Zhongsuo porridge juice, because it is needed, so set :
- Buffers are in memory, while peripherals are in hardware.
- Reading and writing data from memory is faster than reading and writing data from hardware.
Therefore, when a program needs to read or write a large amount of data, the buffer can be used to store the data in memory first, and then write or read at one time, avoiding the overhead of frequent access to hardware. In addition, buffers can optimize the arrangement and formatting of data so that it can be read and written more efficiently.
In human terms: The existence of the buffer is to improve the efficiency of input and output and reduce the number of accesses to peripherals .
How are input and output buffers different in C/C++?
don't rush don't rush
First of all, don't worry, and second, don't worry , so let's first understand: **What is the space for the input and output buffer allocated? Where is the development? When will it be opened? **this problem:
- The space of the input and output buffer is usually allocated by the operating system ;
- In general, it is allocated from the memory when the program is running, allocated in the program running space , not in the kernel space of the operating system;
- The timing of the allocation and the size of the allocated space will vary according to the specific implementation . Generally , when the program writes or reads data to the buffer through the input and output functions, the buffer will be allocated.
Specific location :
-
When to allocate a buffer:
- For standard input and output streams: The buffer space is usually pre-allocated when the program starts.
- For file input and output streams: the buffer space is dynamically allocated when the file stream and stream buffer objects are created, and these objects are usually initialized at the beginning of the program.
- The size of the buffer is usually an implementation detail, but in general, the size of the buffer should be large enough to hold the normal size of the input or output data, but not so large that it wastes memory.
-
The size of the allocated buffer:
-
The size of the buffer should be large enough to hold the normal size of input or output data, but not so large that memory is wasted .
-
The allocation of the buffer size is done by the implementing library, and the specific implementation details may vary depending on the compiler or operating system.
-
Generally speaking, the implementation library will allocate the buffer space by calling the system call provided by the operating system or the dynamic memory allocation function .
-
In the case of tight memory space, the size of the buffer may be limited, which may affect the performance and reliability of the program.
-
hurry hurry hurry hurry hurry
I know you're in a hurry, but don't worry , this part actually doesn't need to be too tangled. of. Right:
- In
C
the language, the standard input and output library<stdio.h>
provides the implementation of the input and output buffer.- Three functions are mainly used:
setbuf()
,setvbuf()
,fflush()
. - Among them,
setbuf()
andsetvbuf()
can be used to set the buffer, andfflush()
used to clear the buffer and output the data in the buffer to the file. - Therefore,
C
the input and output functions in, such asscanf()
andprintf()
etc., are not type-safe :- They rely on format strings to indicate the type of input/output data.
- Incorrect format strings can lead to unpredictable results such as buffer overflows and undefined behavior.
- Three functions are mainly used:
- In
C++
,<iostream>
the library provides the implementation of input and output buffers.- Two different buffers are provided:
streambuf
andfilebuf
. streambuf
is<iostream>
the base class of the library, which provides access to the input and output buffers; andfilebuf
is<fstream>
the base class of the library, which provides access to the file input and output buffers.- However,
<iostream>
the library also provides some functions likesetbuf()
,setvbuf()
,flush()
etc. to manage the input and output buffers. After closing the synchronous stream,<iostream>
the library uses a mechanism different from the standard input and output library to improve efficiency, such as using string streamsstringstream
and buffered streamsbuffer stream
. - Therefore,
C++
the input and output functions in, such asstd::cin
andstd::cout
etc., are type-safe :- They use type-safe
C++
stream semantics, where data types are determined statically rather than dynamically. - This means that the data type is determined at compile time, rather than being dynamically determined at runtime from the format string.
- This kind of static type checking can detect type mismatch errors at compile time, making the
C++
input and output of the more type-safe.
- They use type-safe
- Two different buffers are provided:
This is why, you can still C++
use scanf()
and in printf()
, but it is still recommended C++
to use <iostream>
the standard input and output provided by the library in , and why we often say C++
that C
is more suitable for object-oriented than .
Summary: This part really doesn't have to be too tangled. Fair. correct. sane. Hit the nail on the head. real.
2. Talk about the way of input and output
2.1 Input and output of C/C++
You are in a hurry, you are in a hurry, you are in a hurry, because you are confused , you don't understand stdin
, scanf
, cin
, std::cin
, getline
, stringstream
and stdout
, printf
, cout
, std::cout
what are these things , right? Let's make it clear:
stdin
isC
the standard input stream in the language.cin
isC++
the standard input stream in , andstd::cin
isC++
the standard input stream in the standard library namespace, which is an abbreviationcin
for using the namespace , which is an alias for .std
cin
std::cin
scanf()
isC
an input function in the language, andcin
andstd::cin
areC++
input streams in .scanf()
The parameters of need to use a format string to specify the type of input data, andcin
andstd::cin
can automatically identify the type of input data.getline()
It isC++
an input function in , which can be used to read a line of text data from the input stream, and the delimiter can be specified.getline()
Can be used instead ofscanf()
andcin
for reading string type data.stdout
isC
the standard output stream in the language.cout
isC++
the standard output stream in andstd::cout
isC++
the standard output stream in the standard library namespace. The difference between them is the samecin
as andstd::cin
.printf()
isC
an output function in the language, andcout
andstd::cout
areC++
output streams in the .printf()
The parameters of need to use a format string to specify the type of output data, andcout
andstd::cout
can automatically identify the type of output data.- As for
stringstream
thiscrazything, let's put it in the end.
scanf() and printf()
Because we are so familiar with these two things, we are not unfamiliar with these two things at all . These two are C
the standard input and standard output functions in the language.
For that printf()
, just pay attention to the following points:
- usage:
scanf(format, argument_list);
- It is used to output data to the console, and can output various types of data, such as integers, floating point numbers, characters, strings, etc.
- When outputting a string, you need to pay attention to whether the string contains special characters, such as newline characters, tab characters, etc., and you need to use corresponding escape characters to represent them.
- Formatted output can be used to control the format of the output , such as output precision, alignment, etc.
And for scanf()
, in addition to the basic points of attention:
- usage:
scanf(format, argument_list);
- It is used to input data from the console, and can read various types of data, such as integers, floating point numbers, characters, strings, etc.
scanf()
When inputting data, it is required that the data formatformat
matches the format specified in the string, otherwise an error will be generated.
Also need to pay attention: the buffer scanf()
of the function will not be cleared automatically , so you need to use fflush(stdin)
the statement to clear the buffer to prevent the input data from being received by the next input function. If you just want to deal with the newline character, \n
you can use getchar()
read to replace the newline character " eat up".
Take a chestnut :
Observe the following code:
#include <stdio.h>
int main(){
int n; //声明 int 类型变量 n
scanf("%d", &n); //读入 int 类型变量 n
printf("%d\n", n); //输出 int 类型变量 n 并且换行
char c = getchar(); //读入一个字符,并存储在 char 类型变量 c 中
printf("%c", c); //输出 char 类型变量 c
printf("14\n"); //输出 14 并且换行
return 0;
}
Suppose you run it and enter the following in the console:
114
5
In theory, I'd expect to get the output:
114
514
But in fact, the console hums and hums and hums and hums, and outputs the following:
114
14
5
Even the console did not receive the character you entered later .
In this example, scanf("%d", &n)
a number from the input stream is read 114
and stored in a variable n
. However, since there is a newline character in the input buffer \n
, getchar()
the function will read this newline character and store it in the variable c
, resulting in such a result. The data in the buffer is not automatically cleared , which is why the console simply ignores your subsequent input and outputs unexpected content.
Then continue to observe the following code:
#include <stdio.h>
int main(){
int n; //声明 int 类型变量 n
scanf("%d", &n); //读入 int 类型变量 n
printf("%d\n", n); //输出 int 类型变量 n 并且换行
getchar(); //用 getchar() 吃掉缓冲区中的 '\n'
char c = getchar(); //读入一个字符,并存储在 char 类型变量 c 中
printf("%c", c); //输出 char 类型变量 c
printf("14\n"); //输出 14 并且换行
return 0;
}
Recompile and run and enter the following in the console:
114
5
You can find that the console is humming and ah ah ah ah ah output:
114
514
In this example, in order to avoid the situation that the above buffer is not cleared, we manually clear the input buffer after reading the data, and use to getchar()
read the newline character in the buffer \n
, so that the subsequent characters 5
are successfully read in, and the final output expected content.
cin and cout
cin
and cout
are C++
input and output streams, which can be used to implement console input and output operations. Generally, when using cin
and , cout
you can simplify the code by introducing using namespace std;
, but you can also use fully qualified names std::cin
and std::cout
.
Since the input cin
and cout
output of and will automatically match the corresponding data types, the formatted input and output for the two is not the focus of the discussion here, but here, we need to mention its about **synchronized stream** the concept of:
- Synchronous stream means that when data is output in the program stream, the program must wait until the data is completely output to the device before continuing to execute the following code.
- Likewise, when a program tries to read data from an input device, the program waits for the user to enter complete data before continuing to execute the following code.
Although synchronous flow can ensure the correctness of input and output, it will affect the efficiency of the program in some scenarios, especially in the case of a large amount of data input and output.
That's why, even if C++
would rather give up the high performance of scanf()
and printf()
, but also get the safety and correctness brought by the synchronization of input and output streams, which also makes is C++
more suitable for object-oriented development.
Note :
scanf()
andprintf()
also have a synchronous stream mechanism, but their buffer implementation is more low-level and more efficient.- In addition, the type checking mechanism of
cin
andcout
and various other operations are also one of the factors that affect its performance.
getchar() and getline()
The two are put together simply because they look alike , but they are vastly different:
-
getchar()
The function reads a character from standard input (stdin) and returns theASCII
code value of that character. -
It is usually used to read a single character or an array of characters, and can implement simple input operations.
-
When using it, it should be noted that since the input characters are directly input through the keyboard, it is necessary to press the Enter key to send the input characters into the buffer, and only then can the input content be read
getchar()
. -
getline()
The function reads a line of text from the input stream and stores it into a string object, and can read a whole line of input including spaces. -
When using it, it should be noted that if the default delimiter is used
\n
,getline()
the newline character will be read into the buffer. If the read input is used next timegetline()
, the newline character in the buffer will be read instead of the expected input . At this time, you cancin.ignore()
clear the characters in the buffer by calling, or specify other separators.
The issue getchar()
of the buffer zone has already been mentioned, here is a getline()
chestnut of :
Observe the following code:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s); //读入 string 类型 s
cout << "First: " << s << endl; //输出 s
getline(cin, s); //在此读入
cout << "Second: " << s << endl; //再次输出 s
return 0;
}
Suppose you run it and enter the following in the console:
114
514
In theory, I'd expect to get the output:
First: 114
Second: 514
But in fact, the console hums and hums and hums and hums, and outputs the following:
First: 114
Second: 514
You'll be amazed that expectations are met, and you think, "Hey, this isn't faultless crap L ys LysL ys playing with me? "
Don't be in a hurry, let me be in a hurry.
getline()
There are actually three parameters, the third parameter is the delimiter parameter, that is, the getline()
data will be divided and processed by this parameter, and by default, it getline()
will be used \n
as the delimiter, that is, we use by default getline(cin, s, '\n');
.
So in this example, 114
pressing the Enter key after entering is considered a delimiter and is removed from the input stream, while \n
still remaining in the buffer. The second getline()
call then reads the remaining characters in the buffer, i.e. removes and stores "\n514"
the s in it . So the output is as expected.\n
514
Let's re-specify getline()
the delimiter and modify the following code:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s, ','); //读入 string 类型 s,并以 ',' 为分隔符
cout << "First: " << s << endl; //输出 s
getline(cin, s, ','); //在此读入
cout << "Second: " << s << endl; //再次输出 s,并以 ',' 为分隔符
return 0;
}
Suppose you run it and enter the following in the console:
114,
514,
In theory, I'd expect to get the output:
First: 114
Second: 514
But in fact, the console hums and hums and hums and hums, and outputs the following:
First: 114
Second:
514
You'll be surprised that this time it doesn't live up to expectations, and you think, "Eh, this isn't crap, rubbish L ys LysL ys playing with me? "
You are in a hurry, but don't be in a hurry.
In this example, 114,
pressing the Enter key after entering ','
is considered a delimiter and is removed from the input stream, but subsequent entered \n
remains in the buffer. The second getline()
call then reads the remaining characters in the buffer, i.e. removes and stores "\n514,"
the s in it . So the output is not as expected.','
\n514
In order to avoid this result, we also need to manually clear the buffer, we can use getchar()
the "eat" buffer \n
, but it is recommended to use the following method:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s, ','); //读入 string 类型 s
cout << "First: " << s << endl; //输出 s
// 使用 cin.ignore() 忽略掉输入缓冲区中的换行符
// 也可以使用 cin.get() 读取缓冲区中的换行符
cin.ignore();
// cin.get();
getline(cin, s, ','); //在此读入
cout << "Second: " << s << endl; //再次输出 s
return 0;
}
Finally got the expected result.
First: 114
Second: 514
Generally speaking, getchar()
it is suitable for reading a single character or an array of characters, and getline()
it is suitable for reading a whole line of text. When using the two, you need to pay attention to different input methods and buffer processing .
stringstream
stringstream
It isC++
a data stream object provided by the standard library, which is used to perform input and output operations on strings in memory.- It can perform input and output like
cin
andcout
, and has interfaces and methods similar to input and output streams, such as<<
and>>
operators. - It provides a method to convert a string into a data type, which is convenient for programmers to process data.
- In is also
C++
type safe .stringstream
stringstream
The input and output streams such as and cin
, cout
have similar interfaces and methods, and can perform input and output operations, but their scopes are different. cin
, cout
and other input and output streams are usually used for standard input and output streams, and stringstream
are usually used for string processing.
Usually we can use to stringstream
split, convert, concatenate and other operations on the string, and then use cin
or cout
to output to the standard input and output stream:
- We can use
getline()
the function to read a line of string from standard input; - Then use
stringstream
to convert it to a numeric type, and finally usecout
to output to the standard output stream. - Such codes can not only handle the standard input and output streams, but also conveniently perform string operations, which improves the scalability and reusability of the program.
Take a chestnut :
Observe the following code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
stringstream s;
string name = "Lys";
int age = 13;
double height = 1.86;
string status = "is a dog";
s << "Name: " << name << ", Age: " << age << ", Height: " << height << ", Status: " << status;
string str = s.str();
cout << str << endl;
return 0;
}
In this example, we first create a stringstream
object s
, then use <<
operators to insert strings, integers and floats, and a string into the s
, and finally use str()
the method to convert all inserted data into a string and print it to standard output.
For another example, observe the following code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
string s;
getline(cin, s);
stringstream ss(s);
string str;
while(ss >> str){
cout << str << endl;
}
return 0;
}
Compile and run and enter the following in the console:
Lys is a dog.
Then get the following output:
Lys
is
a
dog.
In this example, we first create a string
type s
, and use getline(cin, s)
to read in the string, and then s
convert the string into stringstream
an object ss
, and then use the object to filter spaces and assign values to it str
, and finally print it to the standard output.
2.2 Turn off C++ standard stream synchronization
As mentioned earlier, due to cin
and cout
There are functions such as synchronous flow mechanism and type checking mechanism that affect its performance. Therefore, in the face of a scene that requires a large number of input and output, the input scanf()
and printf()
output efficiency of and is significantly better than cin
and cout
, but we can still turn off the synchronous flow by setting the synchronous flow flag of and to improve the efficiency of the program, even better than and .cin
cout
scanf()
printf()
In C++
the program, add the following statement to optimize the input and output flow speed and interactivity:
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
ios::sync_with_stdio(false)
: Turn off the synchronizationC++
of the standard input and output stream withC
the language input and output stream, thus speeding up the input and output.cin.tie(nullptr)
: Unbindcin
andcout
, so as to avoid the problem that the output buffer is refreshed every time when the input is read.cout.tie(nullptr)
:cout
is bound by defaultnullptr
, in fact this sentence does not need to be added . See Ok, lets talk about cout.tie once and forever for a related discussion .
It should be noted that after the synchronization of the input and output streams is turned off, the input and output functions of the language cannot be C++
used in the code C
, otherwise it may cause problems such as incomplete output or wrong output order. In addition, after unbinding, you need to manually refresh the output buffer , otherwise the output content may be incomplete or not timely. Therefore, when using these statements, you need to carefully consider the usage scenarios and execution order to avoid unexpected errors.
The following statement:
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
The purpose of increasing the input and output speed can also be achieved. This is more general than using nullptr
, as it may not be supported in some older C++
compilers nullptr
.
Generally speaking, there is not much difference between these two writing methods, except that the null pointer constant used when unbinding is different, but both can achieve the effect of improving the input and output speed.
3. Final exercise
3.1 Pan-Caesar encryption
Description :
As we all know, in network security, it is divided into plaintext and ciphertext. Caesar encryption is to move all the English letters in a plaintext back three digits ( ZZThe next digit of Z is AAA ), likeaaA moves backward three digits to becomeddd, A A A moves backward three digits to becomeDDD, Z Z Z moves backward three digits to becomeCCC , but Pan-Caesar encryption is not so simple. It moves each letter in the plaintext backward by k bits to obtain the ciphertext, and one will be appended at the end of the ciphertext. This question wants you to solve it by getting the?
ciphertext the original plaintext.
Input format :
In the first line, enter a positive integer kkk indicates the number of digits the letter moves backward.
Next, enter several lines of character strings to represent the ciphertext, and the data input ensures that only the last character of the ciphertext is ?
.
Output format :
Output the original plaintext.
Data range :
0 ≤ k ≤ 100 0 \le k \le 1000≤k≤100。
Sample input :
2
*eee/peee++?
Sample output :
*ccc/nccc++
3.2 Solution
You are already a mature ACMer \text{ ACMer } As an ACMer , you must learn to analyze and solve problems by yourself. If you can't solve it, just solve it yourself.
#include <iostream>
#include <cstring>
using namespace std;
void solve(){
int k; cin >> k;
string s;
k %= 26;
getchar(); //清空缓冲区中的 '\n'
while(getline(cin, s)){
for(int i = 0; i < s.size(); i ++){
char st = s[i];
if(st >= 'a' && st <= 'z') cout << char(st - k < 'a' ? st - k + 26 : st - k);
else if(st >= 'A' && st <= 'Z') cout << char(st - k < 'A' ? st - k + 26 : st - k);
else if(st == '?') break;
else cout << st;
}
cout << endl;
}
}
int main(){
solve();
return 0;
}