Passing vector to a function gives error. c++ - c++

This is a noob question, sorry but, I just started using vectors in c++. Here's is the code I am struggling with.
int main()
{
//some code
int n;
cin>>n;
vector <int> a(n+1,0);
int first=find(&a,d); //d has some value from the upper portion of the code
}
int find(vector <int>* a,int o)
{
int b=o;
while(a->b!=0)
b=a->b;
return b;
}
Q1 : Why doesn't passing vector like find(a,d) work like it does in arrays.?
Q2 : In the find function, Why do I have to access the vector elements with "." or "->". Shouldn't a[b] work? If that is the correct way then why does a[b] work in the main function?
Q3 : What's wrong with the code? When I compile I get the error
In function ‘int find(std::vector<int>*, int)’:
error: ‘class std::vector<int>’ has no member named ‘b’
I understand the error, but then how do I access the required element?
Thanks in advance. :)

Why doesn't passing vector like find(a,d) work like it does in arrays.?
Arrays are passed by "decaying" into a pointer to the first element; so they are effectively passed by reference.
Vectors are straightforward object types, passed by value unless the function is declared to take a reference. A function taking it by value will get a separate copy of it.
You could change the function to take the vector by reference:
void find(const std::vector<int> & a, int o);
^
The const is optional, but is a very good idea if the function doesn't need to modify the vector.
In the find function, Why do I have to access the vector elements with "." or "->".
You don't. You access class members of the vector itself (such as size()) like that.
Shouldn't a[b] work?
It would if a were an object or reference. Since it's a pointer, you have to dereference it, (*a)[b]
If that is the correct way then why does a[b] work in the main function?
In the main function, 'a' is an object, so can be used directly as an operand.

You should study vectors, templates, the c++ way to do that.
Take a look at: http://www.cplusplus.com/reference/vector/vector/
Q1 : Why doesn't passing vector like find(a,d) work like it does in arrays.?
Because it is not an array, its an object, so you can pass it as copy and not referece, you just pass it as a reference if you change the value.
Q2 : In the find function, Why do I have to access the vector elements with "." or "->". Shouldn't a[b] work? If that is the correct way then why does a[b] work in the main function?
a[position] returns the element
a->b dont work, you cannot access the b as an element
Use a->at(position) to access every element in the vector
Example (you can use iterators too)
for(int x=0; x<a->size();x++)
cout << a->at(x);
Q3 : What's wrong with the code? When I compile I get the error
The previous question answers that.
You dont have the b element, the A is a vector it contains elements.
If you want to get the element at the position B do a->at(b).
If you want to find use
for(int x=0; x<a->size();x++)
if(a->at(x) == b) return x; //returns the position

You're saying:
int b = o;
while(a->b!=0)
b=a->b;
return b;
when you mean:
for(vector<int>::const_interator i = a.begin(); i != a.end(); ++i)
if (*a == o)
return a.end() - i;
return a.size();

Related

How to use c++ swap function?

