Passing pointer to an array into a function (C++) - c++

I'm trying to pass an array into my function calls for build_max_heap and max_heapify so I can modify the array after each call, but I receive an error saying "candidate function not viable: no known conversion from 'int [9]' to 'int *&'for 1st argument."
#include <iostream>
#include <string>
using namespace std;
void build_max_heap(int*& array, int size);
void max_heapify(int*& array, int size, int index);
void build_max_heap(int*& array, int size)
{
for(int i = size/2; i>=0; i--)
{
max_heapify(array, i);
}
}
void max_heapify(int*& array, int size, int index)
{
int leftChild = 2*index+1;
int rightChild = 2*index+2;
int largest;
int heap_size = size;
if( leftChild <= heap_size && array[leftChild] > array[index])
largest = leftChild;
else
largest = index;
if(rightChild <= heap_size && array[rightChild] > array[largest])
largest = rightChild;
if(largest != index) {
int tempArray = array[index];
array[index] = array[largest];
array[largest] = tempArray;
max_heapify(array, heap_size, largest);
}
}
int main()
{
int array[]={5,3,17,10,84,19,6,22,9};
int size = sizeof(array)/sizeof(array[0]);
build_max_heap(array, size);
return 0;
}

int array[]={5,3,17,10,84,19,6,22,9};
While array can be decayed to a pointer int* to be passed as a function argument, it the pointer cannot be passed as a "non-const reference" int*&, because it is immutable (it is a constant address). You could have passed it as a const reference like this:
void max_heapify(int* const& array, int size, int index)
// ^^^^^^
However, this doesn't make much sense, you can simply pass the pointer by value (a copy of the address of the array), which results in the same: the variable at the caller wont be changed. The usual use case of const& parameters is to pass objects that are expensive to copy, such as std::string. This does not apply to pointers; making a copy of a pointer is as cheap as copying any basic variable.
You should change your functions to take the pointer by value:
void build_max_heap(int* array, int size)
void max_heapify(int* array, int size, int index)
also, correct the call to max_heapify inside build_max_heap, give it the correct number of arguments:
void build_max_heap(int* array, int size)
{
for(int i = size/2; i>=0; i--)
{
max_heapify(array, size, i); // <-- 3 arguments
}
}

Related

Data in int* argument of function not returned caller

Compiled with g++ on WSL2, sample output of
#include <stdlib.h>
#include <stdio.h>
#include <vector>
using std::vector;
vector <int> powers_2(const int npow) {
vector <int> v;
int j = 2;
for (int i=0; i<npow; i++) {
v.push_back(j);
j*= 2;
}
return v;
}
void pow_2(const int npow, int *v, int *nv) {
vector <int> w = powers_2(npow);
*nv = w.size();
v = (int*)malloc(*nv * sizeof(int));
for (int i=0; i<*nv; i++) {
v[i] = w[i];
printf("%d %d %d\n",i,v[i],w[i]);
}
}
int main() {
int *y;
int ny;
pow_2(3,y,&ny);
printf("\n in main\n");
for (int i=0; i<ny; i++) {
printf("%d %d\n",i,y[i]);
}
}
is
0 2 2
1 4 4
2 8 8
in main
0 1
1 0
2 1091723517
So the argument int* v is set in pow_2, but the data is not returned to caller. Why?
There is a difference between passing function arguments by value, by pointer and by reference.
The line
pow_2(3,y,&ny);
will pass the value of y to the function pow_2, which means that a copy of the value of the variable y will be made, which will exist as the local variable v in the function pow_2. This is not what you want, because changing the variable v in the function pow_2 will only change that variable, but it won't change the value of the original variable y in the function main.
What you instead want is to pass the variable y itself to the function pow_2, not its value, so that it can be changed by the function pow_2. There are two ways of doing this. You can pass the variable y
as a reference, or
as a pointer
to the function pow_2.
To make the function pow_2 take a reference to an int * instead of the value of an int *, you can change the line
void pow_2(const int npow, int *v, int *nv) {
to:
void pow_2(const int npow, int * &v, int *nv) {
Alternatively, you can make the function pow_2 take a pointer to an int * instead of the value of an int *. You can change the line
void pow_2(const int npow, int *v, int *nv) {
to
void pow_2(const int npow, int **v, int *nv) {
However, this will require you to rewrite the function pow_2 so that the pointer is deferenced whenever it is used:
void pow_2(const int npow, int **v, int *nv) {
vector <int> w = powers_2(npow);
*nv = w.size();
*v = (int*)malloc(*nv * sizeof(int));
for (int i=0; i<*nv; i++) {
(*v)[i] = w[i];
printf("%d %d %d\n",i,(*v)[i],w[i]);
}
}
Also, you will have to call the function differently. You will have to change the line
pow_2(3,y,&ny);
to:
pow_2(3,&y,&ny);
Therefore, passing the variable as a reference is easier than passing it as a pointer.

C++ collect2: error: ld returned 1 exit status

I tried to make a program to insert a data into an array and I wanted to do it using pointers so that I can create a new array and make use of pointers to point to it simply. But I got a error and other SO questions didn't helped.
CODE:
#include <iostream>
using namespace std;
bool insert(int arr[], int size, int elem, int pos);
int main()
{
// Create a array
int arrayData[] = {0, 3, 4, 3};
int *arrptr = arrayData;
int size = sizeof(arrayData) / sizeof(*arrayData);
int elem = 6, pos = 3;
// insert the element to position pos
insert(arrptr, size, elem, pos);
return 0;
}
bool insert(int *arr[], int size, int elem, int pos)
{
int newArray[size + 1];
for (int i = 0; i < size + 1; i++)
{
if (i < pos)
{
newArray[i] = *arr[i];
}
else if (i == pos)
{
newArray[i] = elem;
}
else
{
newArray[i] = *arr[i - 1];
}
}
*arr = newArray;
return true;
}
ERROR:
/tmp/ccwuU0I9.o: In function `main':
arrayInsertion.cpp:(.text+0x61): undefined reference to `insert(int*, int, int, int)'
collect2: error: ld returned 1 exit status
These two declarations
bool insert(int arr[], int size, int elem, int pos);
^^^^^^^^
and
bool insert(int *arr[], int size, int elem, int pos)
^^^^^^^^^
differ.
Also variable length arrays
int newArray[size + 1];
is not a standard C++ feature.
And this statement
*arr = newArray;
does not make sense because the variable arr is a local variable of the function. Its changing does not have effect on the passed argument.
You have initially to allocate the source array dynamically.
And the array will be enlarged without adding new values if the given position is greater than the current size of the initial array.

C++ dynamic array, increasing capacity

I'm trying to implement a dynamic array and here is my function for increasing the capacity
int* changeCapacity(int *arr, int length, int newCapacity) {
int *newArr = new int[newCapacity];
if(length > newCapacity){
return 0;
} else {
for(int i = 0; i < length; i++){
newArr[i] = arr[i];
}
delete[] arr;
arr = newArr;
return arr;
}
}
This is the error i get:
speicher(2465,0x7fff7cfc2310) malloc: * error for object 0x7f9742403910: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
i'm calling it like this:
int* addElement(int *arr, int& length, int& capacity, int val){
if(length >= capacity){
capacity = capacity * 2;
changeCapacity(arr, length, capacity);
arr[length] = val;
length += 1;
return arr;
}else{
arr[length] = val;
length += 1;
return arr;
}
}
I assume that your problem must come from two things IMO :
First:
changeCapacity(arr, length, capacity);
arr[length] = val;
Here you doesn't get the new arr value (returned by changeCapacity()).
So your function addElement() will return Wrong pointer and on your next addElement() that will do free memory corruption.
Why do you have to get the new arr value?
You do the same as here
a = 1;
changeVar(a);
// value of a here?
int changeVar(int a)
{
a = 5;
return (a);
}
How will be the value of a? 1 because the argument of changeVar is a local variable.
Second:
You give a NULL value on your addElement() function.
Right now you are changing the address of arr, in which you have to pass the pointer by reference. Do this:
int* changeCapacity(int *&arr, int length, int newCapacity)
This is somewhat a guess based on the error message, but you have shown:
int* addElement(int *arr, int& length, int& capacity, int val)
{ //...
changeCapacity(arr, length, capacity);
//...
}
which calls:
int* changeCapacity(int *arr, int length, int newCapacity)
{ //...
delete[] arr;
//...
}
However, the original source of the arr argument to addElement() is unknown given the code you have posted so far. Are you by chance doing something like this:
foo()
{ int array[N];
//...
addElement(array, ...);
//...
}
or maybe calling addElement() with a global array variable? In either of those cases, the original array is not allocated via a new[] to match the delete[], and this would appear to be what the runtime library is complaining about. The value of the pointer stated in the error message tends to make me think it was allocated on the stack initially.
Of course the other issues, like not capturing the return value of changeCapacity() and/or addElement(), and the possibility that changeCapacity() might return a NULL pointer are still valid as well, and should be fixed.
Here is a better way of doing it. Everything is well explained in the comments for anyone who wants to learn:
#include <iostream>
using namespace std;
int* changeCapacity(int *arr, int length, int newCapacity);
int* addElement(int *arr, int& length, int& capacity, int val);
int main(){
int length = 0; // no inital elements in array
int capacity = 1; // initial capacity is one
int* arr = new int[capacity]; // allocating space for values
int* temp; // pointer for storing temporary values
/* loop for adding elements to the array */
for(int i=0;i<21;i++){
temp = addElement(arr,length,capacity,i); // adding an element to the array
if(temp == NULL) { // checks if execution was successful
cout<< "NULL returned...\n Exiting Now...";
return 0; // exits the program on failure
}
arr = temp; // changing the value of arr
}
/* loop for printing the array */
for(int i=0;i<length;i++){
cout<<arr[i]<<" ";
}
return 0;
}
/* function for increasing the capacity of array */
int* changeCapacity(int *arr, int length, int newCapacity) {
int *newArr = new int[newCapacity]; // definging a new array
if(length > newCapacity){ // checking if the length of the array is valid
cout<< "invalid length of array\n";
return NULL;
} else {
/* loop for transferring values to the new array */
for(int i = 0; i < length; i++){
newArr[i] = arr[i];
}
delete[] arr; // deleting the old array (clears the memory of the old array)
// arr = newArr; removed as this is not needed
return newArr; // returns the new array
}
}
/* function for adding a new element to the array */
int* addElement(int *arr, int& length, int& capacity, int val){
if(length >= capacity){ // checks if the array has space for storing the given value or not
capacity = capacity * 2; // doubles the capacity of the array
int* temp = changeCapacity(arr, length, capacity); // changes the size of the array to the new one
if(temp == NULL){ // checking if a null was returned
cout<< "Failed to change capacity\n";
return NULL; // returning NULL
}
arr = temp; // the value of arr was not changed in your code (problem corrected)
arr[length] = val; // stores the value in the array
length += 1; // increasing the number of element count of the array
return arr; // returns the new array
}else{
arr[length] = val; // stores the value in the array
length += 1; // increasing the number of element count of the array
return arr; // returns the new array
}
}

Passing a pointer by reference

#include <iostream>
using namespace std;
void merge(int *& toMerge, int lo, int mid, int hi)
{
int merged[hi+1];
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++)
{
if (i > mid) {merged[k] = toMerge[j]; j++;}
else if (j > hi) {merged[k] = toMerge[i]; i++;}
else if (toMerge[j] < toMerge[i]) {merged[k] = toMerge[j]; j++;}
else {merged[k] = toMerge[i]; i++;}
}
toMerge = merged;
}
int main(int argc, const char * argv[])
{
int x[8] = {1,7,4,6,2,7,3,2};
merge(x, 0, 7, 3);
return 0;
}
I am trying to pass a pointer by reference here such that the end result will be that the array x will be sorted. However, my compiler is throwing an error that there is no matching function call for the merge(x, 0, 7, 3).
I am not sure as to why this is happening because the merge function requires a pointer, and x is a pointer to the first element in the array -- so it should work. Why doesn't it?
An array decays to a pointer when you pass it as an argument to a function call but not to a reference to a pointer.
Imagine this:
void foo(int*& p)
{
p = new int;
}
int main()
{
int arr[6] = {0};
foo(arr);
// You don't want arr to be an invalid object here.
// If the compiler allowed you to do that, that's what will happen.
// Not only that, foo(arr); is equivalent to:
// arr = new int;
// which is not allowed in the language.
}
You really should NOT pass a reference, because you don't really want merge changing the value of the pointer. You just want to allow it to change the values stored in the array, which it can do without the reference (i.e., just from the pointer).

Returning an integer array

This is one the methods that I have to make for my assignment
int*mode(int &) – returns an integer array containing the modal value(s) of the
population, the reference parameter should be set to the size of the result
But from searching, you cannot return array's from a function? I can calculate modal value from a given array, put it in an array, but return an integer array? maybe the professor meant something else? I know how to do all other methods except that one. I don't even know what that method means (Coming from java)
Header File
#include <string>
using namespace std;
class population
{
public:
//Default Constructor
population(void);
//Constructor that accepts an integer array object, and the size for that array object
population(int[], int);
//Constructor for creating a deep copy
population (const population &);
//For overloading purposes
population & operator = (const population &);
//Destructor that frees dynamic memory associated with the underlying array
~population(void);
//Method for loading new content into an array
void load(string);
//Method for adding new content into existing array
void add(string);
//Accessors
//Returns the size of the population (The number of values stored in the array)
int size();
//Returns the sum of the popluation (The sum of the contents in the array)
int sum();
//Returns the mean of the population
float mean();
//Returns the median of the population
float median();
//Returns the standard deviation of the population
float stddev();
//Returns an integer array containing the modal values of the popluation
int*mode(int &);
private:
int arraySize;
bool sorted;
int * popArray;
};
CPP
#include "population.h"
//Default Constructor
population::population(void)
{
}
//Constructor to intialize the population object
population::population(int arr[], int s)
{
//Store s into a variable
arraySize = s;
//Declare popArray as a Dynamic array
popArray = new int[arraySize];
//Copy the passed array into the popArray
for ( int i=0; i < s; i++)
{
popArray[i] = arr[i];
};
}
//Constructor for deep copying purposes
population::population (const population & p)
{
}
population::~population(void)
{
}
int population::size(void)
{
//Return size of the array, which is the amount of population in the array.
return arraySize;
}
int population::sum(void)
{
//Variable to hold sum of the array
int sumArray = 0;
//Add all the contents of the array into one variable
for ( int i = 0; i < arraySize; i++)
{
sumArray += popArray[i];
}
//Return the sum of the array
return sumArray;
}
float population::mean(void)
{
//Variable to hold sum and the mean of the array
int sumArray = 0;
float meanArray;
//Add all the contents of the array into one variable
for ( int i=0; i < arraySize; i++)
{
sumArray += popArray[i];
}
//Sum of the array divided by number of contents in the array (Average)
meanArray = (sumArray / arraySize);
//Returns mean value in type float
return meanArray;
}
float population::median ()
{
return 1;
}
float population::stddev()
{
return 1;
}
int population::*mode(int & i)
{
return
}
With a prototype like that, I'm guessing that he wants you to new an array to be returned:
int *population::mode(int & i)
{
// compute the number of modal values you need to return
i = /* whatever the size of the return array will be */;
int * ret = new int[i];
// fill in ret
return ret;
}
Try:
int foo(int arrayBar[])
or
int foo(int* arrayBar)
or
int* foo(int arrayBar[])
If those don't work, make sure your pointer is at the beginning of the array.
Source: Return array in a function