Can't understand what's wrong with litlle code (getline()) - c++

I am a bit ashamed with this, but really I can't see what's not working properly with this code. For now it should only store some book names (hence the array and the getline()), and the first cin indicates how many of them I am going to store. But I don't know why, if I enter a number N for nbBooks, I am only able to enter N-1 book names, and library[0] (last book entered) is just a space.
#include <iostream>
using namespace std;
int main()
{
int nbBooks;
cin >> nbBooks;
string library[nbBooks];
while(nbBooks--) {
getline(cin, library[nbBooks]);
}
cout << library[0];
return 0;
}
I know there must be something with getline(), but even though I did search answers about this I couldn't find any.

arrays must has a Specific size at compile time not at runtime.
this code will issue an error flag: "error C2133: 'library' : unknown size"
if you want to allocate an array with a size assigned at runtime then:
use the memory HEAP:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int nbBooks;
cout << "nBooks: ";
cin >> nbBooks; // nBooks is not defined until runtime
cout << endl;
cin.sync(); // flushing the input buffer
string* library = new string [nbBooks]; // allocating pointer to array on the heap memory not the stack
int i = 0;
while(nbBooks--)
{
cout << "library[" << i << "]: ";
getline(cin, library[i]);
i++;
cin.sync(); // flushing again the buffer remeber "safe programming is the purpose of any programmer"
}
cout << "library[0]: " << library[0] << endl;
// now remember memory of heap is not unallocated by the compiler so it must be fred by the programmer
delete[]library; //dont forget "[]"
return 0;
}
now compile the code and everything will work correctly.
I use cin.sync() right after cin>> nbooks; to ensure FLUSHING the input buffer.
and once again inside the loop after any assignment to the elements I used another to ensure flushing the buffer.
as I know there's an error in getline which doesn't flush the input buffer totally so some data will affect other variable, to overcome this problem we use cin.sync() to ensure emptying the buffer.

Alright, I am a bit confused : a simple cin.ignore() before the getline() function made it work now, while the same thing wasn't working 10 minutes ago (eventhough I was rebuilding and recompiling each time)(and I swear to god I am not idiot enough to forget that ;) )... So sorry for my pretty useless question...
Oh by the way :
while(nbBooks--) {...}
It evaluates the value nbBooks, then decrement it, so no problem here.

Well, the problem is with the \n character which is staying in the buffer after this cin >> nbBooks; line gets executed. The operatot>> method of cin does not accept \n by default thus the newline character is not pulled out from the buffer. So, you have to pull it out, right?. Just add cin.get(); after cin >> nbBooks;. The get() method will extract the \n character. Rest of the code is fine.

Related

How does inputting a string into an int variable work in C++

this is some code that i have in C++:
#include <iostream>
using namespace std;
int main() {
int num1;
string some;
cout << "enter something";
cin >> num1 >> some;
cout << num1 << endl << some;
return 0;
}
I'm a bit confused about how inputting works exactly in C++. First of all, through observation i figured that when asking for multiple inputs, C++ looks for either space or line separated data and am not sure if that is exactly true as websites i have looked at don't say this explicitly. Also my main problem is what happens when for num1, which is an integer variable, i input 'hello', which is a string, and click enter. In that case, C++ doesn't even ask me for an input for some and instead just outputs 0. I am a beginner in C++ and am very confused why this happens as i would expect an error message instead. I am hoping that someone would explain to me the procedure that C++ goes through when dealing with a situation like this, where a string gets stored in an int variable, to better understand inputting in C++. Thanks!
With "Hello" you are putting the cout and cin into an error state where especially cin doesn't accept any further input.
If you want to prevent the user from writing text instead of numbers, you have to check each input character. There are several functions that can check if a key code equals a number or not.

Can a code run if initial array value is less then input value?

