cartesian product of two vector spaces
const-correctness
use references in favor of pointers where possible
The fact that you leave the obligation to free the memory that you allocate to the caller is generally not a good practice
a common pattern in your code is that you have pointers to arrays and their length - why not make a structure to bundle them up?
try to make use of iterators and range-based-for-loops when you don't really need the index (which you don't in your example)
since we don't really care about the type of the elements in a vector space you could use templates to generalize your algorithm

And just to see if it would be possible, I tried to come up with a compile-time version of the algorithm:
template&lt;typename T&gt;
struct pair
{
    T first;
    T second;
};

template&lt;std::size_t N, typename T&gt;
struct cvp
{
    pair&lt;T&gt; pairs[N];
};

template &lt;typename T, size_t NV, size_t NW&gt;
auto get_cvp(const T (&amp;vs)[NV], const T (&amp;ws)[NW])
{
    cvp&lt;NV*NW, T&gt; result;
    auto it_pairs = std::begin(result.pairs);
    for (const auto v : vs) {
        for (const auto w : ws) {
            *(it_pairs++) = {v, w};
        }
    }
    return result;
}

you can try the code here: https://godbolt.org/z/e8GvEf