I came across a C++ code snippet in my exams which was quite confusing (at least for me). I tried to analyze it but there is something that I am unable to understand. The code is written below:
#include <iostream>
using namespace std;
int* doMagic(int *p, int *q)
{
int* t = new int();
t = p;
p = q;
q = t;
return t;
}
int main()
{
int p = 5, q = 10;
int *t = NULL;
t = doMagic(&p, &q);
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"t = "<<*t<<endl;
return 0;
}
The output is:
p = 5
q = 10
t = 5
Now my question is that when the values were passed by reference to doMagic function why weren't the values swapped in it.
Help will be highly appreciated.
Thanks.
The variables p and p in doMagic are local to the function. Any changes made to those variables are made locally in the function. They don't change anything in the calling function.
You can rename those variables to x and y without changing the function's behavior. That will also be a reminder that the names in main and the name in doMagic are separate and independent.
You can swap the values in doMagic by swapping the values of the objects the pointers point to:
void doMagic(int *p, int *q)
{
int t = *p;
*p = *q;
*q = t;
}
although it is idiomatically better C++ to use references
void doMagic(int& p, int& q)
{
int t = p;
p = q;
q = t;
}
Then, the function can be called from main as:
doMagic(p, q);
Having said that, if you don't intend to do anything more in the function, you should use std::swap instead. There is nothing to gain by defining a function in user space that duplicates the functionality of a standard library function.
In this code nothing gets passed by reference.
Some pointer values (&p, &q) get passed by value.
Because they were passed by value, they were stored into new variables in doMagic called p and q. The new variables were then swapped. The value &p was returned and stored in main's variable t.
Also, some memory was leaked, because an int was created with new and was never destroyed with delete.
Related
I'm getting this error when I try to compile my code.
I dont have any *(pointers) and can't understand why im getting this.
Im working now with template. You can check my code too see:
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
template <class T>
class Set
{
public:
T **p;
int n;
Set(){
};
Set(int n)
{
this->n = n;
p = new T*[n];
}
~Set()
{
if(p) delete []p;
}
void setValues(T k,int l)
{
p = k;
n = l;
}
void add(T k)
{
T p1;
p1 = p;
p = new T[n+1];
p = p1;
p[n+1] = k;
n++;
}
void remove(T k)
{
T p1;
int l =0;
p1 = p;
p = new T[n-1];
for(int i=0;i<n;i++)
if(p1[i]!=k)
{
p[l] = p1[i];
l++;
n--;
}
}
void operator+(Set s)
{
for(int i=0;i<n;i++)
p[i]+=s.p[i];
}
void operator-(Set s)
{
for(int i=0;i<n;i++)
p[i]-=s.p[i];
}
void operator*(Set s)
{
for(int i=0;i<n;i++)
p[i]*=s.p[i];
}
void show()
{
for(int i=0;i<n;i++)
cout<<p[i]<<" | ";
}
};
int main()
{
Set<int> s1,s2;
int arr[]={0,2,3,4,3,6};
int n=6;
float arr2[]={0.5,12.1,1.7,23.15};
char arr3[]={'a','h','m','k','c','e'};
s1.setValues(arr,n); // <------------- here is error;
s1.show();
}
I'm getting error on this line s1.setValues(arr,n);
This is setValues() method:
void setValues(T k,int l)
{
p = k;
n = l;
}
I had tried to avoid the error by using & like that: s1.setValues(arr,&n)
and s1.setValues(arr,*n)
Also I tried to change it in method: void setValues(T k,int &l) and void setValues(T k,int *l)
in class: public:
T **p;
int *n; and public:
T **p;
int &n;
In my first version I have tried to use: s1.setValues(arr,6) where 6 is the length of the array. But I was also getting the error;
Edit: I had misread the type of p, and also apparently read the error backwards.
The class is intantiated with T as int. All arrays decay to pointers, so arr is of type int*. This means you cannot pass it in as the first argument of setValues.
void setValues(T k, int l);
...
s1.setValues(arr, n); //arr is type int*, but k is of type int.
I'm afraid I don't understand what your code is doing well enough to suggest how you might want to fix it, but this is why the compiler is emitting that error.
Preliminary remark: since you do not use std::set I suppose this is an exercise, and that you are not allowed to use std::vector which would considerably facilitate the management of p
The problem(s)
There are some contradictions in this code, and some more errors that do not appear yet because the corresponding template member function is not used:
The member T** p is defined as a pointer to pointer of T
In the constructor you allocate an array of pointers to T, which will give you indeed a pointer to pointers of T.
But in add() and remove() you try to reallocate p's with an array of T, which will give you a T* instead of T**. In addition you clearly want to add or remove a value and not a pointer.
But in set value, it is not clear if you want to set a single value (which the T k in the signature suggests) or if you want to set all the values from an array (which the length argumen int l suggests). Given the name of the function has Values in plural, I will assume the second alternative.
Solution Step 1: Get it to compile. But it won't really work
You need to correct:
T *p;
and adapt the constructor accordingly with p = new T[n];
auto p1 = p;
You then need to change your function definition to:
void setValues(T k[],int l) // option 1
void setValues(T *k,int l) // or option 2
The good news is that the code will then compile
The bad news is that it will not do what you want. Furthermore the code of the function and some other problems will cause UB (meaning that a lot of bad things can happen, including memory corruption, crash, etc...).
Solution Step 2: assignment of arrays, pointers and the rule of 3
This code does not what you expect it to do:
void setValues(T *k, int l)
{
p = k; // OUCH !!!!!! pointer copy and not copy of the array elements
n = l;
}
Currently, you do not copy the elements of an array, but you replace a pointer. This has following consequences:
first you will leak memory, since the pointer to the allocated memory is lost and will never be freed.
second, you will make this pointer point to an array that was not allocated with new[], which might hurt you badly when you later delete[] this pointer.
third: the array to which your class points might get deleted by the owner of the array, in which case you'd use a dangling pointer.
So you need to adapt your code as follows:
void setValues(T k[],int l) // change signature
{
if (n!=l) { // if the size is the same, we'll reuse p, if not:
delete[] p; // avoid the memory to leek
p= new T[l]; // start with a fresh memory
n = l; // define new length
}
for (int i=0; i<l; i++)
p[i]=k[i]; // copy array elements one by one
}
Another important problem is the rule of 3. This is not a problem with your current main() but quickly will become: if you work with pointers in a constructor or a destructor, you should define a copy construtor and an assignement operator. If you don't, you risk to end with shallow copies of your Set (2 different object but using the same pointer).
Solution Step 3: get rid of the remaining issues
First, your default constructor leaves p and n unitialized. They could be random value, which might cause the destructor to try to delete something that was not allocated. And the same for anny other function that assumes that things that assumed the member values would be consistend. So:
Set(){
p=nullptr;
n=0;
};
Then you have similar problems in add(), that you had in setValues() with the pointer assignment. IN addition you go out of bounds, even after the realocation: the last element of an array p with n+1 element is p[n] and not p[n+1]. I let you as an exercise to improve it.
Online demo
I am trying to make a code that tries to scan over an array for '0' using a pointer variable and then setting the address to that of the space in the array that has '0' in it. Unfortunately, my program is returning 10 as the value and 0 as an index. I would really appreciate any input to help me, and I'm trying to do this without changing main, so I dont think the following code is possible.
int* zerofinder(int array[], int q)
{
int* p = null; /// default value if there isn't a 0 in the array at
all
for (int k = q - 1; k >= 0; k--)
{
if (arr[k] == 0) // found an element whose value is 0
{
p = arr[k]; // change the value of p
break; // stop looping and return
}
}
return p;
}
Instead I think I have to use
void zerofinder(int array[], int x, int* p); function to change the pointer?
You pass the pointer by value.
Then you change where the pointer points to but that only modifies the local copy. It does not change the value of the pointer in the calling function.
You can resolve the problem using one of the following two approaches.
Pass the pointer by reference.
void findLastZero(int arr[], int n, int*& p);
Return the pointer from the function.
int* findLastZero(int arr[], int n);
This will change how you call the function. Instead of using:
int* ptr;
ptr = &nums[0];
findLastZero(nums, 6, ptr);
you can use:
int* ptr = findLastZero(nums, 6);
The problem is that you don't return the value you want from the function
int* findLastZero(int arr[], int n)
{
int* p = nullptr; /// default value if there isn't a 0 in the array at all
for (int k = n - 1; k >= 0; k--)
{
if (arr[k] == 0) // found an element whose value is 0
{
p = &arr[k]; // change the value of p
break; // stop looping and return
}
}
return p;
}
and
ptr = findLastZero(nums, 6);
Sometimes newbies think that pointers are something special, but pointers are values too, and obey the usual C++ rules about pass-by-value. If you pass a pointer to a function then changing the value of that pointer inside the function has no effect on the value outside the function, just like any other type.
This looks like a homework / test / quiz.
The answer to this quiz is: this can't be done without changing the main function.
Why?
As others have already told you, you need to change the findLastZero signature, either changing the p parameter type as int*& or int**, or return an int* from the function.
If you don't change the findLastZero signature (and the main), the findLastZero function has no way to change the outer ptr variable.
I have a multi-file program that reads data from a file and stores the values in various arrays. The size of the arrays is not known during the compiling. After the values are stored, I use another function to determine the maximum and minimum of each array and return the max/min. Before the "return maximum" statement, the values in the array are correct. After "return maximum", the values are changed or erased.
Here is some of the code including one of the 2D arrays and one of the 1D arrays (there are a few more of those but I removed them so there's less code for you to look at)
**EDITED:
FunctionValues.h: ** removed destructor block
class FunctionValues
{
//define variables, set up arrays of unknown size
public:
float **xvel;
int *imax;
int vessels;
int tot_gridpt;
public:
//Constructor -- initialization of an object performed here
FunctionValues(): xvel(NULL), imax(NULL) {}
//Destructor
~FunctionValues() {
}
void read_function(string filename);
};
FunctionValues.cpp: (this reads a file with some imax values, vessel numbers and velocities and stores them in the appropriate arrays, the other includes are also there) All the arrays made are stored in FunctionValues myval object
#include "FunctionValues.h"
using namespace std;
void FunctionValues::read_function(string filename)
{
std::ifstream myfile(filename.c_str());
//acquire variables
myfile >> vessels; //number of vessels
imax = new int[vessels];
//... code reading the file and storing them, then imax and some other values are multiplied to get int tot_gridpt
xvel = new float *[vessels];
for (int i = 0; i < vessels; i++)
{
xvel[i] = new float[tot_gridpt];
}
//arrays filled
for (int i = 0; i < limiter; i++)
{
myfile >> xvel[count][i];
}
}
Gridpts.cpp: ** range() arguments and parameters
#include "FunctionValues.h"
#include "Gridpts.h"
using namespace std;
// forward declarations
float range(float **velocities, const FunctionValues *myval, int num);
void Gridpts::create_grid(FunctionValues *myval, int ptsnum)
{
//find range, 1 for max, 0 for min from smooth wall simulation results rounded to the nearest integer
float maximum = range(myval->xvel, &myval, 1);
float minimum = range(myval->xvel, &myval, 0);
}
range.cpp: ** arguments changed to pass by pointer
float range(float **velocities, const FunctionValues *myval, int num)
{
if (num == 1)
{
float maximum = 0;
for (int round = 0; round < myval->vessels; round++)
{
for (int count = 0; count < myval->tot_gridpt; count++)
{
if (velocities[round][count] > maximum)
{
maximum = velocities[round][count];
}
}
}
maximum = ceil(maximum);
return maximum;
}
main.cpp:
corner_pts.create_grid(&myval, ptsnum);
This is where the error occurs. cout << "CHECKPOINT: " << myval.xvel[0][0] before "return maximum;" gives -0.39032 which is correct. After "return maximum", causes nothing to be printed and then the program crashes when trying run range() again using the xvel array. Similarly for myval.imax[0].
I apologize for copying in so much code. I tried to only include the essential to what is happening with the array. I have only started programming for about a month so I'm sure this is not the most efficient way to write code but I would greatly appreciate any insight as to why the arrays are being changed after returning a float. Thank you in advance for your time. (And if I have broken any rule about posting format, please let me know!)
So your program crashes when you call range() the second time. Therefore, your issue is most likely there.
Your program is crashing because you are taking your FunctionValues parameter by value, which is then destroyed at the end of the scope of the function, since it is local to the function.
// issue with myval being taken as a copy
float range(float **velocities, FunctionValues myval, int num)
{
//...
} // destructor for local function arguments are called, including myval's destructor
Explanation
Your function parameter FunctionValues myval is taken by copy. Since you have no copy constructor defined, this means that the default copy behavior is used. The default copy behavior simply copies the object data from the supplied argument at the call site.
For pointers, since they hold addresses, this means that you are copying the addresses of those pointers into an object local to the range() function.\
Since myval is local to the range() function, its destructor is called at the end of the scope of the function. You are left with dangling pointers; pointers holding the memory addresses of memory that you have already given back to the free store.
Simplified example of your error:
#include <iostream>
class X
{
public:
X() : p{ new int{ 0 } }
{
}
~X()
{
std::cout << "Deleting!" << std::endl; // A
delete p; // B
}
private:
int* p;
};
void func(X param_by_value) // C
{
// ...
}
int main()
{
X x; // D
func(x); // E
func(x); // F
}
You have variable x (D). You use it to call the function func() (E).
func() takes a parameter of type X by value, for which the variable name is param_by_value (C).
The data of x is copied onto param_by_value. Since param_by_value is local to func(), its destructor is called at the end of func().
Both x and param_by_value have an int* data member called p that holds the same address, because of 3..
When param_by_value's destructor is called, we call delete on param_by_value's p (B), but x's p still holds the address that was deleted.
You call func() again, this time the same steps are repeated. x is copied onto param_by_value. However, this time around, you try to use memory that has been given back to the free store (by calling delete on the address) and (luckily) get an error. Worse yet, when main() exits, it will attempt to call x's destructor again.
You need to do some research into function parameters in C++. Passing by value, passing by reference, passing by pointer, and all of those combined with const.
As user #MichaelBurr points out, you should also look up the rule of three (and rule of five).
I'm just wondering why you opted not to use functionality like std::max/min_element in and std::valarray/vector to allocate a contiguous chunk of memory?
Worse case scenario, if you're a fan of the explicit nature of 2d arrays x[a][b] you could create a basic matrix:
template <typename T>
class Matrix {
public:
Matrix(std::valarray<int>& dims) : dims(dims) {}
Matrix(std::valarray<int>& dims, std::valarray<T>& data) : dims(dims), data(data) {}
std::Matrix<T> Matrix::operator[](int i) {
auto newDims = std::valarray<int>(dims[1], dims.size() - 1);
auto stride = std::accumulate(std::begin(newDims), std::begin(newDims) + newDims.size(), 1, [](int a, int b){ return a * b; })
auto newData = std::valarray<T>(data[i * stride], data.size() - (i * stride));
return Matrix<T>(newDims, newData);
}
protected:
std::valarray<T> data;
std::valarray<int> dims;
}
I think more reliance on the standard libraries for their correctness will likely solve any memory access/integrity issues.
Hey I was experimenting a bit with C/C++ and pointers
while reading stuff here
I made myself a function to return a pointer to the int at some place in a global array.
int vals[] = { 5, 1, 45 };
int * setValue(int k) {
return &vals[k];
}
However I was able to do this
int* j = setValue(0);
j++;
*j = 7;
to manipulate the array
but that:
*(++setValue(0)) = 42;
din't work.
Notice however *setValue(0) = 42; works
From what I understand I call the function and get some pointer I increment it to make it point to the 2nd element in my array. Lastly I deference the pointer and assign a new value to the integer it pointed to.
I find C++ pointers and references can be somewhat confusing but maybe someone can explain me this behavior.
EDIT:
This question is NOT a duplicate of Increment, preincrement and postincrement
because it is not about pre- vs. post-increment but rather about increment on pointers that are the return of a function.
EDIT2:
Tweaking the function
int ** setValue(int k) {
int* x = &vals[k];
return &x;
}
You can use
*(++(*setValue(1))) = 42;
You can't call a unary operator (++) on something that is not a variable. setValue(0) is treated as a value.
So,
*(setValue(0)++) = 42;
should be
*(setValue(0) + 1) = 42;
This question already has answers here:
C++ trying to swap values in a vector
(5 answers)
Closed 9 years ago.
I use Visual Studio 2012. I've created my own function which works like sprintf(&a).
And i need to resolve problem: how do I swap two specific pointer elements?
Here is my code:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(vector<int>* a, vector<int>* b)
{
vector<int>* tmp = NULL;
*tmp = *a;
*a = *b;
*b = *tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(*test[0], *test[1]);
printf("%d %d", test[0], test[1]);
return 0;
}
I got an error:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
What is wrong? What i should change?
I am unsure as to what you are trying to do, but I am going to guess you are trying to swap two values in a vector. As your comments have said, using the swap would work, but I think you are confused as to what your code actually does. Let's go step by step here:
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(*test[0], *test[1]); // *test[0] is the same as *(test[0])
When you perform *test[0], this is the same as *(test[0]). This means to dereference/look at the value in memory address test[0], which is 5. That memory address is inaccessible for you, so it will cause a seg fault.
Second problem:
void swap_spec(vector<int>* a, vector<int>* b)
{
vector<int>* tmp = NULL;
*tmp = *a;
*a = *b; // This says, get whatever vector is pointed at b, and copy it to the memory location variable a points to.
*b = *tmp;
}
Since you are passing in pointers to vectors, what you're saying here is to swap the two vectors, not the values inside them. But when you call this with:
swap_spec(*test[0], *test[1]);
The type of test[0] is an int, the type of *(test[0]) is a dereferenced int (which is a seg-fault, but supposedly another int type), but the parameter type is a vector * (a pointer to a vector), which is already inconsistent with the arguments you pass in. See how this is already wrong in multiple levels.
So given all those information, it looks like you are trying to swap two values in the vector. You can do this one of two ways. You can do this with pointers:
void swap_spec(int *a, int *b) {
int tmp = *a;
*a = *b; // Go to address location where variable a points to, and assign whatever value is at memory location where variable b points to
*b = tmp;
}
swap_spec(&test[0], &test[1]); // Pass in address of where test[0] and test[1] points to
// Note that type of &test[0] is an int * (Consistent with parameter)
Or with references:
void swap_spec(int &a, int &b) {
int tmp = a;
a = b; // Since you are using references, this will actually modify test[0] at its memory location
b = tmp;
}
swap_spec(test[0], test[1]); // Since you are using references, you don't need to pass in the address.
The second way is the same as the standard library's swap (http://www.cplusplus.com/reference/algorithm/swap/). References are sometimes (or perhaps generally) favored because it produces cleaner code (less * operators used) and hence less confusion.
You declare your function to take pointers to vector<int>s as parameters but you then pass is something else. *test[1] is dereferencing test[1] which is the int 4. You are treating ints 4 and 5 as pointers which is problematic.
It is not entirely clear what you are trying to accomplish, but if you just want to swap two elements of a vector, why not something like:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(vector<int> & a, size_t i, size_t j)
{
int tmp;
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
printf("%d %d \n", test[0], test[1]);
swap_spec(test, 0, 1);
printf("%d %d \n", test[0], test[1]);
return 0;
}
Suppose what you really want do to is to swap two specific pointer elements. Then there are few possible errors. First the vector you created is an integer array instead of an pointer vector:
vector<int> test(4);
Second, in your function interface, the types of your input parameters are in fact a pointer to an integer vector (which means you would like to swap two vectors, instead of two integer pointers).
void swap_spec(vector<int>* a, vector<int>* b)
Third, since your vector is an integer vector, applying the indirection Operator * will let you get an error (*a means give me the content stored in the memory location described in variable a).
swap_spec(*test[0], *test[1]);
The following is how to swap "two integer pointers":
#include <stdio.h>
void swap_spec(int** a, int** b) // the function which swaps int pointers.
{
int** tmp;
*tmp = *a;
*a = *b;
*b = *tmp;
}
int main()
{
int** test = new int*[4]; // create an array of int integers
for (int i = 0; i < 4; ++i) {
test[i] = new int;
}
*test[0] = 5;
*test[1] = 4;
*test[2] = 3;
*test[3] = 2;
printf("%d %d\n", *test[0], *test[1]);
swap_spec(&test[0], &test[1]); // pass their addresses instead
printf("%d %d\n", *test[0], *test[1]);
for (int i = 0; i < 4; ++i) {
delete test[i];
}
delete[] test;
return 0;
}
If what you would like to do is simply swapping two int elements in a vector, then std::swap() or the answers proposed by #Narfanator and #Spook should work.
Alright, I think this should do you, but my C's a little rusty:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(int* a, int* b)
{
int tmp = NULL;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(&test[0], &test[1]);
printf("%d %d", test[0], test[1]);
return 0;
}
What I have done here is "swap the values at two memory locations", and then passed in the locations of the first and second element of your vector.
Let's go over your code, see if we can't clear some of what's going on up:
void swap_spec(vector<int>* a, vector<int>* b)
This says: Give me two pointers to vectors storing ints. When you're dealing with the elements of a vector, you just pass around the type stored in the vector: in this case, int:
void swap_spec(int a, int b)
However, C/C++ are pass-by-value, which means the passed values would be copied, and then used locally - meaning, you could not effect the overal program environment by passing in the values.
You got this, which is why you passed in pointers.
Instead, you need to pass in pointers to the values:
void swap_spec(int* a, int* b)
Technically, you're passing-by-value a memory address. Anyway - This lets you interact with memory (and this variables, objects, etc) outside of the function, in the overal program.
swap_spec(*test[0], *test[1]);
This passes in the values stored at the memory locations stored in test[0], which is invalid, because it's five.
What you want is:
swap_spec(&test[0], &test[1]);
Which pass in the memory addresses of those values, which is what you wanted.
I guess, that you want to swap elements inside the vectors, not the vectors themselves. So firstly, don't swap std::vector<int> *, but just int *.
Secondly, pointers are not needed here at all. Use a function:
void swap_spec(std::vector<int> & vec, int index1, int index2)
{
int tmp = vec[index1];
vec[index1] = vec[index2];
vec[index2] = tmp;
}
Then call it like this:
swap_spec(test, 0, 1);