Vectors and Functions exercise - c++

I have a question regarding this program. I am a beginner when it comes to programming and c++, and I'm trying to figure out two things.
why is this program not compiling (error: Using uninitialized memory 'total' - I have it defined as a variable??).
Could someone explain how the function outside of the main (sumUpTo) works? Specifically & vec and total, as I've never seen them before. Thanks.
/* 1) read in numbers from user input, into vector -DONE
2) Include a prompt for user to choose to stop inputting numbers - DONE
3) ask user how many nums they want to sum from vector -
4) print the sum of the first (e.g. 3 if user chooses) elements in vector.*/
#include <iostream>
#include <string>
#include <vector>
#include <numeric> //for accumulate
int sumUpTo(const std::vector<int>& vec, const std::size_t total)
{
if (total > vec.size())
return std::accumulate(vec.begin(), vec.end(), 0);
return std::accumulate(vec.begin(), vec.begin() + total, 0);
}
int main()
{
std::vector<int> nums;
int userInput, n, total;
std::cout << "Please enter some numbers (press '|' to stop input) " << std::endl;
while (std::cin >> userInput) {
if (userInput == '|') {
break; //stops the loop if the input is |.
}
nums.push_back(userInput); //push back userInput into nums vector.
}
std::cout << "How many numbers do you want to sum from the vector (the numbers you inputted) ? " << std::endl;
std::cout << sumUpTo(nums, total);
return 0;
}

Errors in your code -
int userInput, n, total;
.
.
.
std::cout << sumUpTo(nums, total);
Here you are declaring total and directly using it as a parameter to sumUpTo function. In that function you are using it in an comparison ( if (total > vec.size()) ). But, since you have never initialized it while declaration nor have you assigned it any value anywhere in the code, the compiler doesn't know what to make of that comparison that you are making since total doesn't have any value.
could someone explain how the function outside of main (sumUpTo)
works? Specifically '& vec' and 'total'
sumUpTo has the declaration as - int sumUpTo(const std::vector<int>& vec, const std::size_t total).
Here, you are expecting the function to take a vector of integers as parameters. But you probably have doubt with & that's before vec. That symbol just specifies that you are going to pass the vector as a reference and not by making a complete copy of the vector. In our regular passing, the vector we pass to function will get passed as a copy of our origin vector. But in this case, the vector is getting passed as a reference and not a copy of the original vector.
Do note that I have used the term reference and not pointers. If you are coming from C background, you could feel both are the same and in some cases, they might function a bit similar but there are few differences(some good answers on SO - 1, 2, 3 ) between them which you can read many good resources available online. Just understand that in this case, it prevents making a copy of the vector when it is passed to the function. If the function declaration wouldn't have mentioned that parameter to be const, you could also make changes in the vector which would also reflect in the original one as well (while they wouldn't have if you passed it normally rather than as reference).
std::size_t is a type that is used to represent the size of objects in bytes. It is an unsigned datatype and used whenever you are dealing with sizes of objects. You can also refer this if you are not sure about the difference between std::size_t and int ( which is what you might have been expecting total to be).
Lastly, it's obvious that const is being used in the function to ensure that the parameters that we are passing to function aren't getting modified in the function.

Related

Passing class with array member into overload of function that uses that array member