I am confused after the following C++ code executed:
#include <iostream>
using namespace std;
int main()
{
char name[0];
int roll;
cout << "Enter your name: ";
cin.get(name, 30);
cout << "Enter roll no.: ";
cin >> roll;
cout << "You have entered:" << '\n';
cout << "Name: " << name << '\n' << "Roll No. " << roll << '\n';
return 0;
}
As you see, it simply takes input and print it. But the problem is, how cin is supposed to read all the characters i have entered if the value of array is 0!!!
The output is as follows:
Enter your name: Bharat Singh Chauhan
Enter roll no.: 12345
You have entered:
Name: Bharat Singh Chauhan
Roll No. 12345
Sorry if the question is asked before ;)
This code:
char name[0];
cin.get(name, 30);
invokes undefined behavior because name does not have enough space to store 30 chars. This means anything can happen, including the program appearing to work sometimes.
Instead, you can do:
std::string name;
std::cin >> name;
// or
std::getline(std::cin, name); // if you want to accept whitespace
which is less error prone in general than using arrays.
Because C/C++ doesn't check memory borders natively. It is undefined behavior, because you're overwriting memory that you didn't allocated here, so, probably, overwriting memory, that was allocated for another purpose, for another variables, structs, etc. With another conditions you can get segmentation failed error.
Why conditions for segmentation failed didn't met now? Because default stack size (memory where your variable is "allocated") is much larger by default and easily can handle your hand-types strings here.
Also compilers could have option stack protection. So, they will warn if you overrun stack memory. It will not really protect you from undefined behavior or overwriting your local variables, but can help to find the problem, not always, but when your overrun is large enough to detect it. See this link for more information: Stack smashing detected
char name[0]; - that is an array of zero 0 characters. If you read more than 0 characters into it, you have undefined behaviour. Arrays don't automatically grow as you add stuff to them. For that you want std::vector or std::string.

Visual C++ - Runtime Check Failure #3 - Variable is not initiliazed

I use Visual C++ 2010 Express Edition to compile and run the .exe files I write in the C++ programming language. I am trying to create a loop-based logic using C++ to ask the user how many entries he chooses to enter, and ask questions limited to that no. of entries. For example I want to output, "How many characters do you wish to enter?: " Say the user gives the answer as '3' which is stored in the int variable 'entries'. I then want to keep asking the question 3 times before it stops and continues with the next line of code. I hope you understand, here is a block of code to demonstrate what I am doing:
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "How many values do you need to enter?: ";
int entries;
cin >> entries;
int offset, number;
string valueName[50];
float valueValue[50];
for (offset = 0; offset < entries; offset++)
{
cout << "Enter " << number << " Value Name: ";
cin >> valueName[offset];
cout << "Enter " << valueName[offset] << "\'s value: ";
cin >> valueValue[offset];
for (number = 1; number <= entries; number++)
{
}
}
char response;
cin >> response;
return 0;
}
Strangely when I run this simple program, it fails when I enter the value's name to be inserted into the 0th element of the valueName[] array. It just pauses the execution of the program and a dialog box pops up saying "Runtime Check Failure #3 - Variable 'number' is being used without being initialized!" Another problem regarding this program is that, for quite some time, when I ran this program this "Runtime Check Failure #3" box never appeared, and when it didn't, the number value went wrong, and first started with 1, and then for the next loop jumped to 6, and then repeated 6 again for the next loop! Please help me! I've checked online scouring this problem everywhere, but it just doesn't apply to my type of problem! Is it because the variables are out of scope? But they're declared outside the for loops right? So please help me!
The runtime is telling you the truth, the following line comes after you have declared number as an int but have not given it a value.
cout << "Enter " << number << " Value Name: ";
In your code you declare the following, in C++ this means give me 2 ints but the values are not defined yet, e.g.
int offset, number;
Change it to something like this ..
int offset = 0;
int number = 0;
You are printing the variable number without assigning to it first, i.e. it's uninitialized. When it prints some random number it's because that what happens to be in the memory at the time you run the program. Assign a value to it before you use it.
The problem is exactly the error message you're getting. You're using the variable number without initializing it.
You use the variable right here, at the top of your loop, when it hasn't been initialized to anything yet:
cout << "Enter " << number << " Value Name: ";
What is your intention with the number variable? It doesn't really seem to be serving any purpose. If you want to print which entry you're currently on, you could use the offset variable instead, like this:
cout << "Enter " << offset << " Value Name: ";
But that still seems a little unclear to me.
But the reason that you're having a problem is because the value is uninitialized, so you're experiencing undefined behavior. This is also the reason that Visual Studio doesn't always catch it; it will probably always catch in Debug mode, but in Release mode it will almost never catch it. You need to initialize all your variables before you use them.
In my case it was because an extern variable was declared twice.

C++, Text to ASCII while-loop error