When I write like this swap(a,b); it is ok.
When I write like this swap(&c[0],&d[0]); there is a error.
Somebody can tell me why?
#include<iostream>
#include<algorithm>
using namespace std;
int main(void){
int *a;
int *b;
int c[]={1,2};
int d[]={3,4};
a=&c[0];
b=&d[0];
swap(a,b);// it is ok
//swap(&c[0],&d[0]);// it is error why
cout<<a[0]<<" "<<b[0]<<endl;
cin.get();
}
user3365922 is correct on the syntax if you wish to swap the contents of c[0] and d[0].
Just to add on because you code sample is a bit weird.
std::swap(a,b) in your code isn't actually swapping the contents c[0] and d[0]. It's swapping the pointers a & b. I mention this because it looks like you replaced the std::swap(&c[0], &d[0]) with std::swap(a,b)--which isn't actually equivalent (this is an assumption, my bad if they weren't meant to be equivalent).
I'm not totally sure what your goal is, but std::swap(c[0], d[0]) will achieve swapping the first entry of c with the first entry of d (leaving the second entry as-is). If you actually wanted to swap the contents of arrays entirely in the example above, you could also do std::swap(c, d).
Replace swap(&c[0],&d[0]) with swap(c[0], d[0]).
&c[0] and &d[0] are rvalues (temporary objects of type int*), but you can swap lvalues only.
You're able to swap(a, b) because a and b are lvalues, a after swap will be pointing to d[0] and b to c[0], swap(a, b) wouldn't swap values in array, this is a difference in behaviour (thanks to M.M's comment with a notice).
swap function
template <class T> void swap ( T& a, T& b )
{
T c(a); a=b; b=c;
}
And a=&c[0]; b=&d[0]; after swap(a,b);
a will pointing to d[0]
b will pointing to c[0]
and here swap(&c[0],&d[0]); the prototype dose not match the current swap function.The required prototype is
swap(int*,int*)
so there is no matching function to call so the compiler throws error.
The arguments to std::swap() are two integer pointers, not two addresses of an array with an index.
For swapping normal singular int values you will have to use a pointer (call by reference), but for an array you could directly pass it (as base address of array is taken) for which you could have used c[0],d[0]. Using & to reference the array (i.e. using &c[0],&d[0]) with the function accepting a int * type would cause argument type mismatch, with your passed values being rvalues of type int *, which cannot be swapped. (whereas lvalues like c,d and c[index],d[index] can be swapped)
The error you recieved should be:
main.cpp:12:13: error: no matching function for call to ‘swap(int*, int*)’
swap(&c[0],&d[0]);
^
This pertains to invalid initialization of a non-const reference of type int*& from an rvalue of type int*, which is included in the error message.
If what you want to consider as the parameters are indeed addresses of the arrays, this would be your function:
void swap_array_elements(int a, int b, int arr[], int arr2[])
{
int temp = arr[a];
arr[a] = arr2[b];
arr2[b] = temp;
}
Note that the first two arguments used here are indices of the two arrays passed respectively as the third and fourth argument. This will swap in between any two elements you require among the two arrays.
Example:
#include <iostream>
void swap_array_elements(int a, int b, int arr[], int arr2[])
{
int temp = arr[a];
arr[a] = arr2[b];
arr2[b] = temp;
}
int main()
{ int array1[]={42,56}, array2[]={63,89};
swap_array_elements(0,1,array1,array2); // swapping element with index 0 in array1 (42) with element with index 1 in array2 (89)
std::cout<<array1[0]<<" "<<array2[1]; // 89 42
return 0;
}

How to edit an object's data from a function?

I apologize if this question has already been answered (I tried searching around, but couldn't find anything quite the same, and similar questions' solutions didn't work), but how do I pass an object (in this case, a vector of objects) and have the function edit those values without returning anything?
Example:
void incVector(std::vector<int> vec)
{
for (auto l = 0; l < int(vec.size()); l++)
{
vec[l]++;
}
}
int main()
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
for (auto l = 0; l < int(vec.size()); l++)
{
std::cout << vec[l]; //Output: "12"
}
incVector(vec);
for (auto l = 0; l < int(vec.size()); l++)
{
std::cout << vec[l]; //Output: "12"
//This output should be "23"
}
}
Obviously, what I'm actually using this for is much more complex, but this is enough of an example to get the point of what I'm trying to do across. In the actual project, it's a rabbit hole of different functions, some of which return things while others don't, so having it simply return the vector isn't an option.
I have tried making incVector accept a reference to a vector, a pointer to a vector, a pointer to a reference to a vector, and a pointer to a pointer to a vector (which are solutions that seemed to work for other similar questions) but none of those are working for me.
EDIT:
God, I feel stupid. I swear I'd tried using a reference before and it didn't work. Yet now, trying it again works just fine. Sorry! ^^;
you pass the vector by value, thus modifications are purely local:
change prototype of your function to:
void incVector(std::vector<int> &vec)
to pass by reference and get the one from main modified
Take the argument by reference. You can also use a modern for-loop.
void incVector(std::vector<int>& vec)
{
for (auto& l : vec)
{
++l;
}
}
But you don't actually need to do any of this. Applying an operation on each element of the vector can be done easily using a standard algorithm (std::for_each) and a lambda function that takes a reference to the vector's element:
#include <algorithm>
// ...
std::for_each(vec.begin(), vec.end(), [](int& l){ ++l; });
for_each is going to call the lambda for each element in the vector and pass it as the argument. Since you take the argument by reference (int&), incrementing it will increment the actual element contained in the vector.
The key point to take away from this however, is that when you want to give a new name to an object that already exists, you use a reference. Those are declared with & before their identifier:
int i = 0;
int &i_ref = i;
Here, i_ref is a reference to i, meaning it's just another name for i. Modifying i_ref is the same as modifying i.
The same applies to function arguments. If a function argument is a reference, it means it's another name for the object that was passed to the function. Modifying the reference is the same as modifying the object that was passed to the function.

How to return an array in c++

How should I return an array from a function? My code is
float ClassArray::arr_sub(float a[100][100], float b[100][100]) {
int i,j;
for(i = 1; i < 10; i++) {
for(j = 1; j < 10; j++){
f[i][j]=b[i][j]-a[i][j];
}
}
return f;
}
and the f returned from this function should be assigned to another array g declared in some other class.
float g[100][100];
g= cm.arr_sub(T,W);
but while building the classes, it says incompatible type assignment of float to float[100][100].
My answer here to another question on arrays explains why you don't want to use arrays.
As I say in that answer you can't assign an array like you're trying:
float g[100];
g = foo(); // illegal, assigning to arrays is not allowed
Another of the weird restrictions on arrays is that you're not allowed to return them from functions:
float foo()[100]; // illegal, returning an array from a function is not allowed
Also note that when you declare a function like float arr_sub(float a[100][100]) you might think you're passing an array by value, but in fact that invokes another of the weird exceptions made for arrays. In C and C++, whenever you declare a formal parameter of a function to be an array, the type is adjusted from 'array' to 'pointer to the array's element type'.
Since arrays don't behave like they ought, you should instead use std::array or std::vector:
std::array<float,100> foo(); // works
std::array<float,100> g;
g = foo(); // works
To do multi-dimentional arrays you can use:
std::array<std::array<float,100>,100> g;
Though that's a bit cumbersome so you can typedef it:
typedef std::array<std::array<float,100>,100> Matrix;
Matrix ClassArray::arr_sub(Matrix a, Matrix b) {
...
}
Matrix g;
g = cm.arr_sub(T,W);
And if you have a compiler that supports C++11 you can even do a template type alias:
template<typename T,int Rows,int Columns>
using Matrix2d = std::array<std::array<T,Columns>,Rows>;
Matrix2d<float,100,100> g;
Note on performance
There is one reason you might not want to return an std::array by value. If the array is large then there may be a signficant performance cost in copying the data from the return value into the variable you assign it to. If that ever proves to be a problem for you, then the solution with std::array is the same as it would be for other large types; use an 'out' parameter instead of returning by value.
void arr_sub(Matrix a, Matrix b, Matrix &result);
Matrix g;
arr_sub(T,W,g);
This doesn't apply to std::vector because std::vector can take advantage of move semantics to avoid having to copy all its elements.
If you insist on using "plain C" 2D arrays, the best thing is to pass a pointer to the result along with the two input parameters, rather than passing the arrays by value the way you did.
However, the best thing to do in C++ is to use vector<vector<float> > instead, and pass it by reference.
void ClassArray::arr_sub(
const vector<vector<float> > &a
, const vector<vector<float> > &b
, vector<vector<float> > &res)
{
for(int i=0 ; i != a.size() ; i++)
for(int j=0 ; j != b.size() ; j++)
res[i][j] = b[i][j] - a[i][j];
}
void main() {
vector<vector<float> > a(100, vector<float>(100, 12.345));
vector<vector<float> > b(100, vector<float>(100, 98.765));
vector<vector<float> > res(100, vector<float>(100, 0));
arr_sub(a, b, res);
}
The best way to do this is to wrap everything into a class. From the look of things, its a Matrix.
There are probably a hundred Matrix classes out there already, so it is really pointless to write another one.
But, if this is a learning exercise it might be worthwhile.
To answer your asked question, make a third argument to your function: float result[100][100]. Inside your function, write the results into the result array.
This works because in C and C++, arrays are always passed by reference and never by value. This is because C++ passes only the pointer to the beginning of the array.
if you really wish to return an array and some how manage to use it in the main(), the most efficient way would be to declare the returning array as dynamic. that way you will avoid losing the pointer to this new array as it will be allocated in heap and not in stack.

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 +.

c++ std::set insert causing segmentation fault

All-
I can't quite figure out why this piece of code is resulting in a segmentation fault... Any help would be great.
#include <iostream>
#include <set>
using namespace std;
class A{
public:
int _x;
A(int x){
_x = x;
}
};
bool fncomp(A a1, A a2){
return a1._x < a2._x;
}
int main(){
bool(*fn_pt)(A,A) = fncomp;
set<A, bool(*)(A,A)> testSet;
for(int i=0; i<10; i++){
cout << i << endl;
A a(i);
testSet.insert(a);
}
}
The output is:
0
1
Segmentation Fault
Well, look at your code. You declared a function fncomp, but are you really using that function anywhere? You initialize fn_pt with it, but fn_pt is not used anywhere. Doesn't it seem strange to you? How do you expect your testSet object to know that you want it to use your fncomp as the comparator, if you never ask your set object to use that function?
You declared your set testSet with an ordinary function pointer type bool(*)(A,A) as a comparator type. That's the type of the comparator. Now, you have to pass the actual value of the comparator to your set object through the constructor parameter
set<A, bool(*)(A,A)> testSet(fn_pt);
or
set<A, bool(*)(A,A)> testSet(fncomp);
(You don't really need that intermediate pointer fn_pt).
You forgot to do that, and the set object used the default constructor argument value for the comparator, which in this case is a null pointer. So, every time your testSet object tries to compare two elements, it performs a function call through a null pointer. No wonder it crashes.
Didn't you get a compiler warning about the unused variable fn_pt?
The variable testSet has an internal comparator of the specified type bool(*)(A,A). Since you didn't initialize it, it was default initialized as NULL. So when testSet tried to insert A(1), it tried to invoke a null function pointer to figure out which order is correct.
You probably meant:
set<A, bool(*)(A,A)> testSet(fn_pt);