Malloc () создает пространство для одной структуры, а не массива структур - PullRequest
2 голосов
/ 01 июня 2011

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

Вот в чем дело - я пытаюсь создать динамический массив C с помощью malloc (). Этот массив будет содержать структуры CGPoint, которые я начну создавать и назначать сразу после построения массива. Вот код:

CGPoint* tempVertices = malloc(sizeof(CGPoint) * 4);  //defining a collision frame
tempVertices[0] = CGPointMake(37, 46);
tempVertices[1] = CGPointMake(69, 40);
tempVertices[2] = CGPointMake(48, 6);
tempVertices[3] = CGPointMake(17, 10);

//Then I pass the pointer to my array off to a setter...
[self setVertices: tempVertices];

Однако, когда создается tempVertices, кажется, что я получаю место только для одной CGPoint:

int test1 = sizeof(CGPoint);        // 8
int test2 = sizeof(tempVertices);   // 4
int test3 = sizeof(*tempVertices);  // 8

При переходе к отладчику XCode он показывает, что tempVertices является указателем на CGPoint. Когда я устанавливаю tempVertices[0], CGPoint, на который указывает tempVertices, получает это значение, которое отражается в отладчике. Куда делись мои остальные 3 слота? tempVertices, кажется, указывает на отдельный CGPoint вместо массива. Я хочу массив.

Есть идеи, что я делаю не так? Я знаю, что есть другие способы исправить это с помощью C ++ или других объектов, но я хочу придерживаться C, если это возможно.

Заранее спасибо!


Обновление:

Чтобы ответить zpasternack, setVertices: - это пользовательский письменный установщик. И я не знаю, как / если он знает, насколько велик входящий массив. Я пытаюсь лучше понять простой язык C, поэтому очень важны идеи / объяснения относительно правильного способа передачи динамического C-массива в качестве аргумента. Вот как выглядит сеттер:

- (void) setVertices:(CGPoint*) val {
    _vertices = val;    //_vertices is a member variable of the type CGPoint* 
    //...calculate a centroid, other stuff...
}

При необходимости я мог бы обернуть мои CGPoints в объекты NSValue и использовать взамен NSArray, но я уверен, что хотел бы знать правильный способ сделать это просто C.

Спасибо всем, кто прокомментировал - вы, ребята, замечательные :) 1031 *

Ответы [ 4 ]

4 голосов
/ 01 июня 2011

На вашей 32-битной машине вы получаете именно то, что ожидаете.sizeof (tempVertices) - это размер указателя, а sizeof (* tempVerices) дает вам размер CGPint (вероятно, два целых).Вы не можете получить размер выделенного массива с помощью sizeof ().Это значение известно только во время выполнения, а sizeof () является оператором времени компиляции.

1 голос
/ 02 июня 2011

ОК, после вашего редактирования я думаю, что вижу, что происходит. Этот код, в точности как вы написали, должен работать хорошо. Xcode не будет показывать вам значения этих CGPoints, потому что он не знает, что это массив, просто указатель на одну CGPoint. Но это там. Установите точку останова сразу после вызова setVertices:. В командной строке gdb выведите некоторые из этих значений.

(gdb) print _vertices[1]
$2 = {
  x = 69, 
  y = 40
}
(gdb) print _vertices[3]
$3 = {
  x = 17, 
  y = 10
}

Правильно, понимаете?

Это не значит, что здесь нет проблем. С одной стороны, setVertices: пропускает эту память. Вы выделяете память для tempVertices, удерживаете этот указатель, но нигде не освобождаете его. В следующий раз, когда вы позвоните setVertices:, у вас будет утечка.

Еще большая проблема заключается в том, что никто не знает, сколько CGPoints содержится в этом массиве, кроме кода, который выделил для него память. Это всегда будет 4 CGPoints? Что произойдет, если кто-нибудь получит доступ к _vertices[5] или _vertices[27]? Плохие вещи, если вы не выделите им столько места.

Требуется ли, чтобы это был простой массив C? Мол, эти точки будут переданы OpenGL или cocos2d или что-то еще? Если нет, вы можете рассмотреть возможность использования некоторого класса массива для него. Поскольку эти объекты не являются производными от NSObject, вы не можете использовать NSArray. Вы можете использовать std::vector, если не возражаете против перетаскивания в кучу C ++. Я бы, наверное, этого не сделал.

Если вы настроены на привязку к массиву C, вам, вероятно, следует поработать, чтобы сделать интерфейс менее подверженным ошибкам. Как я уже упоминал ранее, вам нужно отслеживать размер массива. Возможно, вы могли бы добавить параметр в setVertices: представляющий количество CGPoints, которые содержит массив. Тогда другие части кода, которые обращаются к _vertices, могут проверить это, чтобы убедиться, что они не выходят за пределы массива. И, как я упоминал ранее, убедитесь, что вы освободили эту память, прежде чем переназначить указатель.

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

1 голос
/ 01 июня 2011

malloc выделяет достаточно места для 4 структур GCPoint и возвращает указатель на выделенное пространство.

Первый находится в tempVertices + 0. Это tempVertices [0].

Второйнаходится в tempVertices + 1. Это tempVertices [1].

Третий находится в tempVertices + 2. Это tempVertices [2].

Четвертый находится в tempVertices + 3. Это tempVertices [3].

0 голосов
/ 01 июня 2011

Я бы не использовал sizeof() для определения размера массива, выделенного во время выполнения.

Были ли у вас проблемы с назначением новых CGPoint объектов в ваш массив? CGPointMake() выполняет какое-либо собственное распределение?

...