I've come this far without asking for help, but I've got a problem that I can't seem to fix. I like cryptology, so now that I am learning C++, I want to make programs to encrypt and decrypt strings. I read that the best way is to convert the text to ASCII and go from there, so here is a simple program I made in C++ to try and convert a char variable to ASCII:
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main()
{
char strString[1000];
cout<<"Enter you message:"<<endl;
cin>>strString[1000];
string strEncrypt;
int a = 0;
while (strString != '\0')
{
int b = (int)strString[a];
strEncrypt.at(a) = b; //This is where I'm getting an error.
a++;
}
cout<<"Encrypted message:"<<endl;
cout<<strEncrypt<<endl;
}
So, I've tried all 3 things I know to do to troubleshoot (Google, check for missing simicolons, and make sure I'm doing == not =, but this is just something I don't know how to do, not something I'm forgetting (I hope). So, any help would great!
You don't have to change the characters to ASCII they already are. Chars are basically the same as integers in memory.
Now to your question; . If you want to set a character in a string you can do that like this
string[index] = b;
Another thing to be careful for in your code. You are using cin to read the string from the user. This will not let you read messages that have spaces in them and will only read the first word. For example, if the user enters "Love Crypto" cin will only read "Love" and "Crypto" will be ignored. To get the entire line, use getline instead.
As for looping over characters in a string, it's better to do it as follows:
for(int i = 0; i < strString.length(); i++)
{
strString[i] = bla;
}
Again, you're code isn't actually doing anything. It is only reading a letter and then storing a "letter" in another string.
string::at() throws exception if the index passed to at() is out of range. So, if you are getting runtime error then it's expected. Because, your string strEncrypt is initialized to "" and thus the size is 0.
You may try
strEncrypt.reserve(strlen(strString));
Easiest way to actually make the code you have work is change this line strEncrypt.at(a) = b; to this strEncrypt += b; Which will add the characters to the empty string strEncrypt.
Your code doesn't make much sense though as char types are already ascii. You'll have to explain more about what kind of encrypting you are trying to do and maybe we can point you in the right direction.
EDIT: After thinking about what you're trying to do a bit more based on the code you have it seems like you want to print the numeric ascii value of characters. You can do that with just a cast like this:
string input;
cout << "Enter you message:" << endl;
// handle spaces in the message
getline(cin, input);
cout << "String chars as ascii values:" << endl;
cout << "Char: " << "ASCII Code:" << endl;
for (int i = 0; i < input.length(); ++i)
{
// casting the char to an int with (int) will print the ascii code
cout << input[i] << " " << (int)input[i] << endl;
}
On top of the fact that your input is already in ASCII, keep in mind that doing cin >> strString[1000] doesn't limit the input captured to the length of your buffer unless you specifically specify the number of characters to capture for the stream object using setw() or setting it's ios_base::width data member. So your method right now risks buffer overflows.
Secondly, the form of cin >> that you're using will not capture the entire line of input. Instead it will stop at the first white-space or any other delimiting character (or end-of-file if that is reached first). In your case, if you are entering a line like "Hello World", then the syntax you're using will only capture "Hello" and drop "World".
A much better idea would be to use the getline() function with a std::string object if you are wanting to capture a line of input to a string and remove the delimiting newline character without risking buffer overflows ... for instance:
string strString;
getline(cin, strString);
Apart from advises given, when receiving this kind of run-time errors use Cppcheck utility.
It will give you the answer: "Message: Array 'strString[1000]' index 1000 out of bounds".

Loop problem. Cin C++ getline clear buffer

I am having a problem, but I cannot figure out what I'm doing wrong. I'm not sure if it's a problem with my loop, or the cin buffer is not being cleaned. I am doing a program that transforms a C-style string to uppercase, however if the user enters more than 11 characters, then the function should only display the first 11, and anything after that should not be displayed.the problem is that if I enter more than 11 characters, then my loop never stops and keeps telling the user that the answer entered is invalid and if he would like to enter a new string.
The issue comes from when you're trying to clear your buffer. When you return from cStringToUpper there are still extra characters in your buffer, but you're immediately looking for y/q.
You give cin.getline a buffer 12 long so it will only take that many characters, the rest are still in the buffer. If you instead use
string str;
cin.getline(str)
Then you will get the whole line, then you can crop it at 11 characters. Not 100% on the cin-syntax but you get the idea.
Or move the ignore-part above
cin >>cont;
to ignore the extra characters that way.
cin >> cont;
cout << "\n" << endl;
cin.ignore(200,'\n');
should be
cin.ignore(200,'\n');
cin >> cont;
cout << "\n" << endl;
You may correct your program by modifying your cStringToUpper fn. something like:
...
int loopCount;
char buffer[256];
cin.getline(buffer,256);
strncpy(letters, buffer, 11);
//letters[11]= '\0';
cout << "\n" << endl;
...