I'm new to programming (in general) and C++ (in particular). I'm learning vectors and am trying to write a simple program that:
allows the user to enter a vector of students' test scores
when the user types the sentinel (-1 in this case), the vector terminates
outputs a tally of the student's grades
Here's my code:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
const int SENTINEL = -1;
vector<int> studentGrades = { 0 };
int myInput;
int main()
{
do
{
cout << "Please enter a student's grade: ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades[myInput]++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades[i] << endl;
return 0;
}
Two questions:
1) Can anyone provide guidance on why this code is only allowing me to enter one student's grade?
2) Is the for loop that compute the "tally" correct?
Thanks in advance for taking a look,
Ryan
* REVISED CODE *
# JCx - this is the revised code:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
const int SENTINEL = -1;
vector<int> studentGrades = { 0 };
int myInput;
int main()
{
do
{
cout << "Please enter a student's grade (or -1 to QUIT): ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades.at(myInput)++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades.at(myInput) << endl;
return 0;
}
and, I'm seeing this error:
Unhandled exception at 0x7707C42D
Microsoft C++ exception: std::out_of_range at memory location 0x0035F890
There's more than one problem. The attempt to access studentGrades[-1] when the users enters your sentinel value, and the fact that the default vector only contains an entry for 0 and the use of push_back.
Let's just walk through some of the problems:
User runs program. User enters 100. studentGrades[100] is out of range. Undefined behaviour occurs as the vector only has one element.
User runs program, enters -1 studentGrades[-1] is out of range.
User runs program, enters 0. studentGrades[0] is in range, incremented to 1. studentGrades.push_back(1) adds an element to the vector studentGrades[1] is now also equal to 1.
As a great starting point, if you swap your subscript vector references for the vector at method as I've shown below you will get out-of-range errors which will help (a lot). The code below still needs work but at least you'll have run-time errors instead of odd behaviour.
int main()
{
do
{
cout << "Please enter a student's grade: ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades.at(myInput)++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades.at(myInput) << endl;
return 0;
}
I think if I was implementing this I'd be using std::map instead of a vector. It would let you have a studentGrade[1000] without having to allocate memory for studentGrade[0] to [999] first.
However as you are learning about std::vector check out vector::resize to set the vector big enough for the required elements, std::vector::size to find out whether you need to increase the size. You could then ditch the push_back.
References
vector::at http://www.cplusplus.com/reference/vector/vector/at/
vector::size http://www.cplusplus.com/reference/vector/vector/size/
Related
I was practicing with vector, I wanted to push an element using push_back(); using a for loop, but the program doesn't even enter the for loop, help!!!
#include <iostream>
#include <vector>
using namespace std;
int main()
{
cout << "check ";
int val;
vector<char> vec;
cout << "check " << endl << "Its in the game";
//those two "check" were to confirm if the program is even running and is it a
problem while declaring the vector
for(int i = 0; i < vec.size(); i++){
cout << "enter element for vector" << endl;
cin >> val;
vec.push_back(val);
}
}
Your vector is empty. The for loop starts at zero, which is not less than zero, so the for loop never runs.
Your vector is literally empty, which means vec.size() is 0.So It will never enter the loop. If you know what your vector size is gonna be, you should define it as
std::vector<int> vec(vec_size);
for(int i=0;i<vec_size;++i)
{
//whatever.....
}
Or you could have used a while loop.
while(std::cin>>val)
{
//do your thing....
}
I am very new to c++ and currently trying to complete a few little challenges to get up to speed with the simpler aspects.
I'm trying to create an array (found info to suggest vectors are the same and better) of structs to hold data about 10 people. Each person has an "index" (to identify person1, person2, person3, etc..), a "num" (to store the collected data) and a "rank" (a variable which I intend to use to sort the people using the data collected)
The code doesn't show any errors before compiling, however, when the first piece of data is entered I get the following message:
"Debug Assertion Failed!
Program: C:\WINDOWS\SYSTEM32\MSVCP140D.dll
File: d:\program files\microsoft visual studio\community\vc\tools\msvc\14.12.25827\include\vector
Line: 1795
Expression: vector subscript out of range"
I have tried searching through multiple threads but I can't seem to work out why this problem is occurring.
My code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct person
{
int index; /*person number*/
int num; /*number of pancakes eaten*/
int rank; /*rank used for sorting people*/
};
vector<person> people; /*create a vector (array) of "person"'s*/
void getData()
{
cout << "You will be asked to enter data from 10 different people" << endl;
cout << "\n" << "The question is; 'How many pancakes did they eat for breakfast?'" << endl;
cin.get();
for (int i = 1; i <= 10; i++)
{
system("CLS");
int j;
cout << "Person " << i << " : ";
cin >> j;
person temp;
people.push_back(temp);
people[i].index = i;
people[i].num = j;
people[i].rank = i;
}
}
int main()
{
getData(); /*collect data for the people*/
system("CLS");
cout << "Data Collected : " << endl;
system("pause");
}
Thanks in advance for anyone who can help.
The problem is in your indexing. The index starts at 0 and not 1. So what happens is when you push the first element, it is stored at people[0]. Then you try to access people[1], since i = 1. Hence the subscript is out of range error.
You need to modify the code to be:
....
for (int i = 0; i < 10; i++)
{
system("CLS");
int j;
cout << "Person " << i << " : ";
cin >> j;
person temp;
people.push_back(temp);
people[i].index = i;
people[i].num = j;
people[i].rank = i;
}
....
Below is my code so far. I am just doing this step by step, for a class assignment. Trying not to give the whole code I just want to know what is wrong with what I have so I can learn to fix it. Thanks for the help.
The goal is to create class driver then to get total lap times, compare them and put them in order of 1st thru 3rd place. I've made this in a simple program already. Now I am trying to make an array of the class driver.
So far this is working, It asks for input correctly, and gives an output but before the end of the program I get:
Debug Error!
Run Time Check Failure #2 - Stack around the variable 'driver' was corrupted.
None of the answers I've found here make sense to my application. I have 0 failures when I run the build before running the program.
I also know not to use single character variables, I just do this as I learn what I'm missing and later change them.
#include <iostream>
#include <string>
using namespace std;
class Driver
{
int carNumber;
public:
void setNumber(int number)
{
carNumber = number;
}
int getNumber()
{
return carNumber;
}
};
int main()
{
int x;
int i;
Driver driver[3];
for (i = 1; i <= 3; i++)
{
cout << "Enter Driver " << i << "'s car number: ";
cin >> x;
driver[i].setNumber(x);
}
for (i = 1; i <= 3; i++)
cout << "driver " << i << "'s number is " << driver[i].getNumber() << endl;
return 0;
}
start for loop as shown below because as we know that array stores n elements from location 0 to n-1.
for (i = 0; i <3; i++)
{
cout << "Enter Driver " << i << "'s car number: ";
cin >> x;
driver[i].setNumber(x);
}
Your array access indexes are wrong.
Arrays start at index 0, not 1, and end at 1 less than the number of elements. So for a declaration of driver[3], the valid indexes are 0, 1, and 2, not 1, 2 and 3. With the wrong indexes, you're writing past the end of the array, causing the stack corruption.
Your write loop should be more like
for (i = 0; i < 3; i++)
{
cout << "Enter Driver " << i << "'s car number: ";
cin >> x;
driver[i].setNumber(x);
}
You'll need to make a similar fix to the read loop.
for(int i=0;i<50;i++,size++)
{
cin >> inputnum[i];
cout << size;
if(inputnum[i] == '.')
{
break;
}
}
The break breaks the input stream but the size keeps outputting.
The output of size is 012345678910111213...474849.
I tried putting size++ inside the loop but it made no difference. And size afterwards will be equal to 50, which means it went through the full loop.
I forgot to explain that I added the cout << size within the loop to debug/check why it outputted to 50 after the loop even if I only inputted 3 numbers.
I suspect that inputnum is an array of int (or some other numeric type). When you try to input '.', nothing actually goes into inputnum[i] - the cin >> inputnum[i] expression actually fails and puts cin into a failed state.
So, inputnum[i] is not changed when inputting a '.' character, and the break never gets executed.
Here's an slightly modified version of your code in a small, complete program that demonstrates using !cin.good() to break out of the input loop:
#include <iostream>
#include <ostream>
using namespace std;
int main()
{
int inputnum[50];
int size = 0;
for(int i=0;i<50;i++,size++)
{
cin >> inputnum[i];
if (!cin.good()) {
break;
}
}
cout << "size is " << size << endl;
cout << "And the results are:" << endl;
for (int i = 0; i < size; ++i) {
cout << "inputnum[" << i << "] == " << inputnum[i] << endl;
}
return 0;
}
This program will collect input into the inputnum[] array until it hits EOF or an invalid input.
What is inputnum ? Make sure t's a char[]!! with clang++ this compiles and works perfectly:
#include <iostream>
int main() {
int size = 0;
char inputnum[60];
for(int i=0;i<50;i++,size++) {
std::cin >> inputnum[i];
std::cout << size;
if(inputnum[i] == '.') {
break;
}
}
return 0;
}
(in my case with the following output:)
a
0a
1s
2d
3f
4g
5.
6Argento:Desktop marinos$
Your code seams OK as long as you're testing char against char in your loop and not something else.. Could it be that inputnum is some integral value ? if so, then your test clause will always evaluate to false unless inputnum matches the numerical value '.' is implicitly casted to..
EDIT
Apparently you are indeed trying to put char in a int[]. Try the following:
#include <iostream>
int main() {
using namespace std;
int size = 0;
int inputnum[50];
char inputchar[50];
for(int i=0;i<50;i++,size++) {
cin >> inputchar[i];
inputnum[i] = static_cast<int>(inputchar[i]); // or inputnum[i] = (int)inputchar[i];
cout << size << endl; // add a new line in the end
if(inputchar[i] == '.') break;
}
return 0;
}
Then again this is probably a lab assignment, in a real program I'd never code like this. Tat would depend on the requirements but I'd rather prefer using STL containers and algorithms or stringstreams. And if forced to work at a lower-level C-style, I'd try to figure out to what number '.' translates to (simply by int a = '.'; cout << a;`) and put that number directly in the test clause. Such code however might be simple but is also BAD in my opinion, it's unsafe, implementation specific and not really C++.
I present to you all a program I'm working on for my college programming course. I still have a little ways to go before it completely meets my assignment's requirements, but I've gotten a basic draft of the program error-free (supposedly) and it appears to run… but then it suddenly kicks me into Xcode's debugger and gives me:
Thread 1: EXC_BAD_ACCESS(code=2, address=0x7fff95c1e5f5)
Here's the command line output, up until it kicks me out:
-----------------------
Quarterly_sales_taxator
-----------------------
How many company divisions will we be dealing with? 2
Am I correct in assuming that there are 4 sales quarters? yes
Please enter the sales Company Division #1 brought in for Sales Quarter #1 20
(lldb)
Here's my code:
//
// quarterly_sales_taxator.cpp
// Ch. 7 program #7
//
// Created by John Doe on 11/27/12.
//
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cctype>
using namespace std;
void read_company_divisions_and_sales_quarters(double **, int, int);
//void write_company_divisions_and_sales_quarters_to_array(double **, int, int); // This will be used later on to read data from a file.
void display_quarterly_sales_array(double **, int, int);
string temp; // A global temporary placeholder variable; I use this several times.
int main()
{
int COMPANY_DIVISIONS,
SALES_QUARTERS = 4;
double **quarterly_sales_form;
cout << "\n\n-----------------------\nQuarterly_sales_taxator\n-----------------------\n\n";
cout << "\nHow many company divisions will we be dealing with? ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
while (COMPANY_DIVISIONS < 1 || isdigit(COMPANY_DIVISIONS == false))
{
cout << "\n\n------"
<< "\nError:"
<< "\n------"
<< "\n\nYou have entered an invalid choice."
<< "\nPlease type a number greater than zero. ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
}
cout << "\n\nAm I correct in assuming that there are 4 sales quarters? ";
getline(cin, temp);
// Convert to uppercase.
for (int count = 0; count < temp.length(); count ++)
{
temp[count] = toupper(temp[count]);
}
if (temp == "NO" || temp == "NOPE" || temp == "INCORRECT" || temp == "YOU ARE NOT" || temp == "YOU ARE INCORRECT" || temp == "NEGATIVE" || temp == "NEGATORY")
{
cout << "\nOk, then how many sales quarters are we dealing with? ";
getline(cin, temp);
stringstream(temp)>>SALES_QUARTERS;
}
cout << endl << endl;
// This sets up the 2d array.
quarterly_sales_form = new double *[COMPANY_DIVISIONS];
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
read_company_divisions_and_sales_quarters(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// write_company_divisions_and_sales_quarters_to_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS); // I'll add this feature later.
cout << "\n\nHere's what you entered:\n\n";
display_quarterly_sales_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// Since we used a series of pointers, we need to free the allocated space back up.
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ delete[] quarterly_sales_form[COMPANY_DIVISIONS]; }
delete[] quarterly_sales_form;
return 0;
}
/*############################################
# read_company_divisions_and_sales_quarters #
############################################*/
void read_company_divisions_and_sales_quarters(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < QUARTERS; count++)
{
for (int index = 0; index < DIVISIONS; index++)
{
cout << "\nPlease enter the sales Company Division #" << count+1 << " brought in for Sales Quarter #" << index+1 << " ";
getline(cin, temp);
stringstream(temp) >> array[count][index];
}
}
}
/*################################
# display_quarterly_sales_array #
#################################*/
void display_quarterly_sales_array(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < DIVISIONS; count++)
{
cout << "\nCompany division #" << count+1 << ":\n";
for (int index = 0; index < QUARTERS; index++)
{ cout << array[count][index] << ", "; }
}
}
Can some kind soul please tell me what I'm doing wrong?
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
In this line, COMPANY_DIVISIONS should be count.
In addition to what Dan Hulme said, it seems this line
stringstream(temp) >> array[count][index];
should really be
std::istringstream(temp) >> std::skipws >> array[index][count];
In addition to using std::istringstream rather than std::stringstream and making sure that an lvalue is at hand, which isn't strictly needed until the type read becomes more interesting, this also reverses the indices: index runs over COMPANY_DIVISIONS and count over SALES_QUARTERS.
The real question is, of course: Who hands out assignments like this? Pointer manipulations and allocations are best left to low-level library writers. This is C++ not C: we can and should use abstractions. Getting this code exception safe is a major challenge and there is no point in teaching people how to write broken (e.g. exception unsafe) code.