I have created two routines, one to sort a vector in-place:
void Sort(double** vector, unsigned int vectorLength) {
//...
}
and one that returns a new array with the sorted result:
double* Sort(double* vector, unsigned int vectorLength) {
//...
}
Later using the sort method:
double* test = new double[5];
//...
Sort(*test, 5);
I receive the compiler error that 'none of the 2 overloads could convert all the argument types.'
Is not the type double*, a pointer to a double, not fundamentally different to a double**, a pointer to a pointer to a double?
How is this not clear to the compiler?
You get the error because *test expression is neither double* nor double** - it's a double, with no asterisks.
Passing test without dereferencing it would have worked:
double* sorted = Sort(test, 5); // Invokes the second overload
Note that you can sort in place even if you pass a pointer. Using an overload for this that requires an artificial &, works but it makes your API counter-intuitive.
A better approach would be defining a method with the same set of parameters, but a different name, for example
double* Sort(double* vector, size_t vectorLength) {
//...
}
void SortInPlace(double* vector, size_t vectorLength) {
//...
}
Your variable test has type double* and so *double has type double. Which means that you are attempting to pass double which matches neither double* nor double**.
One possibility is that you actually meant to create a sorted copy of the original array:
double* sorted = Sort(test, 5);
But I rather presume, since your call to Sort ignores the return value, that you meant to pass &test to sort in-place.
Sort(&test, 5);
However, that in itself indicates that your interface is badly designed. You would pass &test if you wanted the function to modify test. But you don't. You want the function to modify the array that test refers to. Your in-place sort function can, and should, be implemented by passing a parameter of type double*.
It is my opinion that you are abusing function overloading here. I would recommend that you choose a different design. I would use functions with different names.
Some other comments:
Use size_t for array lengths.
Use const to indicate that an input parameter shall not be modified.
It's very clear, but the expression *test when test has the type double * is the same as test[0], i.e. it's a double and not a pointer at all.
Perhaps you meant &test to take the address of the pointer.
*test goes directly to the value stored in that memory address. So, it goes to the double stored in the address test, which is a pointer to double.
So, you're passing a double value, not a pointer.
Your work would work with either of these two:
Sort(test, 5); // Passes a pointer to double.
or
Sort(&test, 5); // Gives you the address of test. Passes a pointer to a pointer to double.
Related
What is the purpose of a function parameter that has two indirection operators?
Since a call by reference is changing the value of the original variable I thought that a function parameter with two indirection operators might change the address of the original value.
But as my attemp below shows, it does not:
void addrchanger(int**);
int main()
{
int value1 = 4;
int* value1ptr = &value1;
std::cout<<&value1<<std::endl;
addrchanger(&value1ptr);
std::cout<<&value1<<std::endl;
//the address of value1 doesn't change.
}
void addrchanger(int** foo)
{
//this is an attempt to change the address of value1 to the next slot
++**foo;
}
The purpose is to pass a pointer to pointer(s) or a pointer to array(s). Such practise is C-like for historical functions like main() char** argv (that is why you also want an argc, because the size cannot be deduced by the pointer). It is also used when you want to be returned a pointer, so you pass a pointer to a pointer, like in many Win32 functions.
For example in StringFromIID
HRESULT StringFromIID(
REFIID rclsid,
LPOLESTR *lplpsz
);
you would pass a double pointer as the 2nd parameter (a wchar_t**) in order to be returned a pointer, which them must be deallocated like the doc says.
Avoid that completely nowadays in C++ and use std::vector in whatever depth is necessary.
The void addrchanger(int** foo) function can change:
the value: (**foo)++ making int value1 to 5
and address: (*foo)++ making value1ptr point to the next space after value1
I believe you expected the ++**foo to move value1 to the next position, which is not the case.
The pointer to pointer is also useful for matrix declarations, but most libraries such as the GNU scientific library, BLAS, OpenGL glLoadMatrixf(), prefer the use of a single pointer.
When p is of type int **,
++**p
increases the value of the int represented by **p.
In order to change the address of the int pointed to, you would use
++*p
With direct access to your variable, you would use one * less for everything:
int *p;
++*p; // increment the int value
++p; // increment the pointer
But inside such a function, every arguments is just a copy, so if you want to change something outside, you need a pointer to it, which means that one more * is used for everything.
function f(int **p) {
++**p; // increment the int value
++*p; // increment the pointer
// you can also increment the argument
// but you can't know whether it will then
// still point to another int pointer:
++p
}
In addition, you can use & instead of * in C++ which is used only for declaring a variable as a reference and then works like a secret, hidden pointer. You use one less * again, like outside the function at the beginning.
function f(int *&p) {
++*p; // increment the int value
++p; // increment the pointer
// you can also not increment the reference itself,
// as it is a hidden pointer.
}
This sounds dangerous because who would want secret pointers? But it is very common in C++ because people like typing less * all over the place.
I'm reteaching myself C++ and as I'm reading about pointers a question has came into mind.
When declaring function signatures in C++, the address-of and dereference operators are used, such as the below.
int someFunction(std::vector<int>& nums) {
//do stuff
}
In this context the & is being used to declare that the address of the nums variable is being used rather than the value.
If this signature is changed to the below, the value is being used instead.
int someFunction(std::vector<int>* nums) {
//do stuff
}
However if the below is now used, I assume the value of the nums variable is still being used despite the lack of operator.
int someFunction(std::vector<int> nums) {
//do stuff
}
If this is true, since the lack of an operator and the * operator both result in the same thing, why is there any need for the * operator at all? Is it simply for brevity?
Those * and & in your code are neither dereference nor address-of operators. Both, * and & can have different meanings. Here they are part of the type:
int x; // declares an int
int* p; // declares a pointer to int
int& r = x; // declares a reference to int
The address-of and dereference operators come into play for example when you assign something to the above variables:
p = &x; // here & is address-of operator
x = *p; // here * is dereference operator
int someFunction(std::vector<int>& nums) {
//do stuff
}
In this context the & is being used to declare that the address of the nums variable is being used rather than the value.
No. Here the & means that nums is passed as reference.
If this signature is changed to the below, the value is being used
instead.
int someFunction(std::vector<int>* nums) {
//do stuff
}
No. Here nums is passed as pointer.
Only this is pass-by-value:
int someFunction(std::vector<int> nums) {
//do stuff
}
You are confusing things. In C++ arguments passed to a function are copied into the function. This is called "passing arguments by value", which is Ok for small types such as primitive types (int, double, etc), but it might be very costly for large objects. Imagine if your std::vector has 10 million elements.
In the first case with int someFunction(std::vector<int>& nums) the & indicates to the compiler that you want to pass the argment nums by reference, instead of the default by value. That means that the vector will not be copied into the function and a reference will be used instead (the cost here is like copying a single pointer). Note that since you are using a reference, if you modify nums inside your function the change will be visible outside the function (the variable passed as argument to the function will be changed). This is sometimes what you want and sometimes it is not. If you want to avoid the copy but don't want to change the vector, use int someFunction(const std::vector<int>& nums) instead.
In the second case you are actually passing just a pointer to the function and not a std::vector<int>, although the pointer points to an std::vector<int>. Similarly to the previous case, only a pointer is copied no matter how many elements the vector has and any change you made the the pointed vector will be visible outside the function. Note, however, that pointers can be null, while references cannot. That means that you would need to check if the pointer is null.
The third case is the default "passing by value" and a vector is copied into the function. Any change you make in the vector will not be visible outside the function, since you only changed the copy. But the cost can be high if the vector as many elements.
Please consider these 2 lines of code
void doStuff(int ** i)
void doStuff2( int && i)
in the first one I assume that it is a pointer of pointer and the second is an rvalue,
I came across this question and it explains the rvalue but when should I use the first and when should I use the second ?
could you clarify this to me please ?
int ** i is a pointer to a pointer.
Generally, use this sparingly, as this may have different meanings and you have better ways to express that in C++.
It may be a pointer to single variable containing a pointer to a single int:
int value = 0;
int * pValue = &value;
int ** ppValue = &pValue;
However, each may also be a pointer to the first element of an array:
int valuesA[1000], valuesB[100], valuesC[10];
int * pValues[] = { valuesA, valuesB, valuesC };
// these are actually pointers to the first element of the array
int ** ppValues = pValues;
Use this only with clear documentation how to access elements, how to know the element sizes, and who is responsible for freeing (if any), how long the pointers are valid etc.
Usually, if you have such an array / matrix, you certainly should wrap it behind a safe-to-use interface, or replace it alltogether e.g. with a vector<vector<int>>.
Even for the single-int use cases there are usually better options. E.g. a function signature that allows to modify a pointer, a reference to a pointer would be more suitable:
bool SelectValue(int *& p) { ... }
int && is a rvalue reference.
Unlike the int **, this is not a double indirection.
It is, roughly a reference that can also bind to a temporary value.
("Normal" references cannot).
A Brief Introduction to Rvalue References
I have been trying to cast a map structure to a void pointer and cast it vice versa.
void addToMap(void *data){
// add some elements to the map
}
map<string, vector<myStruct> > myMap;
addToMap(&myMap);
I am trying to send myMap to addToMap function as an argument and add some elements inside the function. How can I deference the void parameter back to the map structure ?
I know that static_cast can be used to dereference the void type to know types. For instance:
int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);
The above snippet would work, but not in this case I suppose. I have already tried it out for my case, perhaps there has to be another trick.
In addToMap function you can cast the void pointer back to the original type:
void addToMap(void *data){
auto pmap = static_cast<map<string, vector<myStruct> >*>(data);
pmap->insert(...);
}
static_cast is also able to perform all conversions allowed implicitly
(not only those with pointers to classes), and is also able to perform
the opposite of these. It can:
Convert from void* to any pointer type. In this case, it guarantees that if the void* value was obtained by converting from
that same pointer type, the resulting pointer value is the same.
I'm getting declared as array of references of type float& error in XCode when I declare a function as :
void calcCoeff(float sigma, float& ap[], float& bp[], float& an[], float& bn[]);
can anyone tell me what could be the problem? I also tried
void calcCoeff(float sigma, float &ap[5], float &bp[5], float &an[5], float &bn[5]);
thanks...
The problem is exactly as described by the error message: float& ap[] declares an array of references, and that's not a legal type in C++, just as pointers to references and references to references are prohibited.
If it were legal you can think of what it would mean by thinking of an array of pointers. A reference is in some ways conceptually similar to a pointer; a reference is meant to refer to another entity and when a reference requires a runtime representation C++ implementations typically use pointers.
So, if you were to pass an array of pointers to a function you would need to construct an initialize it:
float a, b, c;
float *arr[] = {&a, &b, &c}; // or in fictional array-of-references syntax: float &arr[] = {a, b, c};
Or if you already have an array of floats, and you want an array of pointers to those elements:
float a[3];
float *b[] = {&a[0], &a[1], &a[2]); // or in fictional array-of-references syntax: float &b[] = {a[0], a[1], a[2]};
Presumably what you actually want is to pass an array, by reference, to a function so that the function can write into the array and the changes will be visible to the caller. (or simply because you want to avoid copying the array). Since normally function parameters are passed by value, and the way to pass by reference is to stick & in there you did the same for an array type. This is a pretty good instinct, but there are a few wrinkles in C++ that messed it up for you.
The first is simply the odd syntax for declaration in C++. You can read about the 'spiral rule' or 'declaration mimics use' elsewhere, but suffice it to say that it matters whether that & is 'closer' (syntactically) to the variable name or float. float &arr[] is an array of references. You need a couple parentheses to put the ampersand closer to the variable: float (&arr)[] declares a reference to an array.
Next is that C++ unfortunately inherits some strange behaviors from C intended to make arrays and pointers pretty much interchangeable. The relevant behavior in your case is that if you declare a function that takes an array parameter:
void foo(int arr[], int size);
the language specifically says that the type is 'adjusted' to be a pointer. The result is the same as:
void foo(int *arr, int size);
What this means is that arrays do not behave like value types. Trying to pass an array 'by value' does not result in a modifiable copy of the array being passed to the function; instead the function effectively receives the array 'by reference'.
A second consequence is that array parameters do not need to have complete array types, i.e. the array size can be omitted, because the array type is adjusted and the size is never used anyway. This means that if you naively convert an 'array parameter' that doesn't specify a size into a reference to an array, you have to specify the size in addition to adding the &. float (&arr)[10].
Using raw array as parameters is highly undesirable in my opinion. First because it discards type information:
void foo(int arr[10]) { // same as void foo(int *arr)
int x = arr[9];
}
int bar[3];
foo(bar); // no compile error! the special array rules discarded the size of the array
And because raw arrays are not consistent with other built-in types, all of which have value semantics. For these reasons raw arrays should be avoided. Instead you can use std::array which avoids all the 'special' rules for built-in arrays and therefore behaves as built-in arrays ought to.
void foo(std::array<int, 10> arr); // Takes arr by value, modifications will not be visible externally
std::array<int, 3> bar;
foo(bar); // compile error
And if you need a dynamically sized array then you can use std::vector instead.
Change it to:
void calcCoeff(float sigma, float ap[], float bp[], float an[],
float bn[]);
You will be able to modify the values just fine. The [] notation in function arguments is equivalent to a pointer. So it's the same as this:
void calcCoeff(float sigma, float* ap, float* bp, float* an,
float* bn);
Which means that in both cases, you get a pointer to the data rather than a copy. The [] syntax is just a stylistic decision; even though float a[] means the same thing as float* a, the [] syntax is a hint to the caller of the function that it can work on arrays rather than single variables.