Confusion on push_back interaction with pair<float,int> - c++

I have no error message instead I only have unexpected behavior.
double get_optimal_value(int capacity, vector<int> weights, vector<int> values) {
int n = weights.size();
vector<pair<double, int>> valuePerWeight(n);
pair<double,int> x;
for(int i = 0; i < n; i++){
double v = values[i]/weights[i];
x = make_pair(values[i]/weights[i], weights[i]);
valuePerWeight.push_back(x);
}
for(int i = 0; i < n && capacity > 0; i++){
int amount = min(capacity, valuePerWeight[i].second);
value += valuePerWeight[i].first * amount;
capacity -= amount;
}
double value = 0.0;
return value;
}
I am creating a vector with values of type pair<double,int>. I create the pair using make_pair(some_double, some_int), then I call push_back with the pair.
Later in the function I index into the vector and do stuff using the pairs.
However an issue arises, when I index into my valuePerWeight vector and retrieve the attributes of the different pairs. They all end up being zero regardless of index and regardless of .first or .second.
Through printing a bunch of variables I have asserted the created pair is not {0,0} but as soon as I push_back into the vector and index the pair and look at it's .first and .second attributes both are equal to 0.
I can't seem to understand why this is, originally I was using push_back seen as below
valuePerWeight.push_back(make_pair(values[i]/weights[i], weights[i]));
instead of creating into a temporary variable x . However the same issue still stands.
Any help in the right direction would be greatly appreciated.
If there is any further clarification that I can give please ask me.
If you'd like to see for some values below is a snippet which can be compiled
I use input
3 50
60 20
100 50
120 30
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
double get_optimal_value(int capacity, vector<int> weights, vector<int> values) {
double value = 0.0;
int n = weights.size();
vector<pair<double, int>> valuePerWeight(n);
pair<double,int> x;
for(int i = 0; i < n; i++){
double v = values[i]/weights[i];
cout << v << ' '<< weights[i] << '\n';
x = make_pair(values[i]/weights[i], weights[i]);
cout << x.first << ' ' << x.second << '\n';
valuePerWeight.push_back(x);
cout << valuePerWeight[i].first << ' ' << valuePerWeight[i].second << '\n';
}
for(int i = 0; i < n; i++){
cout << valuePerWeight[i].first;
cout << valuePerWeight[i].second;
cout << '\n';
}
sort(valuePerWeight.begin(), valuePerWeight.end());
for(int i = 0; i < n && capacity > 0; i++){
int amount = min(capacity, valuePerWeight[i].second);
value += valuePerWeight[i].first * amount;
capacity -= amount;
}
// for(auto vp: valuePerWeight){
// cout << vp.first << vp.second;
// cout << '\n';
// }
return value;
}
int main() {
int n;
int capacity;
std::cin >> n >> capacity;
vector<int> values(n);
vector<int> weights(n);
for (int i = 0; i < n; i++) {
std::cin >> values[i] >> weights[i];
}
double optimal_value = get_optimal_value(capacity, weights, values);
std::cout.precision(10);
std::cout << optimal_value << std::endl;
return 0;
}

The confusion here is due to the behavior of the constructor you use
vector<pair<double, int>> valuePerWeight(n);
This actually fills the vector with n default constructed pairs, which as you may surmise, are (0, 0). When you push_back, you push to the end of these, so you a totally get 2n pairs.
.reserve does something close to what you expected, not actually filling the vector, but is likely not needed for something not bottle-necking on vector resizing.
Short story, omit the (n) to just construct an empty vector.
Three more suggestions: accept the vectors as const& to save a copy, and look at emplace_back instead of making a pair yourself and pushing it. That's what it's meant for. Also, note the comment by churill - dividing two integers will result in integer division regardless of where you are assigning the result. Static cast one of them to a float or double (or multiply by 1.0 at the start) to ensure floating point division.

Related

Program in C++ that takes 3 numbers and send them to a function and then calculate the average function of these 3 numbers

