0

So I'm making a function to differentiate a polynomial. Here's the function:

void differentiate (double coefficients[], int & degree);

void differentiate (double coefficients[], int & degree){
    int *p_n{&degree};
    int p{*p_n};
    coefficients[p]=0;
    for (int i=0;i<p+1;i++){
        coefficients[i]=(coefficients[i+1])*(i+1);
    }
}

And this is my main() function:

int main(){
    double arr[3]{3,1,5};
    std::cout<<differentiate(arr,2)<<std::endl;
}

However, when I try to use this function in my main() function, it gives me this error saying:

initial value of reference to non-const must be an lvalue

I'm pretty sure it has something to do with the pointer, but I'm not sure what.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • It should be noted that your function accesses `coefficients` out of bounds. The loop runs from 0 to `degree`, where `degree` is 2. But then the indexing adds 1. So, if `degree` is providing the maximum possible index into an array, your function is then accessing past that index in the last iteration of the loop, and you'll get undefined behavior. – paddy Nov 30 '22 at 02:41
  • Another error: you are trying to do `std::cout << differentiate(...)`, but your `differentiate` function returns `void`. You need a value to be able to `cout` it, not `void`. – heap underrun Nov 30 '22 at 02:53

1 Answers1

2

The problem is the parameter int & degree which is a reference. You cannot bind a (non-constant) reference to a literal value, which in your case is the integer literal 2 in the call:

differentiate(arr,2)

In simple terms, the use of a reference parameter allows the caller to provide a modifiable object as that parameter, and any changes to it will be reflected in the caller. The term lvalue in C++ lingo means a modifiable object. So in essence, the error message is quite specific about the problem.

To fix this, observe that you don't actually need to modify the value degree, and since it's also not a giant datatype, you don't need to pass a reference at all. Simply pass it by value:

void differentiate (double coefficients[], int degree);
void differentiate (double coefficients[], int degree){
    int *p_n{&degree};
    int p{*p_n};
    coefficients[p]=0;
    for (int i=0;i<p+1;i++){
        coefficients[i]=(coefficients[i+1])*(i+1);
    }
}

Now, let's look at the convoluted way you use degree:

int *p_n{&degree};
int p{*p_n};
for (int i = 0; i < p+1; i++) //...

This is a very roundabout way of doing this:

for (int i = 0; i < degree+1; i++) //...

So I would suggest you simplify the function to make it more readable.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • Another way to fix it is to change the reference to a const reference, which can bind to a constant – auzn Nov 30 '22 at 02:33
  • That's technically correct, but a const reference to `int` is not good style (in my opinion, and by general convention). You might end up with that kind of thing as a result of more generic code using function templates, but I think explicitly writing `const int & param` is an anti-pattern. – paddy Nov 30 '22 at 02:35
  • @paddy Can I make changes to my function code without disturbing the int & degree parameter (if possible)? – cxs sxc Nov 30 '22 at 02:37
  • Yes, you can create a variable in the caller: `int degree = 2;` and then pass it when you call the function: `differentiate(arr, degree)` – paddy Nov 30 '22 at 02:38