Why is it that if I have a function like this, to swap two numbers, it doesn't work[swap], (I know I can do this by declaring pointers in the prototype, and then pass the address of the respective variables in main()), but works for array, without having to pass pointers and addresses.
Doesn't work
void num_exchange(int m, int n);
int main(){
int num1 = 5;
int num2 = 6;
num_exchange(num1 , num2 );
cout << "num1 =" << num1 << endl;
cout << "num2 =" << num2 << endl;
return 0;
}
void num_exchange(int m, int n){
int temp;
temp = m;
m = n;
n = temp;
}
Works
void arr_exchange(int [], int);
int main(){
int n[7] = { 0, 0, 0, 0, 0, 0, 0 };
arr_exchange(n, 7);
for (int i = 0; i < 7; i++)
cout << n[i] << " ";
return 0;
}
void arr_exchange(int x[], int){
for (int i = 0; i < 7; i++)
x[i] = 1;
}
void num_exchange(int m, int n){
int temp;
temp = m;
m = n;
n = temp;
}
modifies copies of the input integers. To make your code work use
void num_exchange(int& m, int& n){
int temp;
temp = m;
m = n;
n = temp;
}
instead (note the & in the first line). This is called passing by reference. In general, use std::swap to swap things.
void arr_exchange(int x[], int){
for (int i = 0; i < 7; i++)
x[i] = 1;
}
works because in C++
void arr_exchange(int x[], int){
is equivalent to
void arr_exchange(int* x, int){
So here a pointer is passed and thus the original data is modified.
Your num_exchange() takes its arguments by value, i.e., it sees copies of the original value. When you swap them, the copies are swapped but the originals are not touched. When you swap arrays, instead a pointer to the array start is passed (built-in arrays are never copied directly in C++). Since the pointer references the original array rather than a local copy, swapping array elements results in a change visible even when the function is exited.
To pass the actual original objects to your num_exchange() function you'd either use pointers, too, or you'd use references, e.g.:
void num_exchange(int& m, int& n) {
// ...
}
Of course, the easiest approach to swapping elements is to use the standard or type provided swap() function although it is, admittedly, a bit awkward to use due to the extra using-directive:
using std::swap;
swap(num1, num2);
Functions are by default call by value.
what happens when a function call occurs???
When a function call occurs address of next instruction in program is pushed onto stack which tells the compiler where to return after function execution following that the function arguments(5 and 6) are pushed onto stack.
Inside function, these arguments are popped out of stack i.e. m=5,n=6 this means the actual arguments(num1,num2) are unaltered.
The function then executed with aliases of num1(i.e. m) and num2(i.e. n) after execution the address is popped out of stack to continue execution from where it is left.
In C, solution to this problem is to pass address of num1, num2 and use pointers to inside function to point them.
CPP added new concept called reference.A reference is another name given to the variable.
int & n1 = num1;
int & n2 = num2;
why it works with arrays??
Copying whole array is not feasible hence arrays are always pass by reference.The base address of array is passed to function hence whatever modifications done to the array in the function affects the real array.
the code you are loking for need two pointers because the function will copy the data you give them so:
void swap (int * a, int * b){
int temp = *a;
*a = *b;
*b = temp;
}
Related
I implemented a mergesort algorithm but it returns the exact same array I pass as an input. The following is the code. I am suspecting the pseudocode that our professor gave us is wrong. But I am not sure. I have tried to implement is as best as I can.
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
double* merge(double* b, double* c, int N) {
int i = 0;
int j = 0;
double* result = new double[N];
for(int k = 0; k < N; k++) {
if ((i < len(b)) && (j >= len(c) || b[i] <= c[j])) {
result[k] = b[i++];
} else {
result[k] = c[j++];
}
}
return result;
}
void merge_sort(double* a, int N) {
if (N >= 2) {
int mid = (N+1)/2;
double *left = new double[mid];
double *right = new double[mid];
for (int i = 0; i < mid; i++) {
left[i] = a[i];
}
for (int j = 0; j < mid; j++) {
right[j] = a[mid + j];
}
merge_sort(left, mid);
merge_sort(right, mid);
a = merge(left, right, N);
}
}
Any help would be really appreciated.
In the last line, you assign your result to the local var a, which is then lost. You need to return a, or pass the input as a reference/pointer, otherwise any changes are only to the local copy.
Arguments in the function are basically local variables, they behave like any local variable in this function, except their initial value is set by code that calls this function. a is a pointer that stores the address of first element of your double array.
As it's a local variable, you can modify it but when the function ends, it will be discarded like all other local variables of the function.
There are several ways to deal with this problem, each with their own up and downsides. The most obvious is to return final value of a when you're done sorting. You could also pass a pointer TO a pointer to this function, and then you would be able to modify the pointer outside the function:
void function(int** argument){
*argument = another_function();
}
, but that severely restricts the source of your input. It no longer could be a local array passed by address like this:
int x = 10;
int *y = &x; // if this is what you want to change
function(&y); // this works
// now x is still 10, y points to a different place in memory which can store a different value
int x[1]; // if you would like to change this array in place though...
function(x); // this is how you would call the function, but it would fail because it can't change the address that x refers to
You main issue is here:
// You pass in a pointer to the data here.
// the parameter `a` holds a pointer to the data.
void merge_sort(double* a, int N) {
if (N >= 2) {
// STUFF
// Here you write over `a` (which is fine)
// BUT: You don't pass the value back.
// So the caller never knows what the new value is.
a = merge(left, right, N);
}
}
To fix this. I think it is a mistake to allocate a new array in merge(). Rather re-use the array you have. You have already copied the data into left and right to be sorted. The merge should merge the data back into the original array a.
// Change this:
a = merge(left, right, N);
into
merge(a, left, right, N);
Now in merge() you can use a as the destination.
void merge(double* result, double* b, double* c, int N)
// No longer need to allocate space for result now.
There are a couple of other issues:
1: What do you need len() for?
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
You should already know the length of all parts you should not be re-measuring it. Also this function is completely wrong (the double array is not \0 terminated).
2: The length of b and c is not obvious.
double* merge(double* b, double* c, int N) {
You get the wrong value because you call len() which is not correct.
You could calculate from N but that has issues in that you need to make sure both you merge functions use exactly the same method and that is error prone in the long run. I would personally pass the size of each array as parameters to the function.
3: You leak your intermediate arrays!
You call new to allocate storage.
double *left = new double[mid];
double *right = new double[mid];
But you don't deallocate these objects so they are leaked (for every call to new there should be a corespodning call to delete).
Overall. You can solve a cople of issues by using more C++ style techniques (rather than the C style you are using). Iterators and std::vector spring to mind.
I am a C++ beginner and my task is as follows:
Define and initialise a single-dimensional integer array. Next, define a pointer that points to the first element in the array and passes the pointer to a function.
Using only pointer variables (and looping constructs), print only the array values that are exact multiples of 7 from start to finish to standard output. The only program output should be the numbers, one per line with no white space.
I have tried:
void print_sevens(int* nums, int length)
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
int* num = array;
for (int i = 0; i < length; i++)
{
*num++;
if (num[i] % 7 == 0) {
cout << num[i] << endl;
}
}
}
int main()
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
print_sevens(ptr, 5);
}
It compiles but does not output anything.
I am also confused about passing the pointer to a function. Should this be done in the main file or in the function file?
You are creating an additional array in the print_sevens function, which is unnecessary as you already passed the pointer to the first element of the array created in the main()(i.e. array).
Removing that unnecessary array and related codes from the function will make the program run perfectly. (See online)
void print_sevens(int* nums, int length)
{
for (int i = 0; i < length; i++)
{
if (nums[i] % 7 == 0)
std::cout << nums[i] << std::endl;
}
}
and in the main you only need to do the follows, as arrays decay to the pointer pointing to its first element.
int main()
{
int array[5]{ 5,8,21,43,70 };
print_sevens(array, 5);
}
Note that,
num++ increments the pointer, not the underline element it is
pointing to (due to the higher operator precedence of operator++ than operator*). If you meant to increment the element(pointee) you
should have (*num)++.
Secondly, do not practice with using namespace std;. Read more:
Why is "using namespace std;" considered bad practice?
You are modifying the contents of your array when you do *num++.
I need to implement a function that modifies an array. The new array may be a different size. cout prints 1. I understand what's wrong with this code but I just cannot figure out what the syntax is.
//tried this..
int reduce(int *array[])
{
*array = new int[1];
(*array)[0] = 6;
return 0;
}
//also tried this..
int reduce(int array[])
{
array = new int [1];
array[0] = 6;
return 0;
}
int main()
{
int a[1] = {1};
int *p = a;
reduce(&p);
cout << a[0];
return 0;
}
Don't understand your question correctly, but this is what you may do:
void reduce(int *a, int size)
{
for (int i =0; i < size; ++i) {
*(a+i) = 6; // or whatever value to want to
}
}
Call it this way:
int main(){
int a[5] = {1, 1, 1, 1, 1};
int *p = a;
reduce(p, 5);
for (int i =0; i < 5; ++i) { cout << a[i]<<endl; }
return 0;
}
EDIT
What you are trying to do can be vaguely done this way:
int * reduce (int **b, int size) {
*b = new int[size];
for (int i =0; i < size; ++i) {
*(*b + i) = 6;
}
return *b;
}
int main(){
int a[5] = {1, 1, 1, 1, 1};
int *p = a;
p = reduce(&p, 5);
cout << p[0];
cout << p[1];
cout << p[2];
cout << p[3];
cout << p[4];
delete [] p;
return 0;
}
But it still wont change where a is pointing to.
What you are trying to do is not possible with statically defined arrays.
When you use an array like
int a[1] = {1};
you cannot change the size of the array at run time, you cannot make it point to dynamically allocated memory. You may only access and modify the elements the array. That's it.
The function reduce changes where p points to but it does not change the elements of a.
If you want to modify the contents of a, you can simply use a as an argument, and set the values.
MODIFIED:
You want to modify array a, try this :
int reduce(int **array)
{
*array = new int[1];
(*array)[0] = 6;
return 0;
}
int main()
{
int *a = new int[1];
reduce(&a);
cout << a[0];
return 0;
}
First of all, the formal parameter int* array[] actually is the same as int** array (you can think of it as a two-dimensional array). This is probably not what you want.
The answer of #everettjf will only work if you do not change the size of the array. A possible solution (that completely replaces the array) would be
#include <iostream>
void print_array(int[],int);
int* reduce(int array[]) {
// get rid of the old array
delete[] array;
// create a new one
array = new int[7]{8,4,6,19,3,56,23};
// need to return the new address, so that
// the main function is informed on the new
// address
return array;
}
int main() {
// initialize array
int *a = new int[1]{4};
print_array(a,1);
// "change" array by completely replacing it
a=reduce(a);
print_array(a,7);
return 0;
}
// simply prints out the array; no error checking!
void print_array(int array[], int length) {
std::cout << "[";
for (int i = 0; i < length ; ++i) {
std::cout << array[i] << " ";
}
std::cout << "]" << std::endl;
}
In the reduce function, the initial array is completely deleted. Afterwards, you can create a new one (I chose to just use 7 random numbers). It is important to return that pointer back to the caller (the main method). Otherwise the a pointer in the main method would point to invalid
If you are not forced (by some kind of excercise, for example) to use arrays, you should look into http://en.cppreference.com/w/cpp/container/vector
The premise of your question is invalid. It is not possible to resize an array of automatic storage duration (aka a in main()) after its definition by ANY means in standard C++.
Dynamic memory allocations in either of your reduce() functions will not cause a in main() to be resized.
reduce(&p) will calls the first version of reduce() , which will then change p (so it points at the dynamically allocated memory) but not affect a.
If main() calls reduce(a) or reduce(p) (the two are equivalent, given the initialisation int *p = a) will change neither a nor p, but instead cause a memory leak.
The underlying problem, I suspect, is that you believe - incorrectly - that pointers and arrays are the same thing. They are actually different things, but can be used in the same way in various contexts. And your code is one of the contexts in which they cannot be used interchangeably.
If you want a resizeable array, use a static container (like std::vector<int>) and - if you want a function to resize it, pass it by reference. It manages its own memory dynamically, so is able to dynamically resize itself.
I am practicing pointers by creating a Big Number struct, which has numDigits (number of digits) and digits (contents of the big number).
I create a function called removeZero(). After passing the integer array and the size n into it, because of passing by reference, I am supposed to cut down the leading zeros for my input. It works, when the integer array is in main function. However, when I pass an array that is in readDigits, it does not return with a non-leading-zero version. Why? How to fix it?
struct BigNum{
int numDigits;
int *digits; //the content of the big num
};
int main(){
int A[] = {0,0,0,0,0,0,1,2,3};
int n=9;
int *B=A;
//removeZero(A,n); If I use this, it cannot compile
//error: invalid initialization of non-const reference of type ‘int*&’ from an rvalue of type ‘int*’
removeZero(B,n);
for (int i=0; i<n; i++){
std::cout << *(B+i) << std::endl;
}
BigNum *num = readDigits();
return 0;
}
BigNum* readDigits(){
std::string digits;
std::cout << "Input a big number:" << std::endl;
std::cin >> digits;
//resultPt in heap or in stack?
int *resultPt = new int[digits.length()]; //in heap
int n = digits.length();
toInt(digits,resultPt);
removeZero(resultPt,n);
//Output the leading zeros, why?
for (int i=0; i<n; i++){
std::cout << *(resultPt +i) << std::endl;
}
BigNum *numPtr = new BigNum();
numPtr->numDigits = n;
numPtr->digits = resultPt;
return numPtr;
}
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
void removeZero(int* &A,int& n){
int i=0;
while (A[i]==0){
i++;
}
A=A+i; //memory leak?
n=n-i;
}
bool areDigits(std::string num){
for(int i=0;i<num.length();i++){
if(num[i]<'0' || num[i] >'9'){
return false;
}
}
return true;
}
Note that an array and a pointer are two different things. When you pass an array to a function, it degrades to a const pointer. This means that you cannot pass an array to a function which expects a int*&.
It could be the problem of scope of numPtr.numPtr is local variable of function readDigits(). Instead of returning pointer. Pass num to readDigits().
The signature of your removeZero function is:
void removeZero(int* &A,int& n);
That means the forst parameter is a reference of a pointer but the pointer is a non-const one, and you cannot therefore pass an array there, as array is a constant pointer (starting address cannot be changed).
In fact you are changing the starting address within removeZero.
With removeZero, the while loop shopuld be changed from:
while (A[i]==0){
to:
while ((A[i]==0) && (i<n)){
You have a logic error in toInt.
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
// This stores the digits in the reverse order.
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
That line should be
result[i] = (int)(str[i]-'0');
If you intend to keep the digits in reverse order, then removeZero has to be changed keeping that in mind.
`
When you say
int *B=A;
you are just creating a pointer to point to the same memory
of the Array A. Just by incrementing the pointer(*B) within the function
removeZero
A=A+i;
you are not deleting anything but you are just incrementing the pointer(*B)
to point to subsequent memory location within the array.
The original array memory pointed to by A remains the same, since you
have not changed any contents of the array, but you have just
incremented a pointer pointing to the same memory location as that of the array.
Also there are so many problems, like "Debasish Jana" mentioned,
you have to change your while loop. ""Code-Apprentice" gave you the reason for your
compilation error when you uncomment your commented code.
Also within "removeZero" you are incrementing A by i instead of "1" like
A=A+1;
This is one of the reason for the strange behavior you experience
Even after changing all this, you cannot see your array getting changed,
since you are not modifying any of the contents of your array.
If you really want to delete the contents of the array and change it dynamically,
you have to go for Vector<>. With static memory allocation you cannot cut the
array size short by removing some elements here and there. Learn Vector<>!
I am trying to code a class that represents a set of integers. It's a homework assignment but for the life of me I cannot figure out this issue.
In the class "IntSet", I have two private variables; one is a pointer to an array the other is the size of the array. I can create objects of this class and they work as intended. But I have this function named "join" that returns an object of the IntSet class. It essentially concatenates the arrays together then uses that array to create the returning object.
Here is my code:
#include <iostream>
using namespace std;
class IntSet {
int * arrPtr;
int arrSize;
public:
//Default Constructor
IntSet() {
int arr[0];
arrPtr = arr;
arrSize = 0;
}
//Overloaded Constructor
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
//Copy Constructor
IntSet(const IntSet &i) {
arrPtr = i.arrPtr;
arrSize = i.arrSize;
}
/*
* Returns a pointer to the first
* element in the array
*/
int* getArr() {
return arrPtr;
}
int getSize() {
return arrSize;
}
IntSet join(IntSet &setAdd) {
//Make a new array
int temp[arrSize + setAdd.getSize()];
//Add the the values from the current instance's array pointer
//to the beginning of the temp array
for (int i = 0; i < arrSize; i++) {
temp[i] = *(arrPtr + i);
}
//Add the values from the passed in object's array pointer
//to the temp array but after the previously added values
for (int i = 0; i < setAdd.getSize(); i++) {
temp[i + arrSize] = *(setAdd.getArr() + i);
}
//Create a new instance that takes the temp array pointer and the
//size of the temp array
IntSet i(temp, arrSize + setAdd.getSize());
//Showing that the instance before it passes works as expected
cout << "In join function:" << endl;
for (int j = 0; j < i.getSize(); j++) {
cout << *(i.getArr() + j) << endl;
}
//Return the object
return i;
}
};
int main() {
//Make two arrays
int arr1[2] = {2 ,4};
int arr2[3] = {5, 2, 7};
//Make two objects normally
IntSet i(arr1, 2);
IntSet j(arr2, 3);
//This object has an "array" that has arr1 and arr2 concatenated, essentially
//I use the copy constructor here but the issue still occurs if I instead use
//Inset k = i.join(j);
IntSet k(i.join(j));
//Shows the error. It is not the same values as it was before it was returned
cout << "In main function:" << endl;
for (int l = 0; l < k.getSize(); l++) {
cout << *(k.getArr() + l) << endl;
}
return 0;
}
The program compiles and the output as of now is:
In join function:
2
4
5
2
7
In main function:
10
0
-2020743083
32737
-2017308032
I don't know why but the 10 and 0 are always the same every time I recompile and run. Also, if I print out the address of the pointer rather than the value(in both the join function and the main function), I get the same memory address.
Sorry if I misuse terms, I come from a java background, so pointers and such are a little new to me. If any clarification is needed, please ask.
Thanks in advance.
int temp[arrSize + setAdd.getSize()];
This is a local array, its lifetime ends once the function returned.
IntSet i(temp, arrSize + setAdd.getSize());
Here you are constructing an IntSet with this array. In fact the constructor simply changes a member pointer to the value of temp:
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
As a result, since the lifetime of the object that temp and consequently also i.arrPtr is pointing to ends after leaving join, you will have a wild pointer. Dereferencing this pointer later in main invokes undefined behavior.
You need to allocate the array dynamically with new[] and delete it later with delete[]. The same goes for your constructors. Also note that if you use new[] in join and delete[] in the destructor, then you also have to make sure that the copy constructor actually copies the array (create new array with new[] and copy contents). If you simply assign the pointer then both the source and destination object will point to the same array and they will also both try to delete it at deconstruction, again invoking undefined behaviour.
But since this C++, you might as well use a std::vector which does all of this for you. (or std::set if you actually want a integer set)
The quickest fix with your code is to change
int temp[arrSize + setAdd.getSize()];
into this
int * temp = new int[arrSize + setAdd.getSize()];
The thing is that you allocated temp on the stack, so when join() returns that memory is releases. By allocating memory on the heap (as per the fix) the memory is not released when join() returns.
There are other things wrong with your code -- depending on the point of the assignment. I think most of these will be fixed when you consider the implications of having memory on the heap.