Here is my code:
#include <iostream>
using namespace std;
int main(){
char inp[5], out[4];
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
when I type:
12345
6789
It gives me:
6789
Why I failed to save the 5 words char array 'inp' and it showed nothing? The second input looks normal though. However, when I set out[3] or out[5], it seems to work alright? It seem that two char array of [5] then followed by [4] would cause problem...
I see that you enter (type) 1234567890 characters to input data for inp[5] - it is a problem because imp array is able to store 4 characters and null-terminator. When cin >> inp store more than 4 characters to inp array it leads to problem with data (somthing like undefined behaviour). So solution can be in allocation more memory for data, e.g.:
#include <iostream>
using namespace std;
int main(){
char inp[15], out[15]; // more memory
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
When you read into a character array the stream keeps reading until it encounters whitespace, the stream is not aware of the size of the array that you pass in so happily writes past the end of the array so if your first string is longer than 4 characters your program will have undefined behaviour (an extra character is used after your input for the null terminator).
Fortunately c++20 has fixed this issue and the stream operators no longer accept raw char pointers and only accept arrays and will only read up to size - 1 characters.
Even with c++20 the better solution is to change your types to std::string which will accept any number of characters end even tell you how many characters it contains:
#include <iostream>
int main(){
std::string inp, out;
std::cin >> inp >> out;
std::cout << inp << "\n";
std::cout << out << "\n";
return 0;
}
Its because, in memory layout of computer out[4] is laid out first and then inp[5]. Something like this:
out[0],out[1],out[2],out[3],inp[0],inp[1],inp[2],inp[3],inp[4]
So, when you write 6789 in out[4], you are overflowing null character to inp[0]. So, inp becomes NULL.
Related
#include <iostream>
using namespace std;
const int ArrSize = 400;
int main()
{
char arr1[ArrSize];
char arr2[ArrSize];
char arr3[ArrSize];
cout << "enter the first string ";
cin >> arr1;
cout << "enter the second string ";
cin.get(arr2, ArrSize);
cout << "enter the thrid string ";
cin>>arr3;
cout << endl << endl;
cout << "first string is: " << arr1 << "\n";
cout << "second string is: " << arr2 << "\n";
cout << "thrid string is: " << arr3 << "\n";
return 0;
}
execution result is
input :
"abc\n"
output :
first string is: abc
second string is:
thrid string is:(strange characters)
Can you explain why the second cin didn't get input?
I expected that cin would read leading white spaces form the stream buffer and ignore them and read new string.
Let's start by adjusting the program to check for errors.
#include <iostream>
using namespace std;
const int ArrSize = 400;
int main()
{
char arr1[ArrSize];
char arr2[ArrSize];
char arr3[ArrSize];
cout << "enter the first string ";
if (!(cin >> arr1))
{
cout << "Failed cin >> arr1\n";
}
cout << "enter the second string ";
if (!cin.get(arr2, ArrSize))
{
cout << "Failed cin.get(arr2, ArrSize)\n";
}
cout << "enter the third string ";
if (!(cin>>arr3))
{
cout << "Failed cin >> arr3\n";
}
cout << endl << endl;
cout << "first string is: " << arr1 << "\n";
cout << "second string is: " << arr2 << "\n";
cout << "third string is: " << arr3 << "\n";
return 0;
}
The results should be something like
enter the first string abc
enter the second string Failed cin.get(arr2, ArrSize)
enter the third string Failed cin >> arr3
first string is: abc
second string is:
third string is: <garbage here>
We can see that the second and third reads failed. Why is that? To find out, we need to do a little reading. Here's some high-quality documentation for std::istream::get
The relevant overload is number 3, but 3 just calls number 4 with the delimiter set to '\n' and 4 says two important things,
Characters are extracted and stored until any of the following occurs:
count-1 characters have been stored
end of file condition occurs in the input sequence (setstate(eofbit) is called)
the next available input character c equals delim, as determined by Traits::eq(c, delim). This character is not extracted (unlike basic_istream::getline())
If no characters were extracted, calls setstate(failbit). In any case, if count>0, a null character (CharT() is stored in the next successive location of the array.
So if you only get a newline, delim in this case, the output string arr2 is null terminated and the stream is placed into fail state because no characters were extracted from the stream, making the stream unreadable until the failure is acknowledged by clearing it. This is what we are seeing: an empty string and fail bit.
Why is the string empty? Why didn't it prompt for input? Because cin >> arr1 reads one whitespace-delimited token from the stream. It will ignore all whitespace up to the start of the token, but it leaves the whitespace after the token in the stream.
If you type abc and hit enter, "abc\n" goes into the stream. cin >> arr1 reads "abc" into arr1. The "\n" stays in the stream where cin.get(arr2, ArrSize) finds it. The get exit condition is immediately satisfied by the "\n", so get stops and leaves the "\n" in the stream. No characters were extracted. Fail bit is set and arr2 is null terminated.
cin>>arr3 subsequently fails because you can't read from a failed stream. Nothing is placed in arr3, so when arr3 is printed, it is unterminated and << keeps printing until it finds a terminator. This is the garbage characters, though technically anything can happen.
The question does not specify what is to be done with data left over after cin >> arr1. Common solutions are to remove everything up to and including the newline character from the stream with
cin.ignore(numeric_limits<streamsize>::max(), '\n');
but if you want to use any characters left on the line for arr2, you'll have to be trickier. For example, always read lines, build an istringstream out of the line, and then parse the istringstream as is done in option 2 of this answer.
Side note: Reading into character arrays with >> is always risky because it will keep reading until whitespace is found. If the program reads the size of the array from the stream without finding whitepace, sucks to be you. get knows to stop before its overflowed. >> doesn't. On the other hand, get will read until it finds the end of the line, not just a single whitespace delimited token.
>> into a std::string will do the right thing and resize the string to fit the input. Generally prefer std::string to char arrays. And if you are using std::string prefer std::getline to get or istream's getline.
I'm trying to input some characters into the array but after hitting enter , the terminal would not accept further input.
#include <bits/stdc++.h>
using namespace std ;
int main() {
char Array[5];
for(int i=0;i<5;++i){
cout << "Enter :";
cin.ignore('\n');
cin >> Array[i];
}
for(auto data : Array){
cout << data << endl;
}
return 0;
}
Any help would be appreciated.
You don't need the cin.ignore() here:
#include <iostream>
int main() {
char Array[5];
for(int i=0;i<5;++i){
std::cout << "Enter: ";
// No use in cin.ignore() here
std::cin >> Array[i];
}
for(auto data : Array){
std::cout << data << std::endl;
}
return 0;
}
Example:
Enter: 3
Enter: 4
Enter: 5
Enter: 6
Enter: 7
3
4
5
6
7
Main thing to note for you is the fact that cin object will skip any leading white space on itself. So, you don't have to worry that cin will read in '\n' on a second iteration, thus, terminating and skipping the input, it won't read it in.
While the ignore('<character>') will extract specified character, know as delimiting character, from the input sequence and discard it. In your case, the character is \n. The cin function stops extracting characters from the stream as soon as an extracted character compares equal to this. So, no way to pass it \n, no way to terminate input normally (you can still pass it EOF).
More on the proper use of the cin.ignore(): When and why do I need to use cin.ignore() in C++.
I also want to include this in the answer: Why should I not #include <bits/stdc++.h>?.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int num;
cin >> num;
string s;
getline(cin, s);
cout << s << " " << num << endl;
return 0;
}
In this code if I input 3 and press enter, then s takes an empty string.
1) If it is taking the first character as a newline, then is there a possible solution of taking line as input after taking an integer as input?
2) If my input is 4567artyu then how it is deciding whether 7 has to go into the s or num ?
I recommend that you always read complete lines of input from your users. It will cause the least confusion.
Ask for input.
Use std::getline to read a line of input.
If you don't want a string but, say, an integer, use std::stoi or (more general) boost::lexical_cast to safely convert the input to your desired target type. This is where you catch poor inputs and complain at the user.
I don't think that many users, if prompted for a number, would expect that entering 42bananas would be accepted as 42 and the bananas part be “remembered” for later. It will most likely be a typo and the user will be happy to be asked to correct it.
For taking line as input after taking integer as input you can consider removing the stray '\n' character from the stream.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int num;
cin >> num;
getchar();
string s;
getline(cin, s);
cout << s << " " << num << endl;
return 0;
}
This will do the trick.
For second question, it reads 4567 as integer, it will continue to read it as integer until limit of int is reached and if limit is reached it will not consider anything after that. Then it will put the maximum value of int in the variable num and null int the string s. If limit is not reached, then string will remain in the input stream as it is, and will be fetched by variable s.
Try using cin.clear before you accept string
Here is my code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
string nom_fich("data.dat");
ofstream fichier(nom_fich.c_str());
string name;
cout <<"The name is: "<< name ;
cin>>ws;
if (getline(cin, name)){
fichier << name <<endl;
} else {
cerr <<"Error!";
}
fichier.close();
return 0;
}
Question: why if I enter a number instead of a string my program doesn't say me "Error!" ?
EDIT: how can I attempt to my purpose ? I want that get an "Error!" when I enter a type that isn't a type string.
Because a number is a valid string.
Numbers can be represented as strings, i.e. strings can contain digit characters. For example:
std::string my_string("42");
std::cout << my_string[0]; // prints 4
std::cout << my_string[1]; // prints 2
You can't enter a number. You can enter a sequence of characters that can be interpreted as a number, but that sequence is still characters. Those characters arw what getline reads.
A number can be represented as a string, so std::ifstream::operator >> takes the intuitive approach: it treats any sequence of non-blank characters as a string. This includes decimal digits as well.
Unrelated, but instead of creating a superfluous nom_fich temporary variable for the name, you could just write ofstream fichier("data.dat");.
Because the string "123" is just as valid as the string "abc", or the string "def999".
As for "how can I attempt to my purpose?", you'd have to explain to us what your purpose is because, by your own admission, your own code does not describe that purpose and therefore we cannot extract your purpose from it.
Reading a number as a string will certainly work: the number is just represented as a sequence of characters. If you want the stream to attempt reading a number and fail if it doesn't get one, you'd use a different type to read, e.g.:
int number;
if (std::cin >> number) {
std::cout << "ERROR: read a number: " << number << '\n';
}
else if (std::cin.clear(), std::getline(std::cin, name)) {
std::cout << "read a name: " << name << '\n';
}
After the unsuccessful read of a number the stream's state is clear()ed and, instead, it is attempted to read a name. There is a subtle issue as the formatted input for an int will skip leading whitespace while std::getline() doesn't skip whitespace. If skipping leading whitespace is a problem just use the manipulator std::noskipws before trying to read an int.
This is a very strange issue. I'm trying to print a large text file, it's a Wikipedia entry. It happens to be the page on Velocity. So, when I tell it to print the file, it prints "In", when it should print "In physics, velocity is etc, etc etc".
Here's the code I'm using to print out:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char* wikiRead;
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
}
Please help.
wiki >> wikiRead;
The default delimiter for stream is space, so when the stream encounters a space, it simply stops reading, that is why it reads only one word.
If you want the stream to read all words, the you've to use a loop as:
char* wikiRead = new char[1024]; //must allocate some memory!
while(wiki >> wikiRead)
{
cout << wikiRead << endl;
}
wiki.close();
delete []wikiRead; //must deallocate the memory
This will print all the words in the file, each on a new line. Note if any of the word in the file is more than 1024 character long, then this program would invoke undefined behavior, and the program might crash. In that case, you've to allocate a bigger chunk of memory.
But why use char* in the first place? In C++, you've better choice: Use std::string.
#include<string>
std::string word;
while(wiki >> word)
{
cout << word << endl;
}
wiki.close();
Its better now.
If you want to read line-by-line, instead of word-by-word, then use std::getline as:
std::string line;
while(std::getline(wiki, line))
{
cout << line << endl;
}
wiki.close();
This will read a complete line, even if the line contains spaces between the words, and will print each line a newline.
You ask the stream to read the (binary) value of a pointer (probably 4 bytes, depending on your machine architecture), then you ask it to print the text pointed to by those 4 bytes!
I wonder why you ignored the compiler warning (most of the modern compiler warns you about using uninitialized variables). How about this?
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char wikiRead[255];
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
Alternatively I'd suggest you to use string object with getline to get a single line of text.
string str;
getline(wiki, str);
The >> operator applied to a char * reads only one word. Moreover, you're reading into an uninitialized pointer, which is not valid. Usually std::string, not char *, is used for string processing in C++.
If you only want to print the file's contents, you can hook the file's buffer directly to std::cout:
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::cout << wiki.rdbuf() << '\n';
}
If you want to put the contents into an automatically-allocated string, use std::getline with the delimiter disabled.
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::string wiki_contents;
getline( wiki, wiki_contents, '\0' /* do not stop at newline */ );
std::cout << wiki_contents << '\n'; // do something with the string
}
Since you want to read a large file, reading it block by block is a better way.
ifstream wiki;
wiki.open("./wiki/velocity.txt");
const int buf_size = 1024;
char* wikiRead = 0;
int cnt = 1;
do
{
wikiRead = realloc( wikiRead, bufsize*cnt );
wiki.Read( wikiRead + (bufSize*(cnt-1)), buf_size ); //appends to reallocated memory
cnt++;
}while( !wiki.eof())
wikiRead[(bufSize*(cnt-2)) + wiki.gcount() + 1] = '\0'; // null termination.
wiki.Close();
cout << wikiRead;
delete[] wikiRead;
The operator>> is designed to only read one word at a time. If you want to read lines, use getline.
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
string wikiRead;
while (getline(wiki, wikiRead))
{
cout << wikiRead << endl;
}
wiki.close();
}