Похоже я не совсем понимаю что из себя представляют двумерные (n-мерные) массивы в C++, чем они являются для оперативной памяти и чем двумерный массив объявленный на стеке вот таким образом:
RGBQUAD frameBuffer[300][300];
отличается от динамически объявленного двумерного массива:
RGBQUAD ** frame = new RGBQUAD*[height];
for (uint32_t i = 0; i < height; i++)
{
frame[i] = new RGBQUAD[width];
std::fill_n(frame[i], width, clearColor);
}
Теперь немного о самой задаче
Решил я попробовать написать что-то вроде software-renderera, начать решил с самого базового - точки (а именно вывода ее на экран). В WinAPI конечно же есть средства для рисования и установки цвета отдельных пикселей, но после небольшого ковыряния данной темы, я понял что правильным подходом будет именно подготовка кадра как bitmap картинки, а затем показ данной картинки на окне. То есть по задумке у меня будет формироваться bitmap, который я буду с определенной частотой показывать на окне, таким образом получив что-то вроде анимации. Сам по себе показ картинки у меня осуществляется примерно вот так:
// Cоздать временный bitmap (4 байта на пиксель), последний параметр типа void*
// Это может быть как одномерный так и двумерный массив структур RGBQUAD
HBITMAP hBitMap = CreateBitmap(width, height, 1, 8 * 4, pixels);
// Получить device context окна
HDC hdc = GetDC(hWnd);
// Временный DC для переноса bit-map'а
HDC srcHdc = CreateCompatibleDC(hdc);
// Связать bit-map с временным DC
SelectObject(srcHdc, hBitMap);
// Копировать содержимое временного DC в DC окна
BitBlt(
hdc, // HDC назначения
0, // Начало вставки по оси X
0, // Начало вставки по оси Y
width, // Ширина
height, // Высота
srcHdc, // Исходный HDC (из которого будут копироваться данные)
0, // Начало считывания по оси X
0, // Начало считывания по оси Y
SRCCOPY // Копировать
);
// Уничтожить bit-map
DeleteObject(hBitMap);
// Уничтожить временный DC
DeleteDC(srcHdc);
// Уничтожить DC
DeleteDC(hdc);
Все нормально работало, причем удивительно что работало как с одномерным, так и двумерным массивом структур, в качестве параметра pixels
(в функции CreateBitmap
). Будто бы двумерные массивы в С++, которые объявлены не динамически, воспринимаются как одномерные.. И тут я попробовал выделить этот самый фрейм-буфер (двумерный массив) динамически, в куче, то есть по сути создать массив указателей на массивы (выше пример, как именно я это делал). И в итоге все перестало работать, теперь функция CreateBitmap
этого не понимает. Я попытался тогда динамически выделить одномерный массив, как-то вот так:
RGBQUAD * frame = new RGBQUAD[width * height];
std::fill_n(frame, width * height, clearColor);
И все тут же стало работать.
Вопрос: в чем дело? Что я упускаю? Действительно ли в С++ двумерные массивы объявленные динамически это совсем не то же самое что двумерные массивы объявленные обычным способом? В чем разница? За ранее спасибо.
Для обычных массивов, вроде int a[3]
и int b[3][3]
, в памяти хранятся только сами элементы подряд, и все.
int a[3]
.------.------.------.------.------.
| a[0] | a[1] | a[2] | a[3] | a[4] |
'------'------'------'------'------'
int b[3][2]
.---------.---------.---------.---------.---------.---------.
| b[0][0] | b[0][1] | b[1][0] | b[1][1] | b[2][0] | b[2][1] |
'---------'---------'---------'---------'---------'---------'
А вот так выглядит одномерный массив, созданный через new
. Указатель на первый элемент хранится отдельно.
int *c = new int[5]
.-----.
| c |
'--.--'
|
|
V
.-----.-----.-----.-----.-----.
| [0] | [1] | [2] | [3] | [4] |
'-----'-----'-----'-----'-----'
Для многомерного массива вы использовали массив указателей на массивы, он же "рваный" массив.
int **d = new int*[3];
for (int i = 0; i < 3; i++)
d[i] = new int[4];
.-----.
| d |
'--.--'
|
|
V
.-----.-----.-----.
| [0] | [1] | [2] |
'--.--'--.--'--.--'
| | | .--------.--------.--------.--------.
| | '------> | [2][0] | [2][1] | [2][2] | [2][3] |
| | '--------'--------'--------'--------'
| | .--------.--------.--------.--------.
| '------> | [1][0] | [1][1] | [1][2] | [1][3] |
| '--------'--------'--------'--------'
| .--------.--------.--------.--------.
'------> | [0][0] | [0][1] | [0][2] | [0][3] |
'--------'--------'--------'--------'
В таком случае строчки не обязательно расположены в памяти подряд, в отличие от массива, созданного обычным способом, вроде int f[3][4]
.
Самый удобный (мне кажется) способ сделать так, чтобы строчки шли в памяти подряд, вы уже нашли: Использовать одномерный массив: int *g = new int[w * h];
.
Если хотите использовать удобный синтаксис для доступа к элементам: g[y][x]
вместо g[y * w + x]
, то лучше всего сделать свой класс двухмерного массива с перегруженным оператором []
.
Кстати, очень советую вместо new
и delete
использовать std::vector
.
С new/delete легко забыть освободить память, и получить утечку. Замучаетесь искать потом.
Особенно легко забыть, если у вас в коде что-то выбросит исключение.
А std::vector
следит за освобождением памяти за вас.
Разница в том что статический двумерный массив ничем не отличается от одномерного,
Значит расположен он будет так (пример двумерного статического массива 5x5) на схеме ロ
обозначает ячейку
ロロロロロ ロロロロロ ロロロロロ
А в динамическом двумерном массиве все первые элементы это указатели, и расположены все элементы в рознь по оперативной памяти (пример двумерного динамического массива 5x5) на схеме &
обозначает ссылку
&1 ---> ロロロロロ
&2 ---> ロロロロロ
&3 ---> ロロロロロ
&4 ---> ロロロロロ
&5 ---> ロロロロロ
Соответственно они разбросаны по оперативной памяти хаотично в отличии от статического двумерного массива
Если вам нужен непрерывный двумерный массив, есть вариант
int arr = new int[w*h];
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Пытаюсь реализовать функцию дешифрования из DPAPIПозже я заметил, что после моей функции в памяти забивается 8
Пытаюсь переделать данные методы в stream, используя filter и map методы