How should I pass this std::array<> to a function? - c++

std::array<LINE,10> currentPaths=PossibleStrtPaths();
LINE s=shortestLine(currentPaths); //ERROR
LINE CShortestPathFinderView::shortestLine(std::array<LINE,10> *currentPaths)
{
std::array<LINE,10>::iterator iter;
LINE s=*(currentPaths+1); //ERROR
for(iter=currentPaths->begin()+1;iter<=currentPaths->end();iter++)
{
if(s.cost>iter->cost)
s=*iter;
}
std::remove(currentPaths->begin(),currentPaths->end(),s);
//now s contains the shortest partial path
return s;
}
At both those statements I'm getting the same error: no suitable conversion from std::array<LINE,10U>*currentPaths to LINE . Why is this so? Should I pass the array another way? I've also tried passing currentPaths as a reference, but it tells me that a reference of the type cannot be initialized.

You said you tried a reference and it failed. I don't know why, because that was the correct thing to do.
LINE CShortestPathFinderView::shortestLine(std::array<LINE,10> &currentPaths);
From the sounds of it, you also used a reference for the temporary variable. That's wrong.
std::array<LINE,10>& currentPaths = PossibleStrtPaths(); // WRONG
std::array<LINE,10> currentPaths = PossibleStrtPaths(); // RIGHT
LINE s = shortestLine(currentPaths);
And finally, the first element is number zero. The subscripting operator [] is preferred when you are doing array access. So:
LINE s = currentPaths[0];
But you also can easily get the first item from the iterator.
Final code:
/* precondition: currentPaths is not empty */
LINE CShortestPathFinderView::shortestLine(std::array<LINE,10>& currentPaths)
{
std::array<LINE,10>::iterator iter = currentPaths.begin();
LINE s = *(iter++);
for(; iter != currentPaths->end(); ++iter) {
if(s.cost>iter->cost)
s=*iter;
}
std::remove(currentPaths.begin(), currentPaths.end(), s);
//now s contains the shortest partial path
return s;
}

You are dereferencing (currentPaths+1) which is of type std::array* (more precisely: you are incrementing the pointer and then accessing its pointed data) while you probably want to retrieve the first element of currentPaths, that is: currentPaths[0] (the first index in an array is 0).

Related

Access an element of a vector given the vector's pointer

