The examples presented so far have primarily used the extractor and inserter operators, >> and << , to input and output program data. These operations also work with C-strings, but not always as we might expect. To better understand C-string I/O, we must consider the two operations separately.
The inserter operator works predictably well, independent of how the C-string was created (as an array or as a pointer). C++ behaves this way because the name of an array is a pointer, implying that the inserter operator "sees" no difference between the two representations. Furthermore, it makes no difference if the program creates the C-string as an automatic or local variable on the stack or a dynamic variable on the heap with the new operator.
char s1[] char s2[] char* s3 const char* s4 char* s5 char* s6 char s7[15] char s8[15] |
cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; cout << s4 << endl; cout << s5 << endl; cout << s6 << endl; cout << s7 << endl; cout << s8 << endl; |
Hello world Hello world Hello world Hello world Hello world Hello world Example Example |
Furthermore, we can reexamine a familiar operation in the light of the previous discussion:
cout << "Please enter the value for x:" << endl;
While C-string output is predictable, input is not.
Defining a C-string variable is the first step to reading a sequence of characters into the program. The program can define a C-string as a pointer or an array. Which definition is appropriate? If we define a C-string as a pointer, the pointer must point to memory allocated with the new operator or as an automatic array. Or we can initially create the C-string as an array. The latter choice is common, especially for simple input.
The next consideration is how big to make the array. If we're fortunate, the associated problem will inform us, but we're left on our own most of the time. If we make the C-string too small, the program may not have enough space to store all the data, but if it is too big, the program may waste space. Memory is typically plentiful unless working in a constrained environment (like a satellite or phone), so we try to identify a worst-case scenario and add a generous safety margin. We take that approach with the following simple program:
#include <iostream>
using namespace std;
int main()
{
char input[100]; // C-string variable
cout << "Enter a string" << endl;
cin >> input; // does not read spaces
cout << input << endl;
return 0;
}
The "bigger boat" we need is another way to read C-strings. cin is an instance (i.e., an object) of a class named istream (short for input stream). The inserter operator, <<, is a member function defined in istream, and it is this function that fails to read white-space characters. Fortunately, istream also defines another member function named getline, that reliably reads all characters, including spaces and tabs. It reads an entire line - everything up to and including the newline character. Furthermore, it discards the newline character, relieving the program from having to discard it with ignore and eliminating errors arising from a newline character remaining in the input stream. The next version of the program works as expected:
#include <iostream>
using namespace std;
int main()
{
char input[100];
cout << "Enter a string" << endl;
cin.getline(input, 100); // reads spaces
cout << input << endl;
return 0;
}
![]() | ||
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int i1;
cout << "Enter the first number: ";
cin >> i1;
char s1[100];
cout << "Enter the first string: ";
cin.getline(s1, 100);
cout << s1 << endl;
return 0;
}
|
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int i1;
cout << "Enter a number: ";
cin >> i1;
cin.ignore();
char s1[100];
cout << "Enter the first string: ";
cin.getline(s1, 100);
cout << s1 << endl;
return 0;
} |
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s1[100];
cout << "Enter the first string: ";
cin.ignore();
cin.getline(s1, 100);
cout << s1 << endl;
return 0;
}
|
| (a) | (b) | (c) |