C ++ - Указатели на массивы - Массивы указателей - PullRequest
3 голосов
/ 02 декабря 2009

Я заметил, что это вызвало замешательство у нескольких человек, но после прочтения нескольких постов здесь и учебника по cplusplus мой мозг все еще болтается.

Предположим, у меня есть следующие переменные в заголовочном файле -

int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is

Затем в файле реализации C ++ я инициализирую их следующим образом -

//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints];   //array of pointers?

Что теперь представляет моя строковая переменная?

Насколько я могу судить по чтению ссылок на stackoverflow, он должен представлять собой массив указателей. Затем я прочитал следующее, однако ...

(1) Указатели для начинающих

... где (A) массивы указателей и (B) указатели на массивы, оба обсуждаются. Это снова смутило меня, так как они оба работают одинаково.

Тот факт, что я определяю свои указатели в отдельном месте, куда я их размещаю (правильно?), По-видимому, является источником моей путаницы. Правильно ли, что это массив указателей на объекты D3DXVECTOR3?

Завершить - если переменная строка содержит информацию об одном отрезке, как мне создать массив отрезков? В настоящее время у меня есть следующее -

//HEADER FILE
int numberOfLineSegments;
D3DXVECTOR3** lineCollection;   //array of pointers - each of which
                                //points to an array of pointers?
//CPP FILE
numberOfLineSegments = 8;                            //constructor
for(i = 0; i < numberOfLineSegments; i++)            //initialization
{                                                    //and allocation  CORRECT?
   lineCollection[i] = new D3DXVECTOR*[numPoints];   //of memory for     Y/N
}                                                    //lineCollection

VOID createLineSegments(startPoint, endPoint) //could return array instead
{
//pseudo to generate one line segment
while != numberOfLinePoints
line[sentinel++] = interpolate(startPoint, endPoint, time_T)

//pseudo to generate array of line segments
while != numberOfLines
lineCollection[sentinel++] = line
}

Любая помощь очень ценится.

Ответы [ 6 ]

4 голосов
/ 02 декабря 2009

Ваш первый пример:

int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is

Объявляет простой указатель на D3DXVECTOR3. Указатель может быть инициализирован двумя способами. Во-первых:

line = new D3DXVECTOR3;

Это создает один D3DXVECTOR3 и указывает линию на этот объект. Во-вторых:

line = new D3DXVECTOR3[numberOfLinePoints];

Это создает массив D3DXVECTOR3s и указывает линию на первый элемент этого массива. Затем вы можете использовать арифметику указателей для доступа к другим элементам в этом массиве.

Если вы объявите свой указатель как двойной указатель:

D3DXVECTOR3** line;

Вы просто создаете другой уровень косвенности.

3 голосов
/ 02 декабря 2009

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

C ++ (и C) использует указатели на один элемент в массиве как дескриптор для полного массива. Однако некоторые указатели не указывают на элементы в массиве! Вы должны провести различие между точками на один элемент и точками на элемент в массиве.

int length = 8;
D3DXVECTOR3* line = new D3DXVECTOR3[length];

Оператор new [] возвращает указатель на первый элемент в массиве, который он выделяет, и это присваивает это значение строке. Обратите внимание: поскольку указатели не делают различий между отдельными элементами и элементами в массиве:

  • Вы должны хранить длину отдельно
  • Вы должны быть осторожны, вы используете правильные индексы с указателями ("строка" выше)
  • вам лучше использовать "настоящий" тип контейнера, такой как:
    • std :: deque, std :: vector и т. Д.
    • std :: tr1 :: array (он же boost :: array)

(Последний пункт не означает, что вы никогда не используете указатели, вы просто не используете их, когда эти контейнеры более подходят.)

3 голосов
/ 02 декабря 2009
int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is
//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints];   //array of pointers?

line - это массив D3DXVECTOR3. Однако, если указатель D3DVECTOR3 сам по себе является указателем, это будет массив указателей. Поскольку я не очень хорошо знаю заголовки C ++ D3D, я не уверен.

D3DXVECTOR3** lineCollection;

Массив указателей, каждый из которых, вероятно, является указателем на строку (то есть массив D3DXVECTOR3).

У вас есть два варианта. По памяти лучше всего установить каждую запись в lineCollection так, чтобы она указывала на соответствующую строку. Это безопасно, если вы знаете, что строки не изменятся (и не будут освобождены), или если они действительно изменятся, вы хотите, чтобы эти изменения немедленно отражались в вашей коллекции.

Другой вариант - создать новый массив для каждой записи в lineCollection и скопировать точки из каждого line в этот новый массив.

Правильного ответа нет, это зависит от желаемой функциональности.

2 голосов
/ 02 декабря 2009
D3DXVECTOR3 line; // Line is a D3DXVECTOR3
D3DXVECTOR3 * line; // Line is EITHER a pointer to D3DXVECTOR3 OR an
                    // array of D3DXVECTOR3
D3DXVECTOR3 ** line; // Line is an array of pointers to D3DXVECTOR3 OR
                     // an array of array of D3DXVECTOR3

Это потому, что массив не имеет определенной структуры в памяти. Это просто куча D3DXVECTOR3 в ряд. Таким образом, указав на первый элемент, вы получите доступ ко всем остальным.

Итак, имея

D3DXVECTOR3** lineCollection; // An array of pointers OR an array of array!
new D3DXVECTOR[numPoints]; // A pointer to an array of D3DXVECTOR
lineCollection[i] // A pointer to an array

Вы инициализируете это следующим образом:

lineCollection[i] = new D3DXVECTOR[numPoints]; // No extra *

Еще: попробуйте использовать STL (например, std :: vector) вместо уродливых массивов в стиле C / Java. Если можете, избегайте объявления в куче (используя 'new'), а вместо этого в стеке:

D3DXVECTOR a, b, c; // a, b, and c ARE D3DXVECTOR, not pointers
std::vector<D3DXVECTOR> lines;
lines.push_back(a);
lines.push_back(b);
lines.push_back(c);

// equivalently: (you can push_back without temporaries)
std::vector<D3DXVECTOR> lines;
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());

Это позволит избежать ручного управления памятью; это более читабельно. Возможно, вы не всегда сможете использовать этот комфорт (способ организации вашего кода). И если кто-то что-то говорит о выступлениях, не волнуйтесь. Сначала получите что-нибудь работающее без ошибок и утечек памяти.

1 голос
/ 02 декабря 2009
line = new D3DXVECTOR3[numPoints];

line содержит адрес памяти первого элемента массива D3DXVECTOR3.

т.е. line - указатель на первый элемент массива.

Эта статья должна разъяснить это.

0 голосов
/ 02 декабря 2009

Просто посмотрите на этот простой пример:

дело 1:

int *p = new int [N];

Здесь p - указатель на массив из N целых чисел, а p хранит начальный адрес массива.

дело 2:

int **p = new int *[N]; //p is a pointer to pointers holding integers used for 2D array.


for(int i=0 ; i<N ; i++)
{

    p[i] = new int [N]; // each element is pointer to array of integers.

}

Это применимо ко всем видам пользовательских типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...