I am trying to create a sorting function with the parameters being a pointer of a list and I am trying to access an element of the given list. Hopefully this code speaks for the problem better than I can:
void bubbleSort(std::vector<int> *L) {
unsigned int i = 0; int temp;
while(isSorted(*L)) {
if(i==L->size()-1) {
i = 0;
}
if(i<L[i]/*<-ERROR here.*/) {
temp = L[i+1]; // ERROR HERE
L[i+1] = L[i]; // ERROR HERE
L[i] = temp; // ERROR HERE
}
}
}
You don't need to painfully dereference every individual use of L (and indeed doing so is error-prone, as you've demonstrated by missing one in your answer).
Instead, just write:
void bubbleSort(std::vector<int> *Lptr) {
auto &L = *Lptr;
and keep the rest of the code the same.
NB. It would be even better to change the function itself, to
void bubbleSort(std::vector<int> &L) {
as it should have been written in the first place, but I'm assuming there's some artificial reason you can't do that.
The function accepts a pointer to an object of type std::vector<int>.
void bubbleSort(std::vector<int> *L) {
To access the original vector using the pointer, you can write either *L or L[0]. That is, both expressions yield an lvalue reference of type std::vector<int> & to the vector.
To get the i-th element of the vector using the subscript operator through the pointer, you can write either (*L)[i] or L[0][i],
However, in this if statement:
if(i<L[i]/*<-ERROR here.*/) {
You are trying to compare the variable i of type unsigned int to the object L[i] of type std::vector<int>. When i is not equal to 0, this yields a non-existent object of the vector type.
It seems you mean something like the following instead:
if ( (*L)[i] < (*L)[i+1] ) {
or:
if ( L[0][i] < L[0][i+1] ) {
or, vice versa:
if ( L[0][i+1] < L[0][i] ) {
Depending on whether the vector is sorted in ascending or descending order.
Pay attention to the fact that there is no sense in declaring the parameter as a pointer to a std::vector<int>. The function would be much clearer and readable if it accepted the vector by reference instead:
void bubbleSort(std::vector<int> &L) {
In this case, the if statement would look like this:
if ( L[i] < L[i+1] ) {
Although I prefer to change the source code as other answer. But, for this question, you can use ->at() function to access the element in a vector pointer.
if(i<L->at(i)) {
temp = L->at(i+1);
L->at(i+1) = L->at(i);
L->at(i) = temp;
}

Why cant you push_back in 2D vector? c++

I am learning recursion in c++ and was stuck on why you cant simply use the .push_back() instead of creating a function to copy the specific_previous_result elements, then .push_back().
vector<vector<int>> get_every_n_elements(vector<int> arr, int n) {
if (n == 0) {
vector<vector<int>> result;
vector<int> empty_list;
result.push_back(empty_list);
return result;
}
vector<vector<int>> previous_result = get_every_n_elements(arr, n - 1);
vector<vector<int>> current_result; //empty
for (auto specific_previous_result : previous_result) { // [[]] -> []
for (auto elem : arr) { // [1,2,3,4] -> 1
//current_result.push_back(specific_previous_result.push_back(elem));
//This does not work^^
current_result.push_back(group(specific_previous_result, elem));
//The group function copies all elements to newVec and push_back(elem) after
//Then returns newVec with elem at the end
}
}
return current_result;
}
The error that I get when I run the push_back line is error: invalid use of void expression current_result.push_back(specific_previous_result.push_back(elem));. Thank you for your help.
There doesn't seem to be a valid reason to return the vector itself after a push_back. Sometimes it's useful, but most of the time, it is not. I would recommend writing it in two lines, which is also more clearer IMO than a separate (and inefficient!) function:
current_result.push_back(specific_previous_result);
current_result.back().push_back(elem);
The reason why that line is causing the compiler to give you the invalid use of void expression current_result.push_back(specific_previous_result.push_back(elem)); error is trivial. Take a look at the line in question:
current_result.push_back(specific_previous_result.push_back(elem));
The bolded part is calling the vector's push_back function, a function which has a void return type. You are attempting to pass this void return value as a parameter to current_result.push_back.
See the documentation for std::vector::push_back. As you can see, the return value for both overloads is void.
You said it yourself, your group function is returning a vector which you are then pushing onto the back of your current_result vector. This is why the line which uses the group function compiles.

Using C++11's begin() and end() function to determine array dimension by parameter

So I am currently learning C++ (with previous experience in Java and JavaScript) and as far as I am concerned you can't pass an array as argument in C++ like you can in Java. But you can pass a pointer to the first element in the array. So I could iterate through an array like this:
bool occurs(int* arrInt, int length, int sought, int& occurrences)
{
for (int i = 0; i <= length; ++i)
{
if (arrInt[i] == sought)
occurrences++;
}
// if occurences > 0 return true, else false
return occurrences;
}
The whole function should basically return a boolean telling me wether the given int (sought) was found in the array (arrInt) or not. Also I am supplying a little counter via reference (occurrences).
But what bugs me is the length parameter. C++11 provides those fancy std::begin / cbegin() and std::end / cend() functions to get the first and one past the last element of an array:
int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
// function parameter of ocurs(int*,int,int,int&)
auto end = std::end(arr); // end points to one past last element
But why can't I use my arrInt parameter as argument for that function? Then i could get rid of the length parameter:
bool occurs(int* arrInt, int sought, int& occurences)
{
for (auto it = std::begin(arrInt); it != std::end(arrInt); ++it)
{
if (*it == sought)
occurences++;
}
// if occurences > 0 return true, else false
return occurences;
}
Am I missing a major concept here? Thanks in advance
In your first example:
int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
// function parameter of ocurs(int*,int,int,int&)
auto end = std::end(arr); // end points to one past last element
arr is NOT "basically a pointer to an int". arr is of type int[4]. Note that the length is part of the type. As a result, the compiler can easily determine where "one past last element" is. Just add the length.
Where the confusion may come in is that arr is convertible to (you'll sometimes hear decays to) int*. But it isn't just a pointer.
In your second example:
bool occurs(int* arrInt, int sought, int& occurences)
{
for (auto it = std::begin(arrInt); it != std::end(arrInt); ++it) {
...
}
...
}
arrInt is just a pointer. As such, how can you know where end() is? There's no information here. That's why you need that extra length parameter.
You can instead pass in the full array, but you have to do it by reference (you cannot pass arrays by value, thanks C!). And to do that, you have to make it a function template:
template <size_t N>
bool occurs (int (&arrInt)[N], int sought, int& occurrences) {
...
}
Here, arrInt is an array - and its length is encoded in the type (N). So you can write std::end(arrInt).
occurs() is basically rewriting std::count, so you could just use that instead:
int arr[] = {1, 2, 3, 3, 8};
int occurrences = std::count(std::begin(arr), std::end(arr), 3); // yields 2
Or, even simpler, use std::vector<int>.
First, note that an array is not a pointer. And so in this example code:
int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
// function parameter of ocurs(int*,int,int,int&)
… the comments are simply wrong.
However, in both C and C++ an array type expression decays to pointer type, with pointer to first item as result, in a context where a pointer is expected. An example that is not such context, is where an array is passed by reference. Another example is when it's used as argument to sizeof.
With arrInt declared as
int* arrInt
it's just a pointer, with no information about whether it points to a single int or to somewhere in an array, and so
std::end(arrInt)
can't deduce an array size. Normally it deduces that from the array type of the argument. Or from a container's size or end member (how it's implemented is unspecified, and the same info is available several ways).
One possibility is to change your function design, e.g. change it to accept two pointers (or general iterators), like std::find.
Another possibility is to use std::find in your function.
You can do that because given a start pointer and an array size, you can trivially compute the past-the-end pointer for the array, to use as argument to std::find.

std::vector does strange thing

(Sorry if my sentances are full of mystakes, I'll do my best to write something readable) Hi, I'm working on a function that reads a file and store every line whose first char is ":" and removes every dash contained in the string. Every time this kind of line is found, push_back() is used to store this line in a vector. The problem is that, every time push_back() is used, all the elements in the vector takes the value of the last one. I don't understand why does it happen. Here's the code :
string listContent;
size_t dashPos;
vector<char*>cTagsList;
while(!SFHlist.eof())
{
getline(SFHlist,listContent);
if(listContent[0]==':')
{
listContent.erase(0,1);
dashPos = listContent.rfind("-",string::npos);
while(dashPos!=string::npos)
{
listContent.pop_back();
dashPos = listContent.rfind("-",string::npos);
}
char* c_listContent = (char*)listContent.c_str();
cTagsList.push_back(c_listContent);
}
}
I first thought it was a problem with the end of the file but aborting the searching process before reaching this point gives the same results.
the c_str()-method of std::string states:
The pointer returned may be invalidated by further calls to other member functions that modify the object.
If you're allowed to use a std::vector< std::string > instead of the vector of char*, you're fine since there would be always a copy of the std::string listContent pushed into the vector, ie.
std::string listContent;
size_t dashPos;
std::vector<std::string>cTagsList;
while(!SFHlist.eof())
{
getline(SFHlist,listContent);
if(listContent[0]==':')
{
listContent.erase(0,1);
dashPos = listContent.rfind("-",string::npos);
while(dashPos!=string::npos)
{
listContent.pop_back();
dashPos = listContent.rfind("-",string::npos);
}
cTagsList.push_back(listContent);
}
}
(I haven't tested it)

Printing the value of an int Pointer

I have been working on this and I can't seem to get this working properly. I am returning a pointer list's last value, and I would like to print it, but It is printing a very random number. I assuming that this is the memory address of the pointer, but when I dereference it, my output still does the same thing.
My Pointerlist is a list of pointers, like: list<int*> pointerList
For example, this is my method returning :
int* end() { return (pointerList.back()); }
An this is how I am calling it.
int* totry = ca.end();
cout << *totry;
This is printing the Memory Adress and not the value. Does anyone have any Ideas how to solve this?
Thanks in advance!
EDIT:
Here is what the int pointers are pointing to:
I have a list of values such as [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
And I have a list of pointers that points to different parts of that list like the following:
[0,4,8,12]
I have the Code: int* end() { return (pointerList.back()); } in my Header file, and the call in my .cpp file:
int* totry = ca.end();
cout << *totry;
This is how I declare my pointerlist
class ptrList
{
public:
std::list<value_type> listOfValues;
std::list<*int> pointerlist;
I fill my list pointers inside an "add" function, and I do it like this:
int lstsqrt = 4;
for (int a = 1; a < lstsqrt; a++)
{
int endptr = a + (int)lstsqrt;
pointerlist.push_back((&*listOfValues.begin() + endptr)); //( (lstsqrt - 1) + a) );
}
And this is my end() method
int* end() {return (pointerlist.back());}
And this is then passed to my toTry Variable.
One problem is likely to be this line:
pointerlist.push_back((&*listOfValues.begin() + endptr));
Your listOfValues is a std::list, and therefore its values are not stored in a contiguous block of memory. So you're getting an iterator to the first element with listOfValues.begin(), dereferencing the iterator with *, taking the address of that with & to get an int*, then adding some value which points somewhere off into memory that you don't know what it is.
Try doing this instead:
pointerlist.push_back((&*(listOfValues.begin() + endptr)));
where you add endptr to the iterator (to advance it along the list), then dereference and take the address. Actually you may need to use advance instead of +.