how to store data into dynamic array - c++

I have this program that asks user to enter a number and ask the user if they want to view input history. So i was wondering if my code is correct. I want to know if doing cin>>num[count-1] is correct or is there a correct way to get the data the user inputs. Here it is:
#include<iostream>
using namespace std;
int main(){
const int size = 20;
int *num = new int[size];
char answer;
int count = 1;
while(true){
cout<<"ENTER NUMBER: \n";
cin>>num[count-1];
cout<<"TRY AGAIN? ";
cin>>answer;
switch(answer){
case 'y':
count++;
system("cls");
break;
default:
cout<<"INPUT HISTORY: \n";
for(int i=0;i<=count-1;i++){
cout<<num[i]<<endl;
}
count++;
}
}
delete [] num;
return 0;
}
I want to know is doing cin>>num[count-1]` is correct or is there a correct way to get the data the user inputs.

Your code is a c-style code. You have the std::array and std::vector to help you to write a more secure and clean code. Because your tag in your question is dynamic-arrays I suggest to use the std::vector.
Bellow you can check out your code could be with the replacement.
#include <iostream>
#include <vector>
using namespace std;
int main() {
//int *num = new int[size]; //normally you don't need to use new. Let the c++ manage it for you
vector<int> num;
char answer;
while (true) {
cout << "ENTER NUMBER: \n";
num.emplace_back(); //Create a new element to vector num
cin >> num.back(); //set this new element
cout << "TRY AGAIN? ";
cin >> answer;
if (answer == 'y')
system("cls");
else {
cout<<"INPUT HISTORY: \n";
for (auto& numEle : num) //It will interate over all elements of num
cout<< numEle <<endl;
//break; //Maybe you want to break the loop here
}
}
// delete [] num;
return 0;
}

I will first show you the problems in your code. I put in comments.
Then I will explain you, why your input is wrong. Also the answer from user TheArquitect is wrong and will finally lead to a memory overflow.
Your program will also have a desastrous result.
First see the code:
#include<iostream>
using namespace std; // In C++ we never use this statement. Why? See:
// You will find at least 1000 comments in Stackoverflow
int main() {
const int size = 20; // In C++ we use constexpr for compile time constants
int* num = new int[size]; // In C++ we
// Do not use raw pointers for owned memory
// Do not use new
// Do Not use C-Style arrays
// Generally: std::vector should be used
// Or at least std::unique_ptr and std::make_unique
// Also, this 2 lines are nonesense. It is the same as int num[20];
char answer; // All variables should always be initialized
// Variables should be in the scope, where they are necessary
int count = 1; // YOu could use uniform initialization
// Arrays start with index 0 in C++ (also in C )
while (true) { // You are creating an endless loop with desastrous effect
cout << "ENTER NUMBER: \n";
cin >> num[count - 1]; // No, this will not work. Explanation in text
cout << "TRY AGAIN? ";
cin >> answer; // No, this will not work. Explanation in text
switch (answer) { // Switch with only one case can always be expressed with if elese
case 'y':
count++;
system("cls"); // This is a non portable solution
break;
default:
cout << "INPUT HISTORY: \n";
for (int i = 0; i <= count - 1; i++) { // Nearly Never use <= in for loops
// Use for (int i = 0; i < count; i++)
// Do use ++i insted of i++
cout << num[i] << endl;
}
count++;
} // This is an endless loop. count will always be increased. If greater than 20
// then the memory will be corrupted. This will happen always
}
delete[] num; // Dead code. Will never be invoked
return 0;
}
OK. Now, besides the major bugs and the killing out of bounds problem, here the explanation for the problem with inputting data.
Rule: You must always check, if the input operation worked. For that you can check the state of the stream. Additionally, if you do not consume the input data (because of an erronous input by the user), this data is still in the input buffer. And in the next loop it will be read again (without waiting for new user input). The status of the input stream may still be wrong and it will also not read because of this.
Then the endless loop starts to run without user input and corrupts your memory.
You may check, by simply inputting a letter instead of a number.
How to fix?
Again, you must check the state of the stream after reading. This is usually done in the form:
if (std::cin >> number)
Why does this work? Because: The inserter operator returns a reference to the stream (so std::cin) and the boolean '!' not-operator for the std::istream is overwritten. It will show, if the state of the stream is still ok or not.
OK, understood. Now. What to do in case of error? 2 operations:
Clear all failure bits in the state of the stream --> std::cin.clear()
Eat up everything that is still in the input buffer --> std::cin.ignore()
You could write:
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
I assume that you are learing C++ in a class and learn about new and delete. As said, you should not use it. But because teacher request this often in the classes, I will show you now a better solution than yours, still using new, but without (most of) the problems.
#include<iostream>
#include <limits>
int main() {
// We want to create a dynamic array with 20 elements
constexpr size_t MaxArraySize{ 20U };
// Allocate a dynamic arry on the heap
int* numberArray = new int[MaxArraySize];
// Read maximum 20 numbers into our dynamic array
for (size_t currentArrayIndex{}; currentArrayIndex < MaxArraySize; ) {
// Inform the user that he should ent now a number
std::cout << "Enter number: \n";
// Read the number and check, if this worked
if (std::cin >> numberArray[currentArrayIndex]) {
// Now ask, if the user wants to continue or stop
std::cout << "Doy you want to enter more numbers? ('y' or 'n'): ";
// Define variable answer and get user input and check, if ok
if (char answer{}; std::cin >> answer) {
// Does the user want to continue?
if ('y' == answer) {
// Yes, continue. Increment array index
++currentArrayIndex;
}
else {
// No, the user does not want to continue. Show the values entered so far
std::cout << "Input History:\n";
for (size_t i{}; i <= currentArrayIndex; ++i) { // NOTE: <= becuase index has not yet been incrementet
std::cout << numberArray[i] << "\n";
}
break; // Stop the for loop and end the program
}
}
else {
// Strange, input of a character did not work. Should not happen. Terminate program
std::cerr << "\n*** Error: Problem with input!\n\n";
break; // Stop the for loop and end the program
}
}
else {
// The user entered someting wrong, or the input did not work for any other reason
// Inform user about problem
std::cerr << "\n*** Error: No number could be read!\n\n";
// Clear error flag and comsume whatever is in the input buffer
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Release dynamic allocated memory
delete[] numberArray;
return 0;
}

Related

Program outputs incorrect numbers from array

Jeopardy point adding code.
The program is supposed to get the number of players with a dynamic array.
From there, you can enter players names and it will insert the names into a two-dimensional array.
Then you can choose to call on a player to start adding points to.
After looping a certain amount of times and pressing 0, the while loop will cease to run and will skip down to the for loop outputting players name and then points.
Problem: If I input "1" for playerNumber, and I start adding points to index [0][1] and outputs numbers quite different from the original numbers I put in. If there are more than 2 players, 2 of the 3 players have random numbers while one remains an accurate point count.
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
//GLOBAL SCOPE, all loops and other boxes can use these
//Declaration variables w cout & cin.
int playerNumber;
string playerNames;
bool flag = true;
cout << "How many players are there: ";
cin >> playerNumber;
cout << endl;
//Array Declaration.
string playerList[playerNumber][2]; //Dynamic array. changes during program runtime.
int points[playerNumber]; //Dynamic array. Changes during runtime
//GLOBAL SCOPE, all loops and other boxes can use these
//Assigning values to arrays now.
cout << "Enter the players names: " << endl;
//Assigns player name to each row.
for(int i = 0; i < playerNumber; i++){
cin >> playerNames;
playerList[i][0] = playerNames; //Assigns players name to the array
cout << "Player " << i + 1 << ": " << playerList[i][0] << endl;
}
while(flag){
//LOCAL VARIABLES
int choice = 0; //Always reverts back to zero to prevent addition error.
int pointsValue = 0; //Always reverts back to zero to prevent addition error.
//LOCAL VARIALES
cout << "Press 0 to end game, if not, enter player number: " << endl;
cin >> choice;
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}
else if(choice < 0 || choice > playerNumber){
cout << "Choice is less than 0 or greater than player count. Try again." << endl;
}
else{
cout << "Enter points: " << endl;
cin >> pointsValue;
cout << endl;
points[choice - 1] += pointsValue; //Assigns points to points array
playerList[choice - 1][1] = (to_string(points[choice - 1])); //Assigns points to playerNumber.
}
}
cout << endl;
cout << "END OF JEOPARDY. HERE ARE THE POINTS!!!" << endl;
cout << endl;
//Current points for each player
//Shows their name and points
for(int i = 0; i < playerNumber; i++){ //Loops so that player name and points are displayed
string playerName = playerList[i][0];
string totalPoints = playerList[i][1];
cout << playerName << " points: " << totalPoints << endl;
}
return 0;
}
Technically, this is illegal:
string playerList[playerNumber][2];
int points[playerNumber];
The size of the array must be known at compile time (not runtime). Though some compilers allow this as an extension to the language, it is not part of the standard language.
Better choice would have been to use std::vector.
Lets assume your compiler allows this:
The next issue is that you don't initialize the values in the array.
int points[playerNumber]; // This is an array of random numbers.
// Sure if you are doing a debug build the
// compiler may be nice and just set all the
// values to zero as speed is not important
// during debugging. But on a release build
// these could be any value.
Also if we want to be technical its actually undefined behavior to read from the array unless you first write a value. Though usally this is not going to cause the program to crash on most architectures and unfortuantely the code just runs like nothing bad is happening.
You can normall initialize the array like this:
int points[10] = {0}; // but your variable size stuff
// will stop working for that.
-------
// so you will have to manually initialize the members
int points[playerNumber];
for(int loop = 0; loop < playerNumber; ++loop) {
points[loop] = 0;
}
Or if you upgrade to vector:
std::vector<int> points(playerNumber,0); // Size and initial value.
// Though you don't need the
// initial value as vector will
// zero init members.
The last issue I will mention is that you are not consistent on checking if the read worked.
cin >> pointsValue;
What do you think happens to pointsValue if the read fails (ie. the user puts in an illegal value). The proper way to check the user input is to put the read inside an if statement.
if ( std::cin >> pointValue) {
// The read worked `pointsValue` has valid user input
}
else {
// The read faild.
// We don't know what the user input should be
}
The other thing to think about is that user input is line based. They add values hit return. So it is a good tactic to exploit that and read user input by the line. Once you have the line parse that and validate input. That way the standard input stream does not go into a bad state.
std::string line;
if (std::get(std::cin, line)) {
// We have a line of user input.
std::stringstream lineStream(std::move(line));
line.clear();
int choice;
if (lineStream >> choice) {
// We have a valid choice from the user.
// or do we. If the user entered `2x` is that valid input?
// because `choice` is 2; but there is still `x` on the
// input stream.
// That's a choice for you as the developer to make.
// if you don't care, then you have valid input. If you do
// care then you need to check there is no bad data on
// the line.
}
else {
// invalid choice
}
}
else {
// The user input stream just ended.
// This could mean the user entered the end-of-stream character
// or if the user had connected some other stream to the
// standard input on the command line and there is no more
// data to read.
}
I would note that this will probably never work for invalid input.
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
// If you failed to read data from the std::cin
// the the value of `choice` is probably zero
// (if I remember my standard correctly) so the
// first branch of the if tree will be entered
// and you will never enter this branch.
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}

how to store input in a dynamic array?

So I am trying to make a program that stores user input into a dynamic array but I cant do it right. When I try to put a number let us say 1, and I want to try again then I want to view history, the only thing that shows up is the last number I have input. And sometimes there is a large number sowing up like 1214098101909279242 like that.
Here is my code:
#include<iostream>
using namespace std;
int main(){
const int size = 20;
int *num = new int[size];
char answer;
while(true){
cout<<"ENTER NUMBER: \n";
cin>>*num;
cout<<"TRY AGAIN? ";
cin>>answer;
switch(answer){
case 'y':
num[size+1];
system("cls");
break;
default:
cout<<"INPUT HISTORY: \n";
for(int i=0;i<=size;i++){
cout<<num[i];
}
}
}
return 0;
}
I have two major issues with your code:
There is no need for dynamic allocation in this case, since size is a const value (and can be defined as constexpr, which is better).
instead of using the standard containers (such as std::array (for constant size array) or std::vector (for dynamically expanding array)) you use a plain pointer array, which is ill-advised, and in this case can cause memory leak (for example, if you move this code into an utility function, since you never delete the memory of num array!), you should use std::unique_ptr instead! (and better read about the RAII idiom).
Spacing and indentation - your code should be readable to other coders as well.
About your code, the original code have the following line:
cin >> *num
which means put the value in stdin into the FIRST position of num. In both C/C++, arrays are just pointers to the first address of memory that was allocated for the array. In order to access the other items, you need to use the operator[] or use pointer arithmetic with the operator* (for example:
cin >> *(num + count)
will get the item at position count). Also, as pointed above, there is no safety measure for disallowing writing to an invalid memory that you can count on. Therefore, you should use the std containers which enforce index safety.
Just for reference, here is the code I would have wrote to get the same functionality:
int main() {
constexpr size_t SIZE = 20;
std::array<int, SIZE> arr;
arr.fill(0);
int last_filled_position = 0;
bool cont = true;
while (cont)
{
int val;
char answer;
cout << "ENTER NUMBER:" << std::endl;
cin >> val;
cout<<"TRY AGAIN? Yes/Print/Stop";
cin >> answer;
arr.at(last_filled_position++) = val;
switch (answer)
{
case 'y':
system("cls");
break;
case 'p':
cout << "INPUT HISTORY: " << std::endl;
for (int val: arr) // With more complex types, you should use const auto&
{
cout << val << ", ";
}
cout << endl;
break;
case 's':
cont = false;
cout << "STOPPING";
break;
}
}
return 0;
}
So I have change the code a little bit. Is my code valid for some reason? because it works fine now. I can input numbers and when i view all the numbers, it works fine.
#include<iostream>
using namespace std;
int main(){
const int size = 20;
int *num = new int[size];
char answer;
int count = 1;
while(true){
cout<<"ENTER NUMBER: \n";
cin>>num[count-1];
cout<<"TRY AGAIN? ";
cin>>answer;
switch(answer){
case 'y':
count++;
system("cls");
break;
default:
cout<<"INPUT HISTORY: \n";
for(int i=0;i<=count-1;i++){
cout<<num[i]<<endl;
}
count++;
}
}
return 0;
}

Infinite loop when using exceptions in c++11

I would like to create a c++11 program that takes in 10 positive integers and gives the user the total. In the event of a negative number or a char input, the exception should be thrown and the user must re enter their value.
The program below works with negative numbers. However, when I enter a character like "a", the program goes into an infinite loop and I cannot figure out why.
Any and all help will be appreciated
#include <iostream>
int main(){
int array[10] = {0};
int total = 0;
for(int i =0; i < 10; i++){
std::cout<<"Number "<< i+1 << ": " <<std::endl;
std::cin >> array[i];
try{
if(array[i] < 0 || std::cin.fail())
throw(array[i]);
}
catch(int a){
std::cout<< a <<" is not a positive number! "<<std::endl;
i-=1; // to go back to the previous position in array
}
}
for(int k = 0; k < 10; k++)
total+=array[k];
std::cout<<"Total: " <<total<<std::endl;
}
If you get invalid input there are two things to thing you need to do:
Clear the stream status. This is done using the clear function.
Remove the invalid input from the buffer. This is usually done using the ignore function.
As for your program, you don't need exceptions here, just using unsigned integers and checking the status is enough:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
To use exceptions similar to what you do now, the solution is almost exactly the same as above:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
throw i;
}
catch (int current_index)
{
std::cout << "The input for number " << current_index + 1 << " was incorrect.\n";
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
Do not forget to include limits header file while using following line in your code :
std::cin.ignore(std::numeric_limits::max(), '\n');
because numeric_limits template is defined in this header file !

Need some help finding a logical error in my while loop

I am learning C++, and I am doing some exercises in the book I am using. One of them asks to write a program that asks a user how many numbers they want to add up. Then prompt for the numbers the user wants to add or to enter '|' once finished. The numbers are then pushed into a vector. Part of the program asks to check if the size of the vector is equal to the original number of input items and that is where I keep getting an error.
cout << "Please enter the numbers and | once you are done: ";
while(true)
{
for(int num; cin >> num; )
{
if(num == '|')
{
break;
}
ints.push_back(num);
}
if(ints.size() != n)
{
cout << "There are more or less numbers in the vector than originally specified\n"
<< "Vector will be cleared; please re-enter the values: ";
ints.clear();
continue;
}
else
{
break;
}
}
The problem is that if the number of input is off, the message goes into an infinite loop and I am not sure how to fix it.
EDIT: n is the variable that holds in the number of values user wanted to enter.
Thanks!
num is an integer and cin >> num won't extract | symbol. Comparison num == '|' may not work as expected because num could have the numeric value of | ascii symbol even when user did not input any | symbol. You should properly handle end marker reading:
// loop will break when user enters `|` because it is not an integer
// setting failbit of cin
for(int num; cin >> num;)
{
ints.push_back(num);
}
cin.clear(); // reset failbit making cin able to read again
// check the end marker entered by user
{
string end_marker;
cin >> end_marker;
if("|" != end_marker)
{
// use of endl will flush the stream ensuring that
// printed text won't stuck in the buffer
cout << "Please use | as end marker" << endl;
continue;
}
}
Here is how I implemented it. I am worried about the logic in your while loop. I had been taught to avoid while(true) whenever possible. You know the logic behind how your code should work. With more practice you'll start to recognize the conditions you need to use. I am sure there are better ways to do it. But this is the way I tried it.
But to answer your question, the main reason it is failing is because integers cannot compare themselves with characters.
if(num == '|')
That does not work since num is an integer and not a character.
Normally I would implement this in a class and since global variables are not highly looked upon I created my own namespace. You'll have to finish the rest of the logic yourself however:
#include <iostream>
#include <vector>
#include <string>
namespace global
{
std::vector<std::string> strings;
std::vector<int> ints;
std::string a = " ";
int num = 0;
}
void doWork()
{
std::cout << "Please enter the number of integers you would like to add up: ";
std::cin >> global::num;
std::cout << "Please enter the numbers and | once you are done: ";
while (global::a != "|")
{
std::cin >> global::a;
global::strings.push_back(global::a);
}
global::strings.pop_back();
for(auto &e : global::strings)
{
global::ints.push_back(std::stoi(e));
}
}
int main()
{
doWork();
if(global::ints.size() != global::num)
{
std::cout << "Size of vector does not match the size specified. Clearing vector" << std::endl;
global::ints.clear();
global::strings.clear();
global::num = 0;
global::a = " ";
doWork();
}
}
I made a vector of char's and converted those into integers so that way you could add them up. The while loop should be checking for | rather than always running true. It then will check the size of the vector in the end, clear it if it does not match, and ask you to do it again. This is the best way that I could think of doing it.
EDIT: as VTT pointed out, char can only do one character at a time. I have converted it into a string in order to handle the conversion.
EDIT 2: reset the values of global::num and global::a to their default at the end of the failure in order to prevent crashing.

Making an if condition return if its true or while return if its true

When the condition is true or false, how can I make it return back and ask the question again, making the user re-enter the value?
Here is what I want to implement:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
int n;
cout<<"Enter numbers. Press 5 to stop: ";
cin>>n;
bool tr=true;
while(tr)
{
if(n!=5)
cout<<"You entered "<<n; //How to make it return again, since its false? I keep getting infinite loops :( ;
else
tr=false;
}
return 0;
}
You need to prompt the user in the while loop, so that it occurs in each iteration:
int n;
bool tr = true;
while(tr)
{
cout << "Enter numbers. Press 5 to stop: ";
cin >> n;
if(n!=5) {
cout << "You entered " << n;
} else {
tr = false;
}
}
Just put all your code (except 'n' and 'tr' definition) in while loop as follow:
int main()
{
int n;
bool tr=true;
while(tr)
{
cout<<"Enter numbers. Press 5 to stop: ";
cin>>n;
if(n!=5)
cout<<"You entered "<<n;
else
tr=false;
}
return 0;
}
The other answers all work, and there is something to be learned about improving program flow from them, but I believe the trick you're asking for is the continue keyword, which skips the remainder of this iteration of the loop.
bool tr = true;
int n;
while (tr)
{
cout << "Enter numbers...";
cin >> n;
if (n != 5)
continue;
else
tr = false;
}
EDIT Part 1: On the continue keyword.
You want to make your code as readable as possible. In this example, its use is unnecessary (as the other posters have shown); but it is the answer to the question "How do I skip the rest of processing in this iteration of my loop and continue to the next iteration?". Usually, such flow-breaking directives actually make code harder to read; but sometimes the opposite is true. Anything (or, at least, almost anything) that can be accomplished with continue or break, can be accomplished without them, so if you're going to use them, you want to have a definite reason for doing so. Usually, when I use continue, it's because I'm looping through a collection of inputs and I want to skip processing the loop whenever the input isn't in the format I'm expecting. Something like this (pseudo-code)...
foreach (Input i in ReceivedInputs)
{
if (i.isBad())
{
cout << "Bad input";
continue;
}
// Do massive block of calculating here.
}
is easier to read than this...
foreach (Input i in ReceivedInputs)
{
if (i.isBad())
cout << "Bad input";
else
{
// Do massive block of calculating here.
}
}
because the second version makes it harder to track what scope you're in, if you're looking toward the end of the massive block of calculating. In this case, I gain code readability by continue, so I use it. But simple code probably shouldn't use it. The break keyword is similar, though it's a lot easier to come up with examples where break is beneficial.
EDIT Part 2: On multiple iterations
This is just an issue of setting up the loop; there are no magic keywords here. The shortest way I can come up with, is probably something like this:
int n = 0;
int numberToTake = 10;
for ( int numbersTaken = 0; numbersTaken < numberToTake; ++numbersTaken)
{
cout << "Enter numbers...";
int n = 0;
for (cin >> n; n != 5; cin >> n)
cout << "Try again.";
// Do whatever processing on n you want to do here.
}
Though I should point out that, doing it this way, the only value you will ever get from the user will be 5, and if he inputs anything that doesn't fit in an integer, you will get unexpected behavior.
EDIT 3: After reading the comment more thoroughly, I think you're just looking for is the more traditional use of the for loop.
No need for the exra bool variable.
The idiom can be: Infinitely loop until the user enters 5:
for(;;) { // Loops infinitely
cout << "Enter numbers. Press 5 to stop: ";
cin >> n;
if(n == 5)
break; // Exits the loop
cout << "You entered " << n; // Before the if if you want to print 5 as well
}