0

I am learning c++ pointers. I wrote some code to see if I understood correctly.

It might look a little weird. I made it a little complex on purpouse. Could you please tell me If I understood correctly? Or if there is something wrong that I didn't understand?

#include <iostream>

using namespace std;

int main()
{
    int **x = new int*[20];
    *x      = new int [5]; //x[0] ==>[0,0,0,0,0]
    *(x+1)  = new int [3]; //x[1] ==>[0,0,0] 

    *x[0]     = 10; //x[0][0] = 10
    *(x+1)[0] = 20; //x[1][0] = 20

    cout << x[0][0] << endl;
    cout << x[1][0] << endl;

    delete [] *x;
    delete [] *(x+1);
    delete [] x;

    return 0;
}
Rahal
  • 21
  • 2
  • 1
    It looks like you understand what you did. – NathanOliver Aug 13 '18 at 16:48
  • When used with pointers, `arr[x]` is equivalent to `*(arr + x)` and `arr[0]` is equivalent to `*arr`. I see nothing wrong here except mixed styles. – alter_igel Aug 13 '18 at 16:48
  • all fine except nobody would write code like this now. Normal case is to use std::vector – pm100 Aug 13 '18 at 16:49
  • ...or `std::array`. – Max Langhof Aug 13 '18 at 16:50
  • 3
    We have got no idea what you understood. The posted code is free from undefined behavior, and code matches comments. This is as much as I can tell. – SergeyA Aug 13 '18 at 16:51
  • If anything, I would strongly advise, while trying to understand what you apparently wrote, how the operators work. Specifically their precedence. See more about [operator precedence in C++ **here**](https://en.cppreference.com/w/cpp/language/operator_precedence). It may surprise you. – WhozCraig Aug 13 '18 at 16:52

3 Answers3

4

Due to operator precedence, the lines

*x[0]     = 10;
*(x+1)[0] = 20;

are equivalent to

*(x[0])     = 10;
*((x+1)[0]) = 20;

I am not sure whether you meant that. IMO, it will be better to use:

(*x)[0]     = 10;
(*(x+1))[0] = 20;
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • I meant the last one. Because What I wanted to say is that x[0][0] = 10 and x[1][0] = 2. I have to work on operator precedence as WhozCraig advised – Rahal Aug 13 '18 at 16:58
2

As best as I'm able to determine, your code is correct with respect to what your comments expect is happening, prevents memory leaks, and is free of Undefined Behavior, which is all fine and good.

But consider, for a second, how much unnecessary boilerplate code you had to write to make this work. And then consider the following code using std::unique_ptr, which is exactly identical to your code in terms of behavior, but removes the boilerplate that is responsible for deleting the memory, by using a class which handles that behavior automatically:

#include<memory>

int main()
{
    auto x = std::make_unique<std::unique_ptr<int[]>[]>(20);
    x[0] = std::make_unique<int[]>(5); //x[0] ==>[0,0,0,0,0]
    x[1] = std::make_unique<int[]>(3); //x[1] ==>[0,0,0] 

    *x[0]     = 10; //x[0][0] = 10
    //This will no longer compile because, while technically correct, this kind of pointer arithmetic
    //is inherently unsafe and prone to mistakes
    //*(x+1)[0] = 20; //x[1][0] = 20
    x[1][0] = 20;

    cout << x[0][0] << endl;
    cout << x[1][0] << endl;

    //No more deletes needed; `std::unique_ptr` manages its own memory and deletes when needed

    return 0;
}

Now consider the next code, which simplifies further by using a more robust idiom for dynamically-sized arrays, std::vector:

#include<vector>

int main()
{
    std::vector<std::vector<int>> x(20);
    x[0].resize(5); //x[0] ==>[0,0,0,0,0]
    x[1].resize(3); //x[1] ==>[0,0,0] 

    x[0][0] = 10;
    x[1][0] = 20;

    cout << x[0][0] << endl;
    cout << x[1][0] << endl;

    return 0;
}

This is a pretty clear case-study in why, for most purposes, you should prefer things like std::unique_ptr<T[]> or std::vector<T> for describing "Arrays of T". And for 2d arrays, std::unique_ptr<std::unique_ptr<T[]>[]> or std::vector<std::vector<T>>, which describe the same semantics as your original code.

Xirema
  • 19,889
  • 4
  • 32
  • 68
0

The only incorrect thing is, new int[] does not initialize its memberes. After *x=new int[5], x can be {123,456,789,-123,-456} or anything else.

user31264
  • 6,557
  • 3
  • 26
  • 40