2016-02-08 2 views
0

Итак, я пытаюсь сохранить файл PPM в управляемой программе, я успешно сохранил все до цветов, я достиг прогресса в цветах.Двумерный массив с переменным размером в C

Во время задать вопрос на переполнение стека (For loop stops for no reason) Я был убежден, что мой метод был немного дрянной, но я не понимаю, рассуждения для использования последующих:

COLOR (*colors)[width] = malloc(sizeof(COLOR[height][width])); 

кто-то может сломаться точно что делает эта строка кода и объясняет, что это за тип. Поэтому я могу сохранить его в структуре и успешно вернуть его.

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

typedef struct { 
    char code[CODE_LENGTH]; 
    COMMENT *commentPPM; 
    int width, height, max; 
    COLOR **colorValues; 
} PPM; 

с помощью:

ppmFile->colorValues = getColors(fd, ppmFile->width, ppmFile->height); 

и

typedef struct{ 
    int red, green, blue; 
} COLOR; 

COLOR * getNextColor(FILE *fd); 

COLOR **getColors(FILE *fd, int width, int height){ 
    printf("\nentered get colors"); 
    COLOR **colors = malloc(sizeof(COLOR*)*height); 
    printf("\nallocated %d space height",height); 

    int i,j; 
    for(i = 0; i < height; i++, colors++){ 
     *colors = malloc(sizeof(COLOR)*width); 
     printf("\nallocated %d space width",width); 
     for(j = 0; j < width; j++, *(colors++)){ 
      printf("\nlooping through to get the colors for point (%d,%d)", j,i); 
      //*colors = getNextColor(fd); 
     } 
     *colors -= width; 
     printf("\nmoved the pointer for *colors back %d spaces",width); 
    } 

    colors -= height; 
    printf("\nmoved the pointer for colors back %d spaces",height); 

    return colors; 
} 
+1

Я думаю, что вы правы, используя подход 2D-массива. Однако, пожалуйста, поймите, что переполнение стека не является репетиторским сервисом, ни дискуссионным форумом. У вас есть некоторые объяснения с вашим первоначальным вопросом. Это должно было быть достаточным, чтобы дать некоторые «указатели», что нужно для того, чтобы начать и как начать исследование самостоятельно. Есть достаточно книг и онлайн-учебник, которые можно найти. – Olaf

+0

Уверенный, не прося репетиторства, я просил объяснения строки кода, которая просто казалась вытащенной из ниоткуда, я искал высоко и низко, и все, что я нахожу, не имеет никакого отношения к предоставленному коду, делает этот код имеет какое-то особое имя? это на самом деле 2D-массив, вы сказали в другом вопросе, что его указатель на массив массивов, который я googled и ничего не нашел. Поэтому я подумал, что попрошу здесь, где я его нашел. – James

+0

Чтобы быть справедливым, я думаю, нам может понадобиться «канонический дубликат», объясняющий, как правильно распределить 2D-массивы динамически. Есть несколько сообщений по этой теме, но им не хватает подробных объяснений. – Lundin

ответ

2

Для того, чтобы понять это, вы должны сначала понимают понятия:

  • Указатели массива (не следует путать с указателем на первый элемент)
  • Массивы переменной длины, также известные как VLAs.

Учитывая, что уже вы знаете, что выше есть, то наиболее формально правильный способ сделать это, чтобы объявить указатель массива в 2D VLA:

COLOR (*colors)[height][width]; 

И когда вы звоните таНос, вы сказать ему, чтобы выделить достаточно места для такого массива:

malloc(sizeof(COLOR[height][width])) 

затем вы в конечном итоге с

colors = malloc(sizeof(COLOR[height][width])); 

Однако, поскольку colors в этом примере указатель массива, вы должны разыменовываются его каждый раз, когда вы хотите получить доступ к массиву:

(*colors)[i][j] = something; 

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

Таким образом, вы можете использовать другой трюк и пропустить внутреннее измерение, когда вы объявляете указатель массива. Вместо указателя на 2D массива, можно пропустить внутреннее-самое измерение и просто объявить указатель массива на 1D массив:

COLOR (*colors)[width] 

, но использовать это с тем же таНос вызова, как и раньше.Потому что теперь вы можете воспользоваться массивом указателей арифметика:

colors[i][j] = something; 

Который по существу означает, что «в моем массиве из-массивов, дайте мне номер массива i, номер позиции j».

Работает по той же причине, что и int* x = malloc(sizeof(int[n])); ... x[i] = something; работ, что, конечно же, дает int номер i.

+0

Спасибо! Именно то, что я искал! :) – James

+0

Btw это необязательно должно быть переменными аргументами/VLAs, то же самое относится, если 'height' и' width' были константами времени компиляции. Но если они являются константами времени компиляции, возможно, не имеет смысла использовать 'malloc'. – Lundin

+0

Просто уточнить: что-то вроде «арифметики указателей массива» не существует. Это обычная _pointer arithmetic_, где смещение умножается на размер объекта, на который указывает указатель. Здесь объект просто является массивом. – Olaf

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