I have absolutely no clue, what the difference is between the two following examples:
void function(int *p) {
p++;
}
int main() {
int values[] = {1,2,3};
int *p = values;
function(p);
cout << *p;
return 0;
}
This one returns "1".
Whereas a slight modification yields "2" (which is the wanted result):
int main() {
int values[] = {1,2,3};
int *p = values;
p++;
cout << *p;
return 0;
}
Where lies the problem? Is it due to passing by reference or incrementing?
The issue here is
void function(int *p) {
p++;
}
Is using pass by value - not pass by reference. Since the pointer is passed by value any change you make to the pointer itself is not reflected in the call site. If you need to modify where the pointer points then you need to pass it by reference like
void function(int*& p) {
p++;
}
Now when you increment it will point to the second element like it does in your second example.
In this example
void function(int *p) {
p++;
}
int main() {
int values[] = {1,2,3};
int *p = values;
function(p);
cout << *p;
return 0;
}
You are passing a pointer by value, which means you simply pass a copy of the address the pointer is pointing at. You then proceed to increment the function's local copy of that pointer and then exit the function. This has no effect on the original pointer as you incremented a local copy.
In this example, however
int main() {
int values[] = {1,2,3};
int *p = values;
p++;
cout << *p;
return 0;
}
You directly increment your pointer, which means it is now pointing at the next element in the array.
In the first case the value of address is passed by value.
function(p) ==> void function(int *p){}
The 'p' on right side a local variable. So any modification to the pointer will be visible only inside function.
Related
How should be the signature of a funtion
in order to not be able able to change
both the value and the address of the passed pointer?
void testP(int*& k)
{
std::cout << "testP addr:" << k << std::endl;
}
int main()
{
int* p = new int(5);
testP(p);
delete p;
return 0;
}
How should be the signature of a funtion in order to not be able able to change both the value and the address of the passed pointer?
You need to make the parameter to be a reference to a const pointer to a const int as shown below:
//---------vvvvv-----vvvvv----------->added const
void testP(const int*const& k);
{
//*k = 4; //NOT ALLOWED
// k = nullptr ; //NOT ALLOWED
}
Note that the parameter k in the above declaration will be the same if you change the parameter declaration to int const* const&.
When we use arrays and pointers this way:
int *g() {
int arr[] = {1, 2, 3};
return arr;
}
int f() {
int *value = g();
for (size_t i = 0; i < 3; i++) {
std::cout << value[i] << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
It is deleted from the stack after function g returns, so we get a segment error in the function f()
But using std::vector this same logic works without any problem:
std::vector<int> g() {
std::vector<int> arr = {1, 2, 3};
return arr;
}
int f() {
std::vector<int> value = g();
for (size_t i = 0; i < value.size(); i++) {
std::cout << value.at(i) << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
I was thinking that this is something related to the fact that we have the std::vector class acting as a container to the array but using a struct as a container delete the array either:
struct T {
int *arr;
};
T g() {
T t;
int arr[] = {1, 2, 3};
t.arr = arr;
return t;
}
int f() {
T value = g();
for (size_t i = 0; i < 3; i++) {
std::cout << value.arr[i] << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
And in this case, g++ allow us to overflow the array pointer memory limits with the index subscription.
Why vectors doesn't share the same problem?
All the elements in the vector essentially count as part of the vector. And notice you are returning the vector, not a pointer to the vector. But you are returning a pointer to (the start of) the array.
When the function g returns, the vector arr is destroyed but that's okay because that's not the same one that is returned. A copy of arr is returned. (Actually, the compiler is clever enough to reuse the same vector instead of copying it and then deleting one - but you can imagine that it makes a copy)
Then f prints values from its own local variable value - no problem.
By contrast, in the pointer version, f is printing values from the local variable arr inside g, which has already been destroyed. If g would return a pointer to a vector, it would have the same problem.
Your intuition was somewhat right it has something to do with the containment of the array inside a struct, what you misunderstand however is the difference between (int[]) and (int*) and probably you don't understand well where memory resides as well.
To clarify:
In C++ C-style array types (int[]), (char[]) etc cannot be returned from a function.
Your function does not return (int[]) it returns int* which is a pointer that points to an an (int[]'s zero element in the stack space of some function f() ) and hence the existence of this (int[]) stops past the lifetime of the function f(), but a dangling pointer was copied to the caller's site;
Try
using int_array = int[4];
int_array f()
{
int_array arr { 1, 2, 3, 4};
return arr; // Does not compile cannot return array
}
int* f2()
{
int_array arr { 1, 2, 3, 4};
return arr; // Compiles because int[4] is implicitly cast to int*
}
In the case of vector, it contains a pointer to a dynamically allocated memory block, acquired through some means(new, malloc, custom user defined allocator, etc) hence this memory block is not bound to the lifetime of a function call, but it is managed by the owner of it. When you return the vector to the caller, the memory block behind continues to exist until a (delete, free, custom-delete) is called on it. The vector does this in it's destructor ( ~vector() ), but before that happening a vector( const vector& ) constructor call occurs that copies the content of one vector to the other. Most compilers will optimize away this operation, as mentioned by another answer.
In the case where you return the struct, the problem is the same, you are not returning an array (int[]) you are returning a pointer. If you were to contain an array inside the struct it would be successfully copied back to caller, because the restriction only applies for arrays and not for user defined types.
Try:
struct Foo {
int arr[4];
};
Foo f()
{
Foo obj{ 1, 2, 3, 4 }; // brace initialization of struct
return obj;
}
int main()
{
Foo obj = f();
for(int i = 0; i < 4; i++)
std::cout << i << ' '; // outputs 1 2 3 4 with no issues
}
As you can see no issues with memory here. That's why the std::array<> from header exists - to wrap C-Style arrays so they can be copied over.
I hope this explains well enough.
In the second method returning vector<int>. The std::vector<int> arr was copied to another a temporary vector<int>, then std::vector<int> arr was destroyed.
Finally, the vector<int> value was assigned with temporary vector<int>, after assigning completed, temporary vector<int> was destroyed as well.
That's what i think happening with your example.
I'm trying to write an example code for the following line of code:
int (*(*foo)(const void*))[3];
I got this code from here (at each refresh of the website you get a different piece of code and there is a finite set of them so by reloading a couple of times you will get my example). I wanted to see out of curiosity is it even possible to write some code that would make this line work.
Here is what I wrote so far:
#include<stdio.h>
#include<malloc.h>
int* goo(const void * ptr) {
int* ret = (int*) malloc(sizeof(int) * 3);
if (!ret)
return NULL;
for (int i = 0; i < 3; ++i)
ret[i] = i;
return ret;
}
int doo() { return 0; }
int main(void) {
//NOTE: Following 2 lines have syntax errors
int (*(*foo)(const void*))[3] = &goo;
int* values = foo(goo(doo));
for (int i = 0; i < 3; ++i) {
printf("%d", values[i]);
}
free(values);
return 0;
}
If I understood correctly, foo should be some function that receives as an argument another function and returns an int array of size 3. The problem is I don't know how to make foo in this case point to a function or even how to get the int array.
Is it even possible to make this line of code work?
If I understood correctly, foo should be some function
foo is a pointer to a function.
that receives as an argument another function
No, the parameter type of the function that foo points to must be a pointer to const void i.e. const void*. A pointer to void is an object pointer. It can point to an object of any type.
Functions are not objects, but on some systems, pointers to functions can be reinterpreted as pointers to void.
and returns an int array of size 3.
No; Return types cannot be arrays. The function must return a pointer to an array of 3 ints i.e. int(*)[3].
Is it even possible to make this line of code work?
Here is an example program that uses such foo. It doesn't make much sense, but that's because the goal is to use an obscure function pointer:
#include<iostream>
int arr[] {
1,
2,
3,
};
int (*goo(const void*))[3] {
return &arr;
}
int main() {
int (*(*foo)(const void*))[3] = &goo;
int (*values)[3] = foo(nullptr);
for (int i : *values) {
std::cout << i << " ";
}
}
We can greatly improve readability by introducing type aliases:
using IntArr3 = int[3];
using FooFun = IntArr3*(const void*);
IntArr3* goo(const void*) {
return &arr;
}
int main() {
FooFun* foo = &goo;
IntArr3* values = foo(nullptr);
for (int i : *values) {
std::cout << i << " ";
}
}
#include<iostream>
using namespace std;
class Test
{
private:
int x;
public:
Test(int x = 0) { this->x = x; }
void change(Test *t)
{
this = t; //line 1
}
void print() { cout << "x = " << x << endl; }
};
int main()
{
Test obj(5);
Test *ptr = new Test (10);
obj.change(ptr);
obj.print();
return 0;
}
since we know that this pointer hold the reference of calling object. In line 1 i am trying to change the reference of calling object but it shows an error "lvalue required". Can someone explain this??
You cannot assign a pointer to this pointer, because it's a prvalue.
this pointer is a constant pointer that holds the memory address of the current object.
As a result, this is of type const Test* in your case, so it cannot be assigned to. Doing so (if it was allowed) would effectively allow an object to change its own address in memory, as #Peter mentioned.
Note: const Test* is a pointer to a constant object. The object it points to is constant, not the pointer itself.
PS: this->x = t->x; is probably what you meant to say.
Here you are assigning a pointer(here t) to "this" pointer for a particular object.
"this" pointer is const. pointer that holds the memory address of the current object. You simply can't change the this pointer for an object, since doing this you will practically be changing the location of the object in the memory keeping the name same.
Reference - ‘this’ pointer in C++
#include <iostream>
using namespace std;
class Test
{
private:
int x;
public:
Test(int x=0)
{
this->x = x;
}
void change(Test *t)
{
t->x; //t is a pointer. so make it point to x
}
void print() { cout << "x = " << x << endl; }
};
int main()
{
Test obj(5);
Test obj1(10); //create a new object
Test *ptr = &obj1;//make the pointer point to obj1
obj.change(ptr); //use change() to point to argument of obj1
obj.print(); //print the value of obj now
return 0;
}
When you have a function like this, the formal parameter is a reference, it becomes another name for the actual argument, so that when we modify the formal parameter inside the function, the original variable outside the function is changed.
void add_five(int& a)
{
a += 5;
}
int main()
{
int number = 3;
add_five(number);
std::cout << number << std::endl; // prints 8
return 0;
}
I have some code which works on a linked lists. And I am passing two Node*s into the function.
void LinkedList::move_five_nodes(Node* ptr1, Node* ptr2) { ... }
...
void LinkedList::anotherFunction()
{
Node* leader;
Node* trailer;
...
move_five_nodes(leader, trailer);
...
}
I think that the rvalues memory addreses inside the leader and trailer pointer variables will be assigned into the Node* lvalues ptr1 and ptr2.
Node* ptr1 = leader;
Node* ptr2 = trailer;
The issue is that ptr1 and ptr2 are independent local variables inside the function. Initially, they point to the same place as the actual argument pointers. However, my function moves some nodes, and at the end of the function, the values of ptr1 and ptr2 are changed. I want these changes to also be in the original variables leader and trailer, just like references. So even when ptr1 and ptr2 expire, leader and trailer should go into their positions.
How would I do this? Maybe type cast the pointers into int&? Or maybe use pointers to pointers? I want to pass a pointer by reference, but I'm not sure how to do that.
I want to pass a pointer by reference, but I'm not sure how to do that.
For this, consider the following snippet
#include <iostream>
void test(int*& t)
{
t = nullptr;
}
int main()
{
int* i = new int(4);
test(i);
if (i == nullptr)
std::cout << "I was passed by reference" << std::endl;
}
in which is is passed by reference to test, where it is set to nullptr and the program prints: I was passed by reference.
I think this example should make clear how to pass a pointer by reference to a function.
So in your case the function signiture must change to
void LinkedList::move_five_nodes(Node*& ptr1, Node*& ptr2) { ... }
#include <iostream>
void test(int& ref);
int main()
{
int* pointer = new int(10);
std::cout << "before" << *pointer << std::endl ;
test(*pointer);
std::cout << "after" << *pointer << std::endl;
delete pointer;
}
void test(int& ref)
{
ref = 20;
}