I'm trying to implement a polynomial class consisting of an int (degree) and an integer array (the coefficients for each term). I have a function to print the polynomial, which works fine when I pass in the degree and term array directly, but things get funky when I try to put those values into an instance of my polynomial class.
I am using variadic arguments in the polynomial's constructor, such that you should be able to call polynomial(degree, ). I made sure to output each term in my va_list so I know I'm targeting what I want to.
Here's my class:
class polynomial{
public:
polynomial(int degree...){
va_list args;
_degree = degree;
int p[degree];
va_start(args,degree);
for(int i = 0; i < degree; i++){
p[i] = va_arg(args,int);
cout << p[i] << endl; //just to verify that I'm grabbing the right values.
}
va_end(args);
_terms = p;
}
int degree(){return _degree;}
int* terms(){return _terms;}
private:
int _degree;
int* _terms;
};
And here's the function(s) I'm using to print the polynomial:
void printArray(int*p, int l){
std::cout << "[";
for(int i = 0; i < l; i++){
std::cout << p[i];
if(i != l-1) std::cout << ",";
}
std::cout << "]" << std::endl;
}
void printArray(polynomial p){
printArray(p.terms(), p.degree());
}
my main function:
int main()
{
int a[3] = {2,5,3};
printArray(a,3);
polynomial p1(3,2,5,3);
printArray(p1.terms(), p1.degree());
printArray(p1);
return 0;
}
and the output:
[2,5,3]
2
5
3
[2,0,94004573]
[1,0,1]
As you can see, I call printArray() 3 times. The first time, I directly create an integer array and pass it and its length into printArray(). This time, it works fine, outputting [2,5,3] as expected. The second time, I again use the first implementation of printArray(), but this time I pass in the int* and int from an instance of my polynomial. This time, I get some array whose first two elements always seem to be 0 and 2 and whose last value is some garbage value.
The third time, I simply pass in the polynomial to the second implementation of printArray(). This seems to output [1,0,1] consistently (which is of course incorrect).
I suppose it wouldn't be too confusing if the second and third calls to printArray() generated the same garbage values, but as it stands, I am fairly lost in terms of what's happening behind the scene. Any help at all would be appreciated. Thank you!
The problem is these two lines:
int p[degree];
and
_terms = p;
The first (besides not being a non-portable variable-length array extension of your compiler) defined p to be a local variable.
The second line makes _terms point to the first element of this array.
Then the constructor ends, and the life-time of p with it, leaving you with an invalid pointer in _terms.
The natural solution is to use std::vector instead. And if you need to use pointers (because assignment/exercise requirements) you need to use dynamic allocation (using new[], and also then you need to learn about the rule of three/five).

C++ pointers and references in functions

I am coming from a C#/Java background into C++, using visual studio community 2017 & plenty of tutorials. I came to the point where am unsure of what is a correct way to write a function to process a vector of data. Should I force a function to use a pointer / reference? Should I let compiler sort it out? What is best practice?
This is my main, I ask for an input on vector size, then pass a pointer to the integer value to function that creates and populates vector with values through a simple for loop.
I then pass the array to another function that performs a shuffle.
vector<int> intVector(int* count)
{
vector<int> vi;
for (int i = 1; i <= *count; i++)
vi.push_back(i);
return vi;
}
vector<int> &randVector(vector<int> *v)
{
shuffle(v->begin(), v->end(), default_random_engine());
return *v;
}
int _tmain(int argc, _TCHAR* argv[])
{
int count;
cout << "Enter vector array size: ";
cin >> count; cout << endl;
cout << "Vector of integers: " << endl;
vector<int> vi = intVector(&count);
for_each(vi.begin(), vi.end(), [](int i) {cout << i << " ";});
cout << endl;
vi = randVector(&vi);
cout << "Randomized vector of integers: " << endl;
for_each(vi.begin(), vi.end(), [](int i) {cout << i << " ";});
cout << endl;
return 0;
}
So my question is, what is the best practice in my case to avoid unnecessary copying. Should I even care about it? Should I rely on compiler to solve it for me?
I am planing to use C++ for game development on desktop and consoles. Understanding memory and performance management is important for me.
You are in charge of enforcing (or avoiding) the copy of objects around.
Regarding your example:
You can avoid using pointers and use a reference instead.
Like in the following:
vector<int>& randVector(vector<int>& v)
{
shuffle(v->begin(), v->end(), default_random_engine());
return v;
}
Note that since you are using a reference, the shuffle operation is already modifying the parameter of randVector so there is no real need to return a reference to it.
As a rule of thumb when you need to pass an object around and you want to avoid a potentially expensive copy you can use references:
void function(<const> Object& v)
{
// do_something_with_v
}
The rules on passing in C++ for typical code are pretty straightforward (though obviously still more complex than languages without references/pointers).
In general, prefer references to pointers, unless passing in null is actually something you might do
Prefer to write functions that don't mutate their inputs, and return an output by value
Inputs should be passed by const reference, unless it is a primitive type like an integer, which should be passed by value
If you need to mutate data in place, pass it by non-const reference
See https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-conventional for more details.
The upshot of this is that here are the "correct" signatures for your two functions:
vector<int> intVector(int count);
void randVector(vector<int> &v);
This doesn't take into account iterators which is probably really the correct "generic" way to write the second function but that is a bit more advanced. But, see std::shuffle which lets you randomize any arbitrary container by leveraging iterators: http://en.cppreference.com/w/cpp/algorithm/random_shuffle.
Since you mentioned unnecessary copying, I will mention that when you return things like vector by value, they should never be copied (I'm assuming you're using C++11 or newer). They will instead be "moved", which doesn't have significant overhead. Thus, in newer C++ code, "out parameters" (passing in arguments by reference to mutate them) is significantly discouraged compared to older versions. Good to know in case you encounter dated advice. However, passing in by reference for something like shuffling or sorting is considered an "in/out" parameter: you want to mutate it in place and the existing data is important, not simply being overwritten.

