2013-11-21 2 views
2

Меня интересуют различные способы выделения памяти в куче для двумерных массивов.Распределение памяти для указателя на массив и указатель на указатель

Похоже, что при доступе к указателям на указатели и указатели на массивы одного или нескольких измерений используется одно и то же обозначение. Я надеялся, что кто-то разъяснит разницу и полезность каждого из них. Они оба правы?

Это первый способ будет хранить массив как указатель на указатель:

char **createTable(int r, int c) { 
    char **table; 
    int i; 
    char *offset; 
    table = malloc(r * sizeof (char *) + r * c * sizeof (char)); 
    if (!table) return NULL; 
    offset = (char *) table + sizeof (char *) * r; 
    for (i = 0; i < r; i++) { 
     table[i] = offset + c * i; 
    } 
    return table; 
} 

Этот другой путь кажется быстрее. Я не могу придумать хороший способ обернуть его в функцию, подобную другой.

char (*table)[c]; 
table = (char (*)[c]) calloc(r * c, sizeof (char)); 

Am I прямо в понимании того, что даже если массивы как статические указатели, массивы имеют возможность иметь несколько измерений сами по себе?

Верно ли, что первый способ, который я описываю, является православным способом?

+1

Оба, кажется, делают то же самое. Второй, безусловно, более изящный. –

+0

Почему не просто 'char table [r] [c]'? Думаю, ваше намерение состоит в том, что можно будет вернуть указатель из функции, которая его выделяет? Возможно, было бы полезно сделать это ясным в вопросе, чтобы мы знали, почему вы не просто выполняете 'char table [r] [c];' –

+0

Чтобы быть более конкретным: вы не можете вернуть 'table', где' table 'is' char (* table) [c]; 'от функции, которая возвращает' char ** '.Clang: 'несовместимые типы указателей возвращают 'char (*) [c]' из функции с типом результата 'char **'' –

ответ

1

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

#include <stddef.h> 
#include <stdlib.h> 

void* createTable_(size_t r, size_t c) { 
    char (*table)[c] = malloc(sizeof(char[r][c])); 
    /* do the intialization that you need */ 
    return table; 
} 

#define createTable(R, C) ((char(*)[C])createTable_((R), (C))) 

int main(int argc, char*argv[]) { 
    char (*table)[argc] = createTable(argc, argc); 
} 

Функция просто возвращает указатель void* и макрос обеспечивает правильный ввод. К сожалению, такой макрос должен дважды оценить второй аргумент, поэтому будьте осторожны с побочными эффектами.

Edit, для других вспомогательных вопросов, которые Вы задаете:

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

  • Это склонность к ошибкам. Вам действительно нужно получить все вычисления индекса справа. Кстати там же вы можете получить что-то более удобное для чтения с помощью sizeof массивов, что-то вроде

    malloc(sizeof (char*[r]) + sizeof (char[r][c]))

  • Это тратит впустую пространство, то sizeof(char*[c]) части

  • Он менее эффективен, вместо простых расчетов индекса он должен сделать дополнительную косвенность.

  • Это несовместимо с другими языками, которые используют множество матриц, таких как Fortran.

+0

Это отличный ответ для той части, на которую вы отвечаете, но часть сравнения двух подходов будет оценена по достоинству. – niic

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