Program in C++ that takes 3 numbers and send them to a function and then calculate the average function of these 3 numbers.
I know how to do that without using a function ,for example for any n numbers I have the following program:
#include<stdio.h>
int main()
{
int n, i;
float sum = 0, x;
printf("Enter number of elements: ");
scanf("%d", &n);
printf("\n\n\nEnter %d elements\n\n", n);
for(i = 0; i < n; i++)
{
scanf("%f", &x);
sum += x;
}
printf("\n\n\nAverage of the entered numbers is = %f", (sum/n));
return 0;
}
Or this one which do that using arrays:
#include <iostream>
using namespace std;
int main()
{
int n, i;
float num[100], sum=0.0, average;
cout << "Enter the numbers of data: ";
cin >> n;
while (n > 100 || n <= 0)
{
cout << "Error! number should in range of (1 to 100)." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(i = 0; i < n; ++i)
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
return 0;
}
But is it possible to use functions?if yes then how? thank you so much for helping.
As an alternative to using fundamental types to store your values C++ provides std::vector to handle numeric storage (with automatic memory management) instead of plain old arrays, and it provides many tools, like std::accumulate. Using what C++ provides can substantially reduce your function to:
double avg (std::vector<int>& i)
{
/* return sum of elements divided by the number of elements */
return std::accumulate (i.begin(), i.end(), 0) / static_cast<double>(i.size());
}
In fact a complete example can require only a dozen or so additional lines, e.g.
#include <iostream>
#include <vector>
#include <numeric>
double avg (std::vector<int>& i)
{
/* return sum of elements divided by the number of elements */
return std::accumulate (i.begin(), i.end(), 0) / static_cast<double>(i.size());
}
int main (void) {
int n; /* temporary integer */
std::vector<int> v {}; /* vector of int */
while (std::cin >> n) /* while good integer read */
v.push_back(n); /* add to vector */
std::cout << "\naverage: " << avg(v) << '\n'; /* output result */
}
Above, input is taken from stdin and it will handle as many integers as you would like to enter (or redirect from a file as input). The std::accumulate simply sums the stored integers in the vector and then to complete the average, you simply divide by the number of elements (with a cast to double to prevent integer-division).
Example Use/Output
$ ./bin/accumulate_vect
10
20
34
done
average: 21.3333
(note: you can enter any non-integer (or manual EOF) to end input of values, "done" was simply used above, but it could just as well be 'q' or "gorilla" -- any non-integer)
It is good to work both with plain-old array (because there is a lot of legacy code out there that uses them), but equally good to know that new code written can take advantage of the nice containers and numeric routines C++ now provides (and has for a decade or so).
So, I created two options for you, one use vector and that's really comfortable because you can find out the size with a function-member and the other with array
#include <iostream>
#include <vector>
float average(std::vector<int> vec)
{
float sum = 0;
for (int i = 0; i < vec.size(); ++i)
{
sum += vec[i];
}
sum /= vec.size();
return sum;
}
float average(int arr[],const int n)
{
float sum = 0;
for (int i = 0; i < n; ++i)
{
sum += arr[i];
}
sum /= n;
return sum;
}
int main() {
std::vector<int> vec = { 1,2,3,4,5,6,99};
int arr[7] = { 1,2,3,4,5,6,99 };
std::cout << average(vec) << " " << average(arr, 7);
}
This is an example meant to give you an idea about what needs to be done. You can do this the following way:
// we pass an array "a" that has N elements
double average(int a[], const int N)
{
int sum = 0;
// we go through each element and we sum them up
for(int i = 0; i < N; ++i)
{
sum+=a[i];
}
// we divide the sum by the number of elements
// but we first have to multiply the number of elements by 1.0
// in order to prevent integer division from happening
return sum/(N*1.0);
}
int main()
{
const int N = 3;
int a[N];
cin >> a[0] >> a[1] >> a[2];
cout << average(a, N) << endl;
return 0;
}
how to do that without using a function
Quite simple. Just put your code in a function, let's call it calculateAverage and return the average value from it. What should this function take as input?
The list of numbers (array of numbers)
Total numbers (n)
So let's first get the input from the user and put it into the array, you have already done it:
for(int i = 0; i < n; ++i)
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
}
Now, lets make a small function i.e., calculateAverage():
int calculateAverage(int numbers[], int total)
{
int sum = 0; // always initialize your variables
for(int i = 0; i < total; ++i)
{
sum += numbers[i];
}
const int average = sum / total; // it is constant and should never change
// so we qualify it as 'const'
//return this value
return average
}
There are a few important points to note here.
When you pass an array into a function, you will loose size information i.e, how many elements it contains or it can contain. This is because it decays into a pointer. So how do we fix this? There are a couple of ways,
pass the size information in the function, like we passed total
Use an std::vector (when you don't know how many elements the user will enter). std::vector is a dynamic array, it will grow as required. If you know the number of elements beforehand, you can use std::array
A few problems with your code:
using namespace std;
Don't do this. Instead if you want something out of std, for e.g., cout you can do:
using std::cout
using std::cin
...
or you can just write std::cout everytime.
int n, i;
float num[100], sum=0.0, average;
Always initialize your variables before you use them. If you don't know the value they should be initialized to, just default initialize using {};
int n{}, i{};
float num[100]{}, sum=0.0, average{};
It is not mandatory, but good practice to declare variables on separate lines. This makes your code more readable.

Locating a Segmentation Fault

I have the fallowing code. I read the guide for what a segmentation fault is, but I'm not 100% sure where its actually happening within my code. It works until I start working with the dynamic array (histogram), more specifically at the //set all initial values to be zero. Within that mess after I'm not sure. Thanks!
The instructor asked to "Use a dynamic array to store the histogram.", Which I think is my issue here.
-Solved-
thanks for the help, the error was in how I initialized the array pointer
rather than
const int hSize = 10;
IntArrayPtr histogram;
histogram = new int[hSize];
I used
const int hSize = 10;
int hValues[hSize] = { 0 };
IntArrayPtr histogram;
histogram = hValues;
Which worked as the instructor wanted.
#include <iostream>
#include <vector>
using namespace std;
typedef int* IntArrayPtr;
int main() {
vector<int>grades;
int newGrade;
cout << "Input grades between 0 and 100. Input -1 to calculate histogram: " << endl;
cin >> newGrade;
grades.push_back(newGrade);
while (newGrade > 0) {
cin >> newGrade;
while (newGrade > 100) {
cout << "less than 100 plz: ";
cin >> newGrade;
}
grades.push_back(newGrade);
}
grades.pop_back();
int size = grades.size();
cout << "Calculating histogram with " << size << " grades." << endl;
//Create dynamic array for the histogram of 10 sections.
const int hSize = 10;
IntArrayPtr histogram;
histogram = new int[hSize];
}
//Make the historgram
int stackValue = 0;
for (int j = 0; j < hSize; j++) {
//Loop through the grade vector slots
for (int i = 0; i < size; i++) {
int testValue = grades[i];
//If the grade at the index is between the stack values of the histogram add one to the value of the slot
if (testValue > stackValue && testValue < stackValue + 10) {
histogram[j]++;
}
}
//After looping through the vector jump up to the next histogram slot and corresponding stack value.
stackValue += 10;
}
//Histogram output. Only output the stacks with values
for (int i = 0; i < 10; i++) {
if (histogram[i] != 0) {
cout << "Number of " << (i + 1) * 10 << "'s: " << histogram[i];
}
}
return 0;
}
Working Code:
#include <iostream>
#include <vector>
using namespace std;
typedef int* IntArrayPtr;
int main() {
vector<int>grades;
int newGrade;
cout << "Input grades between 0 and 100. Input -1 to calculate histogram: " << endl;
cin >> newGrade;
grades.push_back(newGrade);
while (newGrade > 0) {
cin >> newGrade;
while (newGrade > 100) {
cout << "less than 100 plz: ";
cin >> newGrade;
}
grades.push_back(newGrade);
}
grades.pop_back();
int size = grades.size();
cout << "Calculating histogram with " << size << " grades." << endl;
//Create dynamic array for the histogram of 10 sections.
const int hSize = 10;
int hValues[hSize] = { 0 };
IntArrayPtr histogram;
histogram = hValues;
//Make the historgram
int stackValue = 0;
for (int j = 0; j < hSize; j++) {
//Loop through the grade vector slots
for (int i = 0; i < size; i++) {
int testValue = grades[i];
//If the grade at the index is between the stack values of the histogram add one to the value of the slot
if (testValue > stackValue && testValue < stackValue + 10) {
histogram[j]++;
}
}
//After looping through the vector jump up to the next histogram slot and corresponding stack value.
stackValue += 10;
}
//Histogram output. Only output the stacks with values
for (int i = 0; i < 10; i++) {
if (histogram[i] != 0) {
cout << "Number of " << (i + 1) * 10 << "'s: " << histogram[i] << endl;
}
}
return 0;
}
histogram is a pointer, not an array.
While
int histogram[hSize] = {0};
would create a zero-initialised array, your
histogram = { 0 };
does not set any elements to zero (it couldn't, because histogram points to one int, not many).
The braces are ignored – a pretty confusing behaviour inherited from C – and it is equivalent to
histogram = 0;
that is,
histogram = nullptr;
You want
int* histogram = new int[hSize]();
The parentheses value-initialises the array, and in turn its elements.
Value-initialising integers sets them to zero.
(By the way: the habit of typedeffing away asterisks causes more problems than it solves. Don't do it.)
Seg faults are problems with accessing regions of memory you don't have access to, so you need to look at your use of pointers. It often means you have a pointer with a bad value that you just dereferenced.
In this case, the problem is this line:
histogram = { 0 };
This is not setting the histogram values to zero as you think: it's resetting the historgram pointer to zero. Then you later dereference that pointer causing your SegFault (note that this line doesn't even compile with clang, so your compiler isn't helping you any on this one).
Changing that line to:
memset(histogram, 0, hSize);
Will sort the problem in this case.
More generally, to diagnose a segfault there are two tricks I use regularly (though avoidance is better than cure):
Run the program under a debugger: the debugger will likely stop the program at the point of the fault and you can see exactly where it failed
Run the program under Valgrind or similar - that will also tell you where the error surfaced but in more complex failures can also tell you where it was caused (often not the same place).

How do you add element to array/vector upon execution/compilation (c++)?

I have this code, and I've generated an array of random number twice...
Now, I just want to insert these numbers in to the vector upon execution.
I am using Microsoft Visual Studio.
This is my code:
using namespace std;
int main() {
int gRows, gCols;
std::cout << "Enter Rows: " << std::endl;
std::cin >> gRows;
std::cout << "Enter Cols: " << std::endl;
std::cin >> gCols;
std::vector<std::vector<int>> cGrid;
int numOfElem = gRows*gCols;
int* randNum = new int[numOfElem];
for (int x = 0; x < (numOfElem / 2); x++) {
srand((unsigned int)time(0));
const int fNum = rand() % 20 + 1; //generate num between 1 and 100
const int sNum = rand() % 20 + 1;
randNum[x] = fNum;
randNum[x + 2] = sNum;
}
for (int y = 0; y < numOfElem; y++) {
std::cout << randNum[y] <<std::endl;
}
//int i = 0;
for (int nRows = 0; nRows < gRows; nRows++) {// for every row and column
for (int nCols = 0; nCols < gCols; nCols++) {
cGrid[gRows][gCols] = 0;//card at that coordinate will be equal to
std::cout << cGrid[gRows][gCols];
//i = i + 1;
}
std::cout << std::endl;
}}
How do you add element to array/vector upon execution/compilation (c++)?
You cannot add elements to an array. An array never has more nor less elements than it had when it was first created.
You can add elements to a vector "upon compilation" by using a constructor. Techically the elements are still added at runtime, unless the compiler does some optimization.
During execution, you can use std::vector::push_back or one of the other member functions that std::vector has.
As a sidenote: Calling srand before every other call to rand is a great way to make sure that the numbers returned by rand are not at all random. Secondly rand() % 20 + 1 is not "between 1 and 100" as the comment suggests. Thirdly, you pointlessly overwrite elements in the loop. Fourthly, you didn't initialize all of the elements in the array pointed by randNum before using them.

Cygwin Error When Running Mastermind Program

I am trying to write a program for my programming class that successfully runs a game of mastermind with numbers 1-6 as inputs instead of colors. When I try to test the program as is I get the message
" 0 [main] Lab16 9828 cygwin_exception::open_stackdumpfile: Dumping stack trace to Lab16.exe.stackdump"
Commenting out sections of the code does not seem to help much. I am quite the noobie to all of this so any lessons learned are appreciated.
Any help/suggestions are greatly appreciated! Thank you for reading my question!
/** INCLUDE FILES ***************************************************/
#include <iostream> // input output commands: cout & cin
#include <iomanip>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;
/** FUNCTION PROTOTYPES**********************************************/
void GetPatterns(vector <int> &x); // Gets user pattern
void CreateSolution(vector <int> &y); // Creates the right pattern before user input
bool SolutionCalc(vector <int> x, vector <int> y); // Detects how many guesses are correct and or in the right place, returns bool value to main()
/** MAIN FUNCTION ***************************************************/
int main()
{
/** VARIABLE DECLARATION ****************************************/
bool solution;
vector <int> UserPattern;
vector <int> RealPattern;
srand(time(0));
/** FUNCTION CALLS***********************************************/
CreateSolution(RealPattern);
do
{
GetPatterns(UserPattern);
solution = SolutionCalc(UserPattern,RealPattern);
}while(solution == false);
cout << "Correct!" << endl;
cout << "You are a Mastermind!" << endl;
return 0;
}
/** FUNCTIONS *******************************************************/
void GetPatterns(vector <int> &x)
{
cout << "Welcome to Mastermind." << endl;
cout << endl;
cout << "Please enter your four numerical guesses(space separated, numbers 1-6): ";
for (int i = 0; i < 4; i++) // 4 size vector array for user input
{
cin >> x[i];
}
cout << endl;
}
void CreateSolution(vector <int> &y)
{
for(int e = 0; e < 4; e++) // 4 size vector array for solution
{
y[e] = rand()%6+1;
}
cout << endl;
}
bool SolutionCalc(vector <int> x, vector <int> y) // Z is the bool to check if the solution is solved or not
{
int RightNum = 0, RightPlace = 0;
bool IsSolution;
for (int i = 0; i < 4; i++)
{
if (x[i] == y[i])
{
RightPlace++;
}
if ((x[i] != y[i]))
{
if(x[i] == y[0] || x[i] == y[1] || x[i] == y[2] || x[i] == y[3])
{
RightNum++;
}
}
}
if (RightNum < 4)
{
cout << "You have " << RightNum << " correct number(s) and " << RightPlace << " correct locations(s)." << endl;
IsSolution = false;
}
else if (RightNum == 4)
{
IsSolution = true;
}
return IsSolution;
}
You're assuming that all your vectors have four elements, when you've default-initialized them. Default-initialization for vectors produces vectors with zero elements, so when you access the first through fourth elements of the vectors, you exceed the bounds of the vector.
This is a short example of what I'm talking about:
std::vector<int> myvector;
myvector[1] = 3; // oh no!
You have three options for fixing this. Either you can predefine the size of the vector:
std::vector<int> myvector(4);
myvector[1] = 3; // ok
or you can change it to the appropriate size while you're populating it:
std::vector<int> myvector; // elsewhere
myvector.resize(4);
myvector[1] = 3; // okay
or you can dynamically adjust the size of the array when you're populating it:
std::vector<int> myvector; // elsewhere
for(size_t index = 0; index < 4; ++index){
myvector.push_back(someNumber); // also okay
}
With all the syntaxes, once you've populated your vector, you can access elements the way you expect, with operator[]. Just make sure not to exceed the bounds of the vector! You can check how big a vector is with a call to size like so: myvector.size();

C++ Element access is failing to work?

this is a super simple question but I cannot seem to see what has gone wrong. What this code does is it counts the number of elements in the pixID vector and returns that sum to a diagonal element in the square matrix PtP. However even though 'i' in the first loop reads: 0,5,10,15 for the elements the output looks like this:
1,0,0,0,
0,0,3,0,
0,0,0,0,
0,3,0,0,
instead of the desired:
1,0,0,0,
0,3,0,0,
0,0,2,0,
0,0,0,2,
Any idea what is going on here?
double where(std::vector<double> &vec,unsigned int &v){
double count = 0;
int val;
for(std::vector<double>::iterator it = vec.begin();
it != vec.end();
++it){
if(*it == val){
count++;
}
}
return count;
}
int main(){
unsigned int pixSide = 2;
int id;
std::vector<double> pixID {1,1,2,3,0,2,1,3};
std::vector<double> PtP (pixSide*pixSide);
for(unsigned int i=0;i<pixSide*pixSide;i++){
id = i*pixSide*pixSide + i;
std::cout << id << std::endl;
PtP[id] = where(pixID,i);
}
for(int i=0;i<pixSide*pixSide;i++){
for(int j=0;j<pixSide*pixSide;j++){
std::cout << int(PtP[i*pixSide + j]) << ',';
if(j==pixSide*pixSide-1){
std::cout << std::endl;
}
}
}
}
First, you're not using the parameter "v" in where(). Instead, you're using the uninitialized local variable "val".
Second, I think you may be confusing the dimensions of your objects at a few points. I think you're getting confused about whether you're keeping just the diagonal or the whole matrix.
This way you will consistently be keeping the whole matrix:
std::vector<double> PtP (pixSide*pixSide);
should be
std::vector<double> PtP (pixSide*pixSide*pixSide*pixSide);
and
std::cout << int(PtP[i*pixSide + j]) << ',';
should be
std::cout << int(PtP[i*pixSide*pixSide + j]) << ',';
Of course, this is wasteful for such a sparse matrix -- I don't know whether that matters in your application (are your real numbers larger than pixSide=2?).