Search code examples
c++functionpointersreferencevoid

Exception thrown when trying to change a pointer in a void function


I am trying to make a void function where it changes the pointer that I pass. The code is throwing an exception on one of the lines and i'm not sure why. Could it be I cannot pass the arrays as pointers then implement math on it? I thought I deallocated the pointers to fix it but this seemed to not work.

Void function:

#include <iostream>
using namespace std;

void* func2(int one, double *value1[], int two, double *value2[], double  *final1) {
    double testval;
    double finalval = 0;
    //double *final1;
    double final = 0;
    for (int i = 1; i < one; i++) {
        for (int j = 1; j < two; j++) {
            testval = *value1[i] * *value2[j]; //exception thrown (works up to this point)
            finalval = testval + finalval;
        }
        final = finalval + final;
    }
    *final1 = final;
    return 0;
}

Main Function:

int main(){
    double *array1 = new double[input1];
    double *array2 = new double[input2];
//for loop that takes user input and fills in array1 and array2 with size and a list of values
...
double testval2;
func2(input1, &array1, input2, &array2, &testval2);
cout << testval2 << endl;

delete[] array1;
delete[] array2;
return 0;

I am relatively new to pointers, so my apologies if the code is a little illiterate.


Solution

  • It looks like you want to pass two 1D arrays to func2().

    One way to do that is remove the [] from the function signature as

    (int one, double *value1, int two, double *value2, double *final1)
    

    Within the function, change *value1[i] to value1[i], and similarly for value2. And remove the & when calling the function from the main().

    A couple other thoughts:

    • I'm not sure how an exception could throw from your code. But *value1[i] is definitely an invalid memory access, so what you may have seen is a segmentation fault message. A helpful tool to troubleshoot these kinds of errors is AddressSanitizer, enabled in clang or gcc by compiling with -fsanitize=address, or if you are using Xcode, there is an option for it. Another great tool is valgrind.

    • Manually allocating dynamic arrays is a pretty C-like way of using C++. In C++, it is idiomatic to create the arrays as std::vector objects, which under the hood works the same way (it also allocates a dynamic array) but has a more convenient interface. Particularly the vector cleans itself up automatically, so no need to call delete[], and the vector knows its own size, so no need to pass the size around as a separate parameter as with dynamic arrays.

    Edit: Here is a note to clarify why the original code manages to compile but fails at runtime.

    In the function signature, the combo of both * and [] on double *value1[] makes value1 a pointer to a pointer to double, equivalent to double **value1. In main(), array1 is a double*. When calling the function, &array1 takes the address of that double*, obtaining a double**. So the type matches and the code compiles.

    The code fails at runtime on *value1[i]. value1 is a pointer to pointer to doubles, where the inner pointer points to the dynamic array. So what was intended is (*value1)[i] to first dereference the outer pointer, then subscript into the dynamic array. However, in C++, subscripting (a[]) has operator precedence over dereferencing (*a), so it is read in backward order as *(value1[i]). Subscripting the outer pointer value1[i] is invalid for nonzero i, reading memory from somewhere in the stack and arbitrarily interpreting it as a double*. Then the surrounding *( ) attempts to dereference this busted pointer. The machine's memory protection catches this, and the OS sends a "SIGSEGV" signal or similar to the program to kill it.