Passing vector by value

I want to create a program that uses a vector to sort it for testing reasons. So I want to calculate the CPU time by a benchmark that sorts the vector a certain amount of times. So the original vector needs to remain constant, and then use another vector so that it can be sorted.
So what I have done is...
#include <iostream>
#include <vector>
#include <random>
#include <chrono>
using namespace std;
typedef vector<int> intv;
int main(){
intv vi;
// Stuff to create my vector with certain characteristics...
intv vii=vi;
cout << "Size: \n";
cin >> tt ;
for(i=0; i<tt; ++i){
tb=sort(t,vii);
m=m+tb;
vii=vi;
}
m=m/tt;
cout << "BS" << m << "\n";
}
So I pass the vector by reference, and make a copy for each sorting so that I can sort it again. How can I do this a better way? Is it better to pass it by value, and in that case, Could someone provide me a minimum example of the best way to do this?
sort is a basic bubble sorting function:
double sort(int t, intv &vii){
vii.reserve(t);
bool swapped=true;
int a;
auto t0 =chrono::high_resolution_clock::now();
while (swapped==true){
for (int i=1; i<t; ++i){
swapped=false;
if (vii[i-1]>vii[i]){
a=vii[i];
vii[i]=vii[i-1];
vii[i-1]=a;
swapped=true;
}
}
t=t-1;
}
auto t1 = chrono::high_resolution_clock::now();
double T = chrono::duration_cast<chrono::nanoseconds>(t1-t0).count();
return T;
}
Once you have sorted, you have to do something that is equivalent to:
vii=vi;
I think assigning vi to vii will be the most efficient method of copying the contents of vi to vii. You can try:
size_t index = 0;
for ( auto const& val : vi )
{
vii[index++] = val;
}
However, I will be really surprised if the second method is more efficient than the first.
Nothing wrong with sorting in-place, and making a copy of the vector. The code you have should work, though it is not clear from where your parameter t is coming.
Note that the statement vii.reserve(t) is not doing anything useful in your sort routine: either t is less than or equal to the size of vii, in which case the reserve call does nothing, or it is greater than the size of vii, in which case you are accessing values outside the range of the vector. Better to check t against the vector size and throw an error or similar if it is too big.
Passing by value is straightforward: just declare your sort routine as double sort(int t, intv vii). When the function is called, vii will be copied from whichever vector you pass in as the second argument.
From a design point of view though, it is better to make a copy and then pass a reference. Sorting should change the thing being sorted; passing by value in the context of your code would mean that nothing would be able to inspect the sorted result.

C++ Calling Vectors from Function to Main

I'm trying read a large amount of values into a vector in a specific function and then calling it into the main to get the average. My readInput works perfectly. But I believe
my main function returns 0 when I cout << values.size();. Why is this? What can I do to change that?
using namespace std;
//function prototype
int readInput(vector<int> vect);
int main()
{
vector<int> values;
int sum, avg;
sum = readInput(values);
//cout << sum;
avg = sum / values.size();
cout << avg;
return 0;
}
int readInput(vector<int> vect)
{
int count;
int total = 0;
ifstream inputFile("TopicFin.txt"); //open file
if(!inputFile)
{
return 0; // if file is not found, return 0
}
while(inputFile >> count) //read file
vect.push_back(count); //add to file
for (int count = 0; count < vect.size(); count++)
total+=vect[count]; //sum data in vector
return total;
}
You are not passing your vector by reference, so your function only stores the values in a copy of your vector from main.
int readInput(vector<int>& vect);
this tells your program to pass the the vector by reference meaning anything modified in the function directly modifies your vector in main. If you're new to this stuff check out this post explaining the difference between reference and copy.
You need to pass the vector as a reference or as a pointer. The function just creates a copy of the vector currently passed by value, and manipulates that.
Change the function signature to . . .
int readInput(vector<int>& vect)
Or (perhaps more weirdly for this example) . ..
int readInput(vector<int> *vect)
also changing the function call to
sum = readInput(&values);
Although others have already mentioned the possibility of passing the vector by reference, that is not what I think I'd do in this case. I think I'd just return the vector from the function. I'd also pass the file name to the function:
std::vector<int> values = readInput("TopicFin.txt");
At least to me, this seems to reflect the intent far better. Maybe I'm just a little slow, but it doesn't seem at all obvious from the name that the return value from readInput would be the sum of the values it read.
While returning a vector could theoretically cause an efficiency problem with a compiler that supported neither move construction nor return value optimization, any such compiler is pretty much guaranteed to be so ancient that you really want to avoid it for other reasons anyway.
As far as reading the data into the vector goes, I'd use a pair of istream_iterators:
std::vector<int> data{std::istream_iterator<int>(infile),
std::istream_iterator<int>()};
Of course, given how simple this is, I'd tend to wonder whether it's worth having a separate function like readInput at all.
To sum the values, I'd use std::accumulate:
int total = std::accumulate(data.begin(), data.end(), 0);

Compare two static arrays

I have an issue how to implement to compare two static arrays, ie.
string bufferNames[]={"apple","orange","banana","pomegranate","pear"};
string bufferPictures[] = {"apple.bmp","orange.bmp","banana.bmp","pomegranate.bmp","pear.bmp"};
Each item in the bufferNames presents the choice that to someone has been given, when the picture from the bufferPictures has been loaded onto the screen. So, if I for example get orange.bmp using rand() function that iterates through that list, how can I get the same one corresponding element orange and two other random not correct elements. Any help would be appreciated.
Thanks in advance.
P.S. If further breaking in of the problem is needed, just say it so.
This should do it. The code makes use of the C++11 features. You will
need to adapt it, to pass it off as homework.
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
struct Picture {
std::string name, file;
bool operator==(const Picture& x) const { return this->name == x.name && this->file == x.file; }
bool operator!=(const Picture& x) const { return !(*this == x); }
};
int main()
{
std::vector< Picture > pics =
{
{"apple", "apple.bmp"},
{"orange", "orange.bmp"},
{"banana", "banana.bmp"},
{"pear", "pear.bmp"},
};
// determined by random choice
const Picture& choice = pics[0];
std::vector< Picture > woChoice;
std::copy_if(pics.begin(), pics.end(), std::back_inserter(woChoice),
[&choice](const Picture& x) {
return x != choice;
});
// random shuffle the remainder and pick the first
// two. alternatively and for more efficience use std::random to
// generate indices
std::random_shuffle(woChoice.begin(), woChoice.end());
std::cout << woChoice[0].name << std::endl;
std::cout << woChoice[1].name << std::endl;
return 0;
}
So, if I for example get orange.bmp using rand() function that iterates through that list, how can I get the same one corresponding element orange and two other random not correct elements.
If you use rand() to get a number (let's call it x) between 0 and 4 inclusive (based on there being 5 distinct values in the arrays), then you can use that number in both arrays to find the related word and image.
To get one other random incorrect element, you can call rand() in a loop until you get a value other than x. Let's call it y.
To get another random incorrect elements, you can call rand() in a loop until you get a value other than x and y.
There are other ways to do this, but that's probably easiest to understand and implement.
The names in arrays correspond to each other. So, if you need fruit
number i, take bufferNames[i] and bufferPictures[i] in parallel way.
Ensure that names ARE parallel. Simply making the second array
elements from the first array elements.
As for random in range 0..n-1 excluding elements number i,j (j>i), count it so:
temp=random(n-3);
k=(temp>=i?temp+1:temp);
k=(k>=j?k+1:k);
And again, take bufferNames[k] and bufferPictures[k].
It is not simple, it is VERY simple.