-1

The marked line in hadamard_product() gives a segmentation fault in the following source code.

#include <iostream>
#include <cstdlib>
#include <ctime>

class Vector
{
private:
    int length;
    float * elements;
    bool is_column;//column-vector = single column, multiple rows.
                   //row-vector = singl row, multiple columns.
public:
    Vector()
    {
        this->length = 0;
        elements = NULL;
        is_column = true;
    }
    void set_length(int length)
    {
        this->length = length;
        elements = new float[length];
    }
    void set_row_vector(bool is_row)
    {
        is_column = !is_row;
    }
    float get_length() const
    {
        return length;
    }
    // Copy constructor
    Vector(const Vector& other)
    {
        this->length = other.length;
        this->elements = new float[length];
        for (int i = 0; i < length; i++) 
        {
            this->elements[i] = other.elements[i];
        }
    }
    // Destructor
    ~Vector()
    {
        this->length = 0;
        if (elements != NULL) 
        {
            delete[] elements;
        }
    }
    
    Vector Clone() const
    {
        Vector v(*this);
        return v; 
    }

    // Overloaded assignment operator
    Vector& operator=(const Vector& other)
    {
        if (this != &other) 
        {
            this->length = other.length;
            delete[] this->elements;
            this->elements = new float[length];
            for (int i = 0; i < length; i++) 
            {
                this->elements[i] = other.elements[i];
            }
        }
        return *this;
    }
    float& operator[](int index)//will modify the state of the object 
                                //when assigned a value
    {
        return elements[index];
    }
    bool operator==(const Vector& other) const//this function will not modify the state 
                                                //of the object on which it is called
    {
        if (this->length != other.length) 
        {
            return false;
        }
        for (int i = 0; i < this->length; i++) 
        {
            if (this->elements[i] != other.elements[i]) 
            {
                return false;
            }
        }
        return true;
    }   
    void scalar_product(float scalar)
    {
        for(int i=0 ; i<length ; i++)
        {
            this->elements[i] = this->elements[i] * scalar;
        }
    }
    friend Vector operator*(float scalar, const Vector& vec)
    //Vector operator*(float scalar, const Vector& vec) const
    {
        Vector result(vec);
        result.scalar_product(scalar);
        return result;
    }
    void display() const
    {
        if (length == 0) 
        {
            std::cout << "[]" << std::endl;
            return;
        }
        
        if (is_column)
        {
            std::cout << "[";
            for (int i = 0; i < length - 1; i++)
            {
                std::cout << elements[i] << std::endl;
            }
            std::cout << elements[length - 1] << "]" << std::endl;
        }
        else
        {
            std::cout << "[";
            for (int i = 0; i < length - 1; i++)
            {
                std::cout << elements[i] << " ";
            }
            std::cout << elements[length - 1] << "]" << std::endl;
        }       
    }

    bool is_column_vector() const
    {
        return is_column;
    }
    
    float dot_product(const Vector& other) const//inner product
    {
        if (!(!this->is_column && other.is_column_vector()))
        {
            throw std::runtime_error("Error: lhs must be row vector, rhs must be column vector");
        }
        
        if (this->length != other.length) 
        {
            throw std::runtime_error("Error: Vectors must have the same length to perform Dot product");
            return 0.0;
        }
        float result = 0.0;
        for (int i = 0; i < this->length; i++) 
        {
            result += this->elements[i] * other.elements[i];
        }
        return result;
    }
    
    void hadamard_product(const Vector& rhs, Vector ** returns)
    {
        if (!(this->is_column && !rhs.is_column_vector()))
        {
            throw std::runtime_error("Error: rhs must be a row-vector");
        }

        if (this->length != rhs.length)
        {
            throw std::runtime_error("Error: Vectors must have the same length to perform Hadamard product");
        }

        *returns = new Vector[this->length];//<<<segmentation fault
        int index = 0;
        for (int i = 0; i < this->length; i++)
        {
            Vector temp = rhs.Clone();
            temp.display();
            float val = this->elements[i];
            temp.scalar_product(val);
            
            (*returns)[index] = temp;
            index++;
        }
    }
};

int main()
{
    float array[] = {1.0, 2.0, 3.0};
    
    Vector u;
    u.set_length(3);
    u[0] =-6;
    u[1] = 1;
    u[2] = 4;
    u.display();
    
    Vector v;
    v.set_length(3);
    v.set_row_vector(true);
    v[0] = 3;
    v[1] =-5;
    v[2] = 2;
    v.display();
    
    try 
    {
        Vector ** returns;
        u.hadamard_product(v, returns);
        //for (int i=0 ; i<u.get_length() ; i++)
        //{
        //  returns[i]->display();
        //  delete returns[i];
        //}
        //delete[] returns; // free memory
    } 
    catch (std::exception& e) 
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

What am I going wrong, and how can I fix it?

user366312
  • 16,949
  • 65
  • 235
  • 452
  • 1
    Well: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three?r=Saves_AllUserSaves ? – πάντα ῥεῖ Mar 30 '23 at 11:09
  • 3
    There are several issues in your code. E.g.: `set_length` will leak the previous `elements` if existed. Why don't you use `std::vector` for managing the data ? – wohlstad Mar 30 '23 at 11:10
  • 1
    You're passing an uninitialized pointer to `hadamard_product`, which you immediately dereference. You need to pass it the address of an existing `Vector*`. (Or return it from the function. There is no obvious point to that argument.) – molbdnilo Mar 30 '23 at 11:12
  • 1
    Typo. Should be: `Vector* returns;` `u.hadamard_product(v, &returns);`! – Marek R Mar 30 '23 at 11:14
  • 1
    there are too many pointers in your code. – 463035818_is_not_an_ai Mar 30 '23 at 11:15
  • Fixed version: https://godbolt.org/z/bxfTec4WK – Marek R Mar 30 '23 at 11:16
  • On another note, the `Clone()` function serves no apparent purpose. `Vector temp = rhs.Clone();` achieves exactly the same as `Vector temp = rhs;`, but with more code. – molbdnilo Mar 30 '23 at 11:17
  • 2
    Managing raw pointers correctly is hard. Don't do it! Use the appropriate c++ standard containers or smart pointer implementations instead. These are already optimized, beyond your understanding of optimizations so far. _@user366312_ – πάντα ῥεῖ Mar 30 '23 at 11:18
  • 2
    Also, a *scalar product* is the product of two vectors, not the scaling of one vector. – molbdnilo Mar 30 '23 at 11:24

1 Answers1

2

You want to allocate stack space for a pointer to Vector, then send a pointer to that pointer on the stack. Currently you are allocating pointer to pointer to Vector on the stack and then dereferencing it in the hadamard_product function which obviously segfault.

You want Vector *returns; u.hadamard_product(v, &returns);

odyss-jii
  • 2,619
  • 15
  • 21