Value of array elements is different in caller and callee - c++

I have a function that passes a 2d array as an argument to another function. 2d array is passed as int**.
Caller Function:
bool isMatch(string s, string p)
{
int **dp;
int* a[s.size()];
dp = a;
for(int i=0;i<s.size();i++)
{
int b[p.size()];
dp[i] = b;
}
for(int i=0;i<s.size();i++)
{
for(int j=0;j<p.size();j++)
{
dp[i][j] = -1;
}
}
cout<<dp[0][0]<<endl;
return test(s,p,dp);
}
Calle Function:
bool test(string s,string p,int **dp)
{
cout<<dp[0][0]<<endl;
return true;
}
Now when i print dp[0][0] in isMatch() function -1 is printed which is the expected value. But when i pass the 2d array to an another function (ie; test()) and print dp[0][0] i get random values like 950192880, 337836240 etc. Why is this happenning eventhough everything passed by reference and the stack is not cleared until the caller function is exited?

array b is declared in for loop, so it's invalid out of the loop. you said that the output of dp is as expected, but it's by chance. you should allocated b using new.

Related

Merge Sort returns the same array I input

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.

Struggling to pass an array created in one function to a sort function

I am currently working on a project where we have to create an array of 1000 elements then pass it to another function to sort it. Everything I have seen online shows you how to pass it from main to another function, but not the other way around.
Please take a look at my code and help me pass Ar[1000] from Array() to ISort and ultimately main
#include <iostream>
#include <time.h>
using namespace std;
void Array()//function to make array
{
int Ar[1000];//creating array
int i = 0;//random variable to be element #
int counter = 0;// counter variable
int randnum;//variable to old random number
srand(time(NULL));//seeding rand with time
while (counter != 1000)
{
randnum = rand();
Ar[i] = randnum;
cout << Ar[i]<<endl;
counter++;
}
}
void ISort(int Ar[1000])//Iterative sort
{
int count = 0;//another counter variable
int count2 = 0;//counter variable # 3 because nested loops
int j=0;//Temp index # similar to i
int temp; //Temp variable to help switch elements
while (count != 1000)
{
if (Ar[count] < Ar[j])
{
temp = Ar[count];
Ar[count] = Ar[j];
Ar[j] = temp;
}
}
}
/*void RSort(int Ar)//Recursive sort
{
}
*/
int main()
{
Array();
ISort();
system("Pause");
return 0;
}
Ar in your Array function will be destroyed once this function finishes, you need to have a way to prevent this, one way is to pass an array by parameter instead of making it function local variable:
void Array(int* Ar, int count)//function to make array
{
I would also change Your current ISort definition to:
void ISort(int* Ar, int acount)//Iterative sort
where acount is number of elements in Ar. This is because it makes no difference whether you use void ISort(int Ar[1000]) or void ISort(int* Ar) (read here for more on this). If you want to preserve array type then you must pass it by reference using: void ISort(int (&Ar)[1000]).
Finally changes in main:
int Ar[1000];//creating array
Array(Ar, 1000);
ISort(Ar, 1000);
system("Pause");
return 0;
working code is here: http://coliru.stacked-crooked.com/a/678f581f802da85b
You also forgot to increment count inside your sorting loop.
Your array int Ar[1000] variable inside an Array() function is a local variable. Make it a global variable by moving it out of the function scope:
int Ar[1000]; //creating array
// your functions here
int main()
{
Array();
ISort(Ar);
return 0;
}
You should also modify the Array() function to accept array as parameter as pointed out in the comments below. Please note that I am omitting the array size part as it seems the number of the elements is set to 1000:
void Array(int Ar[]){
//...
};
in which case the above code would be:
int Ar[1000]; //creating array
// your functions here
int main()
{
Array(Ar);
ISort(Ar);
return 0;
}
Change the Array function declaration to:
int* Array() and make it return the array Ar. And in main get the returned value from Array function like this:
int* Ar = Array();
and pass it to the function ISort like this : ISort(Ar);.
Here is an example on SO passing an array to a function.
The easiest solution would be to change Array function a bit:
int* Array() { // change return type to be able to return array you create
int Ar[1000];
for (int i = 0; i < 1000; i++) { // much better to use for loop than while
Ar[i] = rand(); // no need to hold another variable for random number
cout << Ar[i] << endl;
}
return Ar; // return the Ar
}
int main() {
int* array = Array();
ISort(array);
}
Hope that helps. Also there are many other solutions to this but I don't know what exact restrictions your task has. If you have any questions feel free to ask.
EDIT: So I totally forgot about that C arrays are just a plain old pointers... Well then the solution would be like this:
void Array(Ar[1000]& array) { // pass array to the function with reference
for (int i = 0; i < 1000; i++) { // much better to use for loop than while
array[i] = rand(); // no need to hold another variable for random number
cout << array[i] << endl;
}
}
int main() {
int[1000] array = Array();
ISort(array);
}
Sorry for the error but using C style arrays really isn't common in C++ when you can use vectors and maps.

Trailing return type array

auto function(int i) -> int(*)[10]{
}
Can anyone help me how to return a pointer to array of 10 integers using trailing return type? Any example will be helpful.
If you don't care whether your return value is dereferenceable (and you didn't specify that), the following will "return a pointer to an array of 10 integers":
auto function(int i) -> int(*)[10]
{
return nullptr;
}
First you need to decide where the integers will be stored, how they'll be "shared", and whether the caller or callee is responsible for their lifetime.
Options include...
1) returning a pointer to newly dynamically allocated memory:
auto function(int i) -> int(*)[10] {
int* p = new int[10];
p[0] = 1;
p[1] = 39;
...
p[9] = -3;
return (int(*)[10])p;
}
// BTW it's usually cleaner (avoiding the ugly cast above) to handle
// arrays via a pointer (but you do lose the compile-time knowledge of
// array extent, which can be used e.g. by templates)
int* function(int i) {
int* p = ...new and assign as above...
return p;
}
// either way - the caller has to do the same thing...
void caller()
{
int (*p)[10] = function();
std::cout << p[0] + p[9] << '\n';
delete[] p;
}
Note that 99% of the time returning either a std::vector<int> or a std::array<int, 10> is a better idea, and that 99% of the remaining time it's better to return a std::unique_ptr<int[]> which the caller can move to their own variable, which will delete[] the data as it is destroyed by going out of scope or - for member variables - destruction of containing object.
2) returning a pointer to a function()-local static array (which will be overwritten each time function is called, such that old returned pointers will see the updated values and there could be race conditions in multithreaded code):
auto function(int i) -> int(*)[10]{
static int a[10] { 1, 39, ..., -3 };
return &a;
}
The caller calls this the same way, but must not call delete[].
#include <iostream>
const size_t sz = 10;
auto func(int i) -> int(*)[sz] /// returns a pointer to an array of ten ints
{
static int arr[sz];
for (size_t i = 0; i != sz; ++i)
arr[i] = i;
return &arr;
}
int main()
{
int i = 2;
int (*p)[sz] = func(i); /// points to an array of ten ints which funct returns which is arr array
for (size_t ind = 0; ind != sz; ++ind) /// displays the values
std::cout << (*p)[ind] << std::endl;
return 0;
}
auto function (int i) -> int(*)[sz]
this means that a function name funct have a parameters of int that accepts
an int argument and return a pointer to an array of 10 ints which means
that we pointed every int element in an array of ten int. trailing return types are used for to read easily
to return a pointer to an array of ten int
int i = 2;
int (*p)[sz] = funct(i);
which means (*p)[sz] will pointed an array of 10 ints that a func function
returns which is arr array and displays the values using loop

After passing by reference to modify an array, why it stays the same?

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<>!

Array passed as arguement to a function showing garbage values

here's the code:
int *num_arr = number_to_array(num);
cout<<"\nNum aaray:"<<*(num_arr+1);
display(num_arr, digit_count);
The cout statement here is showing the correct value, but display() is not. display is showing garbage values
code for display():
void display(int num_arr[],int dc)
{
cout<<"\n";
cout<<"\n"<<num_arr[0];
cout<<"\n"<<num_arr[1];
for(int i = (dc-1); i>=0; i--)
{
cout<<num_arr[i];
}
}
int* number_to_array(int num)
{
int i=0;
int num_arr[100]; // make dynamic array
while(num!=0)
{
num_arr[i] = num%10;
num = num/10;
i++;
}
return num_arr;
}
what could be the reason?
You are returning address of local variable (name of array is address of it's first element). It is mistake, because array will not exists after you exit a function.
int num_arr[100]; // make dynamic array - it is static array, not dynamic.
Possible solutions:
(Prefferable) Use std::vector
Use dynamic arrays (int *p = new int[100])
Proposal - learn basics of C/C++: pointers, arrays, function arguments and return values.