My program is to read characters into an array and display it to the console. But I don't know why it only reads first 3 characters.
#include <iostream>
using namespace std;
int main() {
int length=0,i;
char str[10];
cout<<"Enter a string"<<"\n";
for(i=0; str[i] != '\0'; i++) {
cin>>str[i];
}
for(int i=0; str[i]!='\0'; i++) {
cout<<str[i];
length++;
}
cout<<"\n"<<"Length of the string="<<""<<length<<"\n";
}
The output looks like:
Here are some of the issues I noticed:
You're checking the contents of str before you even initialize it.
You're assuming the string you're fetching from the stream will be null-terminated, but that's actually not the case.
You aren't checking whether cin is working correctly
You don't check to make sure the string is 10 characters or less, this could cause you to overflow past the end of the buffer
When you're checking the length of the array, again you assume the string is null-terminated
If you want to fix these issues and still use a char buffer, see user4581301's comprehensive answer. However, I'd suggest simply switching to std::string. For example:
#include<iostream>
using namespace std;
int main()
{
string str;
cout<<"Enter a string"<<"\n";
if (cin >> str) {
cout << str << endl;
cout << "Length of the string = " << str.length() << endl;
}
}
TL;DR version
std::string str; //use std::string. practically no reasons not to in C++
if (cin >> str) // read into string and test that read succeeded.
{
std::cout << str << '\n'
<< "Length of the string=" << str.length() << endl;
}
Explaining and salvaging Asker's version
for(i=0; str[i] != '\0'; i++){ // str[i] tested here
cin>>str[i]; // but it has no assigned value until here.
uses str[i] before it is assigned a value. The program likely found a null character in the block of memory allocated for str and stopped prematurely, but technically anything can happen if you use an uninitialized variable. For example, you got the expected result 3 times before finding the null. The program could never found a null and run forever. It could have rained unicorns. Anything.
int i = 0;
do {
cin>>str[i];
} while (str[i++] != '\0');
reads then tests. But lines of data in a stream are not C-style strings and are not terminated with null.
int i = 0;
do {
cin>>str[i];
} while (!std::isspace(str[i++]));
exits when whitespace is found, typically signalling the end of a word, rather than null.
But what if cin>>str[i]; failed for some reason?
int i = 0;
do {
cin>>str[i];
} while (cin && !std::isspace(str[i++]));
Adds a test to ensure something was read. But what if there are more than 10 characters and char str[10]; is overflowed?
int i = 0;
do {
cin>>str[i];
} while (cin && !std::isspace(str[i]) && ++i < sizeof(str));
unless I am reading That is legal unless I'm reading [expr.cond] and [expr.log.and] wrong, sequencing of when ++i occurs in !std::isspace(str[i]) && ++i < sizeof(str)) is guaranteed to not affect !std::isspace(str[i])
But what if you run out of space before find the null? str is unterminated and not a string! This ruins the for loop later in the program.
int i = 0;
do {
cin>>str[i];
} while (cin && !std::isspace(str[i]) && ++i < sizeof(str));
if (i == sizeof(str))
{
str[sizeof(str)-1] = '\0';
}
I think that covers everything you're likely to run into here.
You read in character by character and store it in str[i]; but then you increment i++ before checking str[i]!='\0'.
There are two issues with this approach: First, you check a value at a position that has not been written at that point in time. Second, cin>>str[i] will never write the string termination character - it just reads in valid characters, and if input is terminated (e.g. by EOF), nothing is written.
So you are approaching this the wrong way.
If you want to read at most 10 characters up to a new line (i.e. when the user presses enter), use fgets. Or - and this is the preferred option - use cin and write into an std::string-object.
int main()
{
std::string str;
cin >> str;
std::cout << str << std::endl;
}
str[i] != '\0' checks the pre-existing data stored at str[i], not the user-input value.
Add string initialization:
char str[10] = {'\0'};
and change the reading with:
char c;
for(int i = 0; cin>> c && c!=/*add your termination cond. here*/ && i < 10;++i)
str[i] = c;
So you can ensure that the string is filled with correct values and terminated appropriately.
But better solution would be to use std::string. In that case you dont have to check the sizes, because the string grows by itself.For example:
std::string str;
for(char c; cin>>c && c!=/*add your termination cond. here*/;)
str += c;
Related
I am a beginner in c++ and I want to enter a string as character by character into an array , so that I can implement a reverse function .. However unlike C when the enter is hit a '\n' is not insterted in the stream.. how can I stop data from being entered ?
my code is :
#include<iostream>
#include<array>
#define SIZE 100
using namespace std;
char *reverse(char *s)
{
array<char, SIZE>b;
int c=0;
for(int i =(SIZE-1);i>=0;i--){
b[i] = s[c];
c++;
}
return s;
}
int main()
{
cout<<"Please insert a string"<<endl;
char a[SIZE];
int i=0;
do{
cin>>a[i];
i++;
}while(a[i-1]!= '\0');
reverse(a);
return 0;
}
When you read character by character, it really reads characters, and newline is considered a white-space character.
Also the array will never be terminated as a C-style string, that's not how reading characters work. That means your loop condition is wrong.
To begin with I suggest you start using std::string for your strings. You can still read character by character. To continue you need to actually check what characters you read, and end reading once you read a newline.
Lastly, your reverse function does not work. First of all the loop itself is wrong, secondly you return the pointer to the original string, not the "reversed" array.
To help you with the reading it could be done something like
std::string str;
while (true)
{
char ch;
std::cin >> ch;
if (ch == '\n')
{
break; // End loop
}
str += ch; // Append character to string
}
Do note that not much of this is really needed as shown in the answer by Stack Danny. Even my code above could be simplified while still reading one character at a time.
Since you tagged your question as C++ (and not C) why not actually solve it with the modern C++ headers (that do exactly what you want, are tested, save and work really fast (rather than own functions))?
#include <string>
#include <algorithm>
#include <iostream>
int main(){
std::string str;
std::cout << "Enter a string: ";
std::getline(std::cin, str);
std::reverse(str.begin(), str.end());
std::cout << str << std::endl;
return 0;
}
output:
Enter a string: Hello Test 4321
1234 tseT olleH
I am quite new in c++ and programming so sorry in advance in my question repeats. I have a text file of 3 lines:
7
00000000000000000000000*0000
0 0 0 R 0
What I need to do is read 2nd line and write it into an array as char. But I must not include 3rd line because it will go to a completely different matrix. My code so far :
ifstream input;
input.open("input1.txt");
input >> start;
char a=0;
string line;
while (getline(input, line))
{
a=0;
istringstream iss(line);
int length = line.size();
for (int i=0; i<length; i++)
{
iss >> a;
A[i] = a;
cout << A[i] << " " << i << endl;
}
}
input.close();
However, with this code it always starts new array for 3rd line. What am I doing wrong? What is the easiest way to fix it? Thank you.
-----------------------------Update--------------------------------------
I have modified the code but it still does not work properly. I am getting this kind of result : 5)-└ instead of correct one. My current code:
void Read(int &numLines, int &start, vector<char>&A, char B[][5])
{
ifstream input;
input.open("input.txt");
input >> start;
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
string line;
if(getline(input, line))
{
for(char temp: line)
{
A.push_back(temp);
}
}
input.close();
}
A here is a vector I want to write 2nd line to, char by char
Start is just an integer in which I am storing 1st line (7)
Thank you very much for advices
Mixing >> and std::getline is non-trivial. For example, after input >> start; the end of line marker is left in the stream in case it's still needed. In your case it isn't, and it is picked off by the subsequent call to getline, resulting in a read of an empty line.
This is what's complicating your read of line and forcing the while loop and test for empty lines.
Step through your program with your development environment's debugger and you'll see what I'm talking about. Get used to using the debugger. It's possibly the best programming productivity tool you'll ever encounter.
The easiest way to fix it is to place
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
after
input >> start;
to eat up the end of the line (and anything else that might be on that line. This needs the addition of #include<limits> to get std::numeric_limits<std::streamsize>::max.
Then you can remove the while loop and replace it with
if (getline(input, line))
No loop, not chance of consuming multiple lines from the file. And the logic for reading and processing the third line can follow.
Side note: instead of that for loop, consider
int i = 0;
while (iss >> a)
{
A[i] = a;
cout << A[i] << " " << i << endl;
i++;
}
This will march through iss until it hits the end of the line. You can also throw iss out entirely and just read the characters directly out of line.
int i = 0;
for(char temp: line)
{
A[i] = temp;
}
And A should probably be a vector if it isn't already to reduce the chances of buffer overruns.
for(char temp: line)
{
A.push_back(temp);
}
I would go with something like this:
std::string start;
std::string Astring;
ifstream input;
input.open("input.txt");
input >> start;
input >> Astring;
// If you really want a char array
char * A = new char[Astring.size()];
for (unsigned int i = 0; i < Astring.size(); i++) {
A[i] = Astring[i];
}
// Don't forget to delete after use
delete[] A;
Moreover, if you just need the char array as an input to something else later, you can call Astring.c_str() instead of that for loop, which returns a C-style char array.
Hello there I have a little problem with cin. How can I do cin while != '.' and '\n' ? Below is my code
#include <stdio.h>
#include <iostream>
using namespace std;
void reverse(char x[])
{
if(*x=='\0')
{
return;
}
else
{
reverse(x+1);
cout<<*x;
}
}
int main(){
char a[]="";
while (cin.get()!='\n'&&cin.get()!='.') {
cin>>a;
}
reverse(a);
}
Input: foo.
Output: .o
It cut me 2 last words
You shouldn't include both "stdio.h" (or better <cstdio>) and <iostream>. The former lets you use C standard IO functions, while the latter is the standard for C++. Pick one, for example as in your code you are actually using some <iostrem> facilities, include that.
The problem you are facing basically requieres 3 steps:
read standard input untill a '.' or a '\n' is entered.
store each character except '.' or '\n'.
send the character read to standard output in reverse order.
I think that second point is the key point. Where do you store the character you read? In your code you seem to use c-style null terminated char arrays, but you are not allocating the necessary memory for doing that.
Then, when you use cin.get() you are actually removing a character from to input stream and you do that 2 times before reading a.
I also don't think that using recursion for the last step is a good idea. Maybe it's mandatory in your assigned task, but use of recursion like this (and the tipical factorial example) better stay in books. If you want to use a stack to accomplish the task, it's better to do so explicitly, like here:
#include <iostream>
#include <stack>
int main() {
char c;
std::stack<char> sc;
while ( std::cin.get(c) && c!='\n' && c!='.' )
sc.push(c);
std::cout << std::endl;
while ( !sc.empty() ) {
std::cout << sc.top();
sc.pop();
}
std::cout << std::endl;
return 0;
}
A more "natural" way of doing this task is to store the chars in a std::string and show them in reverse order:
#include <iostream>
#include <string>
int main()
{
std::string a;
char c;
while ( std::cin.get(c) && c != '.' && c != '\n' )
a += c;
std::cout << std::endl;
// you can print what you read with: std::cout << a;
for ( std::string::reverse_iterator rit = a.rbegin(); rit != a.rend(); ++rit )
std::cout << *rit;
std::cout << std::endl;
return 0;
}
If you want to use an array of char to store the input, you have to preallocate enough memory for your needs.
#include <iostream>
#define MAX_CHARS 128
int main()
{
char a[MAX_CHARS + 1]; // enough to store 128 char and the '\0'
char c;
int counter = 0; // better knowing how many char you read
for ( counter = 0; counter < MAX_CHARS
&& std::cin.get(c) && c!='.' && c!='\n'; counter++ )
a[counter] = c;
a[counter] = '\0';
std::cout << std::endl;
// you can print what you have read with: std::cout << a;
while( counter > 0 ) {
--counter;
std::cout << a[counter];
}
std::cout << std::endl;
return 0;
}
If you are reading input from terminal you have to enter a whole line followed by newline in any case, because you are reading a buffered input. If you need unbuffered input and to stop reading characters right when a . or enter is pressed then there isn't a standard C++ solution, it depends on your environment. For sake of semplicity you can use the c-style (and deprecated) getch():
#include <cstdio>
#include "conio.h"
#define MAX_CHARS 128
int main()
{
char a[MAX_CHARS + 1]; // enough to store 128 char and the '\0'
char c;
int counter = 0; // better know how many char you read
while ( counter < MAX_CHARS && (c=getch())
&& c!='.' && c!='\n' && c!='\r' ) {
putchar(c);
a[counter] = c;
counter++
}
a[counter] = '\0';
printf("\n");
// you can print what you read with: printf("%s\n",a);
while( counter > 0 ) {
--counter;
putchar(a[counter]);
}
printf("\n");
return 0;
}
You can replace the first get with peek:
while (cin.peek() != '\n' && cin.get() != '.')
std::basic_istream::peek keeps the character in the buffer, so std::basic_istream::get reads the same, but compares it to other.
- wrong. That would keep \n in the buffer, but . not.
Right: Use a char variable into which you extract only once and compare it twice:
char c;
while (cin.get(c) && c != '\n' && c != '.')
...
Doing a get removes the character from the input stream, so the first two characters are removed in the while loop condition before you've even entered the loop. cin >> a; reads in the next word (space separated) and puts it into a. It does not read character by character. This puts "o." into a, as 'f'and 'o' have been removed from the input stream. You then read the newline in the condition check and you exit out of the loop.
Instead, you should call cin.get() once and store the return value as an int ready for using it ie.
int ch = cin.get();
while(ch!='\n' && ch != '.') {
// Do something with ch
//get the next character ready for the next iteration
ch = cin.get();
}
I should also mention that a only has enough space for one character. You should make a bigger, doing something like char a[200]; which creates space for 200 characters. You should also check you don't try to access anything past a[199].
When I enter "111 111" and then press enter, the output shows nothing. Then when I press enter twice, the expected output appears. Why is that?
#include<iostream>
using namespace std;
int main()
{
char seq[10];
//initialize the sequence
for (int i = 0; i<10; i++)
{
seq[i] = ' ';
}
//read characters from the keyboard
for (int i = 0; i<10; i++)
{
cin.get(seq[i]);
if (seq[i] == '\0')
{
break;
}
}
//the output should be the sequence of characters
//users typed before
cout << seq;
system("pause");
return 0;
}
You can use header file string instead, which provides more flexibility like below:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string seq;
//initialize the sequence
//read characters from the keyboard
getline(cin,seq);
//the output should be the sequence of characters
//users typed before
cout << seq;
system("pause");
return 0;
}
In response to OP's question update:
In the described case, You never inputting \0 from standard input, right? Rather you are pressing enter key.
if (seq[i] == '\0'){
Instead, you can replace this checking line with:
if (seq[i] == '\n'){
You can provide std::getline() with an additional char parameter, that defines the line-delimiter. In your case, simply let it read to the next '\0'.
auto seq = std::string{};
std::getline(cin, seq, '\0');
BTW.: are you really sure, you want to read to the next '\0'? It is not too easy to enter a zero character with the keyboard. If you actually are interested in a complete line from the input, just drop the delimiter parameter: std::getline(cin, seq).
This code:
for (int i = 0; i<10; i++){
seq[i] = ' ';
}
initializes all elements in seq to spaces, not '\0'. I don't think your break statement will trigger therefore.
Your program reads 10 characters before it does anything else. So you need to provide 10 characters.
The break check never triggers. why would it.
Finally, cout << seq is not safe, as it may read memory past the end of seq.
I have problem with the following code:
#include<iostream>
using namespace std;
int main()
{
char a[200];
int i;
for (i = 0; cin.get() != '\n'; i++) {
cin >> a[i];
}
cout << i;
system("pause");
return 0;
}
I don't know why when i input without space 10 char for example. i si equal to 10/2=5 ?
You discard every odd symbol, cin.get() read symbol 1,
cin >> read symbol two, and again cin.get() read symbol 3,
and cin >> read symbol 4 from standard input.
You are throwing out half of your cin results.
When you use cin, a character is read, but you are not assigning it to anything inside the for loop criteria; only inside the loop body are you saving it.
Inside the loop, you read in another character (after the one you already read in during the loop's test criteria) and assign that one. The loop repeats, and the next character read is again thrown away with the line cin.get() != '\n' because you are not assigning the results to anything. And this continues, alternating characters you throw away with characters you "save" into the array.
You get two characters, once increment i variable and only second of them insert in array
int main()
{
char a[200];
int i;
\\ cin.get() - get one char and insert it in a[i]
\\ after that, compare this value with '\n'
\\ if equal, break the loop, if different, continue
for (i = 0; (a[i] = cin.get()) != '\n'; i++);
\\ last character ('\n') should be replaced with '\0'
a[i]='\0';
cout << i;
system("pause");
return 0;
}
while solution:
int main()
{
char a[200];
int i=0;
cin >> a[i];
while (a[i] != '\n')
{
i++;
cin >> a[i];
}
a[i]='\0';
cout << i;
system("pause");
return 0;
}
do - while solution:
int main()
{
char a[200];
int i=0;
do
{
cin >> a[i];
}
while(a[i++]!='\n');
a[i-1]='\0';
cout << i-1;
system("pause");
return 0;
}
As a matter of fact, you are reading the standard input (std::cin) in two different ways, storing its output only once every two character extractions.
std::basic_istream::get (cin.get()) extracts character or characters from stream. Once extracted, whey are forgotten, sent to limbo. You simply ignore them. Which is not what I suspect you want to do.
std::basic_istream::operator>> (cin >> ...) also extracts character or characters (following the type of the right hand side operand).
So, with an input of ten characters, you ignore five of them in your for condition check and store five in the loop block.
A correct way to read the characters would be to use std::getline (en.cppreference.com/w/cpp/string/basic_string/getline):
std::string input;
std::getline(cin, input);
std::cout << input << std::endl;
This example code will simply read a line and output it, verbatim, in the standart output.