2014-11-03 6 views
0

Код ниже печатает адреса динамически распределенного массива. Печатные адреса становятся немного разными, когда начинается новая строка. Если я использую статический массив, адреса будут точно такими же, и элементы массива идут один за другим. В чем причина?Разница между одиночными указателями и массивами с двумя указателями

void func(int* a, int** b) 
{ 
    for (int i = 0; i < n; i++) 
    { 
     for (int j = 0; j < n; j++) 
     { 
      cout << &a[i * n + j]<< " " << &b[i][j]<< endl; 
     } 
     cout << endl; 
    } 
} 

int main() 
{ 
    int** a; 
    a = new int*[n]; 
    for (int i = 0; i < n; i++) 
    { 
     a[i] = new int[n]; 
    } 
    func(a[0], a); 

ответ

0

Разница между одним указателем и дважды массивы указателей

Вы можете увидеть разницу в коде:

int** a;   // a is a pointer of type int** 
a = new int*[n]; // a points to an array of pointers of type int* 

И:

for (int i = 0; i < n; i++) 
{ 
    a[i] = new int[n]; // a[i] points to an array of ints 

Там у вас есть Это.

Печатные адреса при изменении новой строки начинают несколько отличаться. Если я использую статический массив, адреса будут точно такими же, и элементы массива идут один за другим.

Предположительно, вы говорите о статическом массиве массивов и сравниваете его с массивом указателей, которые у вас есть.

Элементы массива выделяются непрерывно в памяти. В случае массива статических массивов элементы внешнего массива являются статическими массивами, и они хранятся непрерывно в памяти. В случае массива указателей элементы внешнего массива являются указателями, и они также хранятся непрерывно в памяти. Массивы int, которые вы динамически распределяете с другой стороны, не сохраняются во внешнем массиве. Там, где они хранятся, определена реализация и обычно не связана с расположением массива, содержащего указатели.

также:

cout << &a[i * n + j]<< " " << &b[i][j]<< endl; 

Здесь вы обращаетесь за пределы массива, на который указывает аргумент a который указываемой a[0] в main и имеет длину n, которая меньше, чем i * n + j когда i является ненулевая. Результатом является технически неопределенное поведение, и печатные адреса наиболее определенно не относятся к элементам массивов, которые вы выделили.

+0

Благодарим за сообщение! – Vasily

+0

Благодарим за сообщение! Да, но есть ли байты после каждой строки, выделенной случайным образом? Если я изменил тип массива, то я мог видеть, что их число фиксировано до 8 + sizeof (type). И у меня 64-битная система, так что это может быть что-то вроде sizeof (pointer) + sizeof (type)? – Vasily

+0

@Vasily Если я правильно вас понимаю, вы спрашиваете об относительном расположении каждого динамически выделенного массива в памяти. Такие детали не указаны стандартом и не соответствуют реализации компилятора. – user2079303

0

Это то, как вы создали свою матрицу. Нет оснований полагать, что a[0] + 1 * n + j равно a[1] + j. a[0] и a[1] были выделены независимо.

Вот способ получить всю матрицу сразу.

int** a = new int*[n]; // allocate the row indexes 
a[0] = new int[n * n]; // allocate the entire matrix 
for (int i = 1; i < n; i++) 
{ 
    a[i] = a[0] + i * n; // assign the row indexes. NOTE: a[0] is already assigned. 
} 

Используя это распределение, a[0] + 1 * n + j равно a[1] + j.


Статические массивы неявно выделяют распределение всей матрицы, поэтому ваш код работает для них.

0
Code below prints addresses of dynamically allocated array. 
Printed addresses become slightly different, when new line starts. If 
I use static array, addresses are exactly the same, and array elements 
are going one after another. What's the reason? 

Причина в том, что следующий вызов будет генерировать новый адрес каждое время она называется, и нет никакой гарантии, что адрес будучи смежным. a [i] = новый int [n];

В то время,

INT в [10] [20]

который представляет собой статический массив будет иметь непрерывное распределение памяти.

+0

'int a [10 \ [20];' не обязательно является статическим. Если это локальная переменная, она автоматическая, а не статическая. –

+0

@JamesKanze не * static * in * static array * в этом контексте используется для обозначения * length *, являющегося статическим (compiletime), а не динамическим (runtime)? В том же смысле, что и 'statc_assert' является компилятором' assert'? Вместо того, чтобы ссылаться на тип распределения. У меня было такое впечатление. – user2079303

+0

@ user2079303 Если это так, это запутанное использование, поскольку в C++ статичность имеет определенное значение при применении к переменной. –

0

Вы используете две конфликтующих реализации в вашем моделировании матрицы: в main, можно использовать массивы массивов, с каждой строкой в ​​ отдельной памяти; и в func вы принимаете одиночный плоский массив из rows * columns элементов, отображающих два индекса на один. Вы должны выбрать тот или другой.

В C++, конечно, вы должны написать класс Matrix, чтобы инкапсулировать этот выбор. Например, если вы хотите единственный плоский массив (обычно предпочтительно), вы бы написать что-то вроде:

class Matrix 
{ 
    int myRowCount; 
    int myColumnCount; 
    std::vector<int> myData; 
public: 
    Matrix(int rows, int columns) 
     : myRowCount(rows) 
     , myColumnCount(columns) 
     , myData(rows * columns) 
    { 
    } 

    int& operator()(int row, int column) 
    { 
     assert(row >= 0 && row < myRowCount 
       && column >= 0 && column < myColumnCount); 
     return myData[row * myColumnCount + column]; 
    } 

    int const& operator()(int row, int column) const 
    { 
     assert(row >= 0 && row < myRowCount 
       && column >= 0 && column < myColumnCount); 
     return myData[row * myColumnCount + column]; 
    } 
}; 

Вы обратите внимание, что я использовал std::vector вместо того, чтобы делать какие-либо динамическое распределение сам. В этом случае разница не огромна, но на практике опытный программист на C++ не использовал новый массив, за исключением исключительных случаев; один иногда удивляется, почему это даже на языке.

Вы также заметите, что я перегрузил оператора () для индексации . Вы не можете предоставить два индекса для [], и это одно из решений этой проблемы. В качестве альтернативы operator[] возьмет один индекс и вернет прокси-объект , который также примет один индекс. Хотя это решение , которое я предпочитаю, это сложнее.

Смежные вопросы