Как я работаю с динамическими многомерными массивами в C?

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

Мой сценарий был в том, что у меня был анализатор уценки, который генерирует эти изящные списки TODO, и я хотел их стилизовать. Изменение сгенерированного HTML не было вариантом, поэтому я пришел к такому решению:

поставили флажок примерно так:

<input type="checkbox" id="cb">

Вы можете присвоить ему стиль visibility: hidden для флажка и visibility: visible на :: после, как это:

#cb {
  visibility: hidden;
}

input#cb::after {
  visibility: visible;
  content: "F";
  color: red;
  background: green;
  padding: 8px;
}

input#cb:checked::after {
  content: " T ";
  color: green;
  background: red;
}
<!doctype html>
<html>

<body>
  <input type="checkbox" id="cb">
</body>

</html>

РЕДАКТИРОВАТЬ:

@connexo в комментарии указал, что входные элементы не могут иметь контент. Это можно легко сделать с помощью элемента label, например, вот так (пожалуйста, кто-нибудь исправит меня, если это не так, у меня нет удобного браузера для тестирования).

#cb-span * {
  visibility: hidden;
}

input#cb + label::after {
  visibility: visible;
  content: "F";
  color: red;
  background: green;
  padding: 8px;
}

input#cb:checked + label::after {
  content: " T ";
  color: green;
  background: red;
}
<!doctype html>
<html>

<body>
  <span id="cb-span">
    <input type="checkbox" id="cb">
    <label for="cb"></label>
  </span>
</body>

</html>

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

Может быть, это кому-нибудь поможет (и я могу добавить это в закладки, потому что я не нашел ничего подобного в Интернете)

59
задан Jonathan Leffler 10 February 2015 в 22:45
поделиться

2 ответа

С динамическим размещением, с использованием malloc:

int** x;

x = malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = malloc(dimension2_max * sizeof(int));
}

[...]

for (int i = 0; i < dimension1_max; i++) {
  free(x[i]);
}
free(x);

Это выделяет 2D-массив размером Dimension1_max * Dimension2_max . Так, например, если вам нужен массив 640 * 480 (например, пиксели изображения), используйте Dimension1_max = 640, Dimension2_max = 480. Затем вы можете получить доступ к массиву, используя x [d1] [d2] где d1 = 0..639, d2 = 0..479.

Но поиск в SO или Google также раскрывает другие возможности, например в этом вопросе SO

Обратите внимание, что ваш массив выиграл ' • выделить непрерывную область памяти (640 * 480 байт) в этом случае, что может вызвать проблемы с функциями, которые предполагают это. Итак, чтобы массив удовлетворял условию, замените блок malloc выше следующим:

int** x;
int* temp;

x = malloc(dimension1_max * sizeof(int*));
temp = malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = temp + (i * dimension2_max);
}

[...]

free(temp);
free(x);
75
ответ дан 24 November 2019 в 18:00
поделиться

Основы

Массивы в c объявляются и доступны с помощью оператора [] . Итак,

int ary1[5];

объявляет массив из 5 целых чисел. Элементы нумеруются с нуля, поэтому ary1 [0] является первым элементом, а ary1 [4] - последним элементом. Примечание 1: инициализации по умолчанию нет, поэтому память, занимаемая массивом, может изначально содержать что-нибудь . Примечание 2: ary1 [5] обращается к памяти в неопределенном состоянии (которое может быть даже недоступно для вас), так что не делайте этого!

Многомерные массивы реализованы как массив массивов (массивов (из ...)). Итак,

float ary2[3][5];

объявляет массив из 3 одномерных массивов по 5 чисел с плавающей запятой в каждом. Теперь ary2 [0] [0] - это первый элемент первого массива, ary2 [0] [4] - последний элемент первого массива, а ary2 [2] [4] - последний элемент последнего массива. Стандарт 89-го требует, чтобы эти данные были непрерывными (раздел A8.6.2 на странице 216 моего 2-го изд. K&R), но, похоже, не зависит от заполнения.

Попытка сделать динамические данные более чем в одном измерении

Если вы не знаете размер массива во время компиляции, вам нужно динамически выделить массив. Возникает соблазн попробовать

double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */

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

double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */

, но в любом случае хитрость заключается в разыменовании времени. Вы не можете написать buf [i] [j] , потому что buf имеет неправильный тип. Вы также не можете использовать

double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */

, потому что компилятор ожидает, что hdl4 будет адресом адреса типа double. Вы также не можете использовать double incomplete_ary4 [] []; , потому что это ошибка;

Итак, что вы можете сделать?

  • Выполните арифметику строк и столбцов самостоятельно
  • Распределите и выполните работу в функции
  • Используйте массив указателей (механизм, о котором говорит qrdl)

Выполните математические вычисления самостоятельно

Просто вычислите смещение памяти для каждого элемента следующим образом:

  for (i=0; i<3; ++i){
     for(j=0; j<3; ++j){
        buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                             padding in this case */
     }
  }

Распределите и выполните работу в функции

Определите функцию, которая принимает требуемый размер в качестве аргумента, и продолжайте как обычно

void dary(int x, int y){
  double ary4[x][y];
  ary4[2][3] = 5;
}

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

Массив указателей

Рассмотрим это:

double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
   hdl5[i] = malloc(5*sizeof(double))
   /* Error checking */
}

Теперь hdl5 указывает на массив указателей, каждый из которых указывает на массив значений типа double. Интересно то, что вы можете использовать нотацию двумерного массива для доступа к этой структуре --- hdl5 [0] [2] получает средний элемент первой строки --- но это не - тем не менее, это объект другого типа, чем двумерный массив, объявленный double ary [3] [5]; .

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

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

Арифметика

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

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

Внешние продукты означают больше петель.

51
ответ дан 24 November 2019 в 18:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: