LINUX.ORG.RU

адресация массивов в С++

 


0

2

Сравним адресацию статического и динамического двухмерного массива. Вот код:

#include <stdio.h>

int main()
{
	printf("Dynamic array: \n");
	int **a = new int* [5];
	for (int i=0; i<5; i++)
		a[i] = new int [5];
		
	for (int i=0; i<5; i++) {
		for (int j=0; j<5; j++) 
			printf("%d ", &a[i][j]);
			printf("\n");
	}	
	printf("\n");

    	delete[] a;

	int b [5][5];

	printf("Static array: \n");
	for (int i=0; i<5; i++) {
		for (int j=0; j<5; j++) 
			printf("%d ", &b[i][j]);
			printf("\n");
		}
	printf("\n");

	return 0;
}

В итоге адреса ячеек в статическом массиве идут все подряд. В динамическом массиве нет: строка подряд, потом пропускается ячейка, потом опять строка. Как это так получается? Что лежит в пропущенной ячейке?

★★★★

Последнее исправление: beastie (всего исправлений: 1)

Оффтоп: тут мемлик, удаляй массив в обратной последовательности

for (int i = 0; i < 5; i++)
{
  delete [] a[i];
}
delete [] a;

CrazyAlex25 ★★★
()

Эм... оператор new есть только в c++

CrazyAlex25 ★★★
()

как ты их положил, так они и лежат..

можно подряд:

int **array;
int *flat;
int i;
array=calloc(5*sizeof(int *));
flat=calloc(25*sizeof(int));
for(i=0;i<5;i++)
   array[i]=flat+i*5;

MKuznetsov ★★★★★
()

Как это так получается?

Так работает operator new[]

Что лежит в пропущенной ячейке?

Длина выделенного региона памяти.

mix_mix ★★★★★
()

адресация массивов в С
new int [5];
delete[] a;

Так Си или Си++?

Deleted
()

facepalm. Книжек бы тебе почитать, да по самым по основам.

anonymous
()

Какой это C? Это C++, зачем бред путать людей

int13h ★★★★★
()
Ответ на: комментарий от post-factum

Поправил tag и subj. ;)

Это какая-то странная смесь C и C++. Тут вам и stdio.h вместо stdio, и printf вместо cout и new вместо malloc.

beastie ★★★★★
()
Ответ на: комментарий от MKuznetsov

Такой код не компилируется, но идею понял. Действительно подряд выделяет.

hotpil ★★★★
() автор топика

Таким образом, вот такой код:


int **a;
	int *f;
	int i;
	a = new int* [5];
	f = new int [25];
	//a= (int**)malloc(5*sizeof(int*));
	//f = (int*)malloc(25*sizeof(int));
	for (i=0;i<5;i++)
	    a[i]=f+i*5;	

выделяет ячейки подряд, внезависимости от того new там используется или malloc. Так что в плане выделения памяти они одинаково работают. Никакой дополнительной ячейки new не дает. Почему получается подругому в коде в сабже пока не понял.

hotpil ★★★★
() автор топика

Открою страшную тайну: если бы ты работал в многопоточном приложении, у тебя malloc на каждую очередную строку вообще мог бы хоть мегабайты пропускать!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от beastie

Похоже, только человек сдал лабораторки по С, как ему потребовалось на С++ лабы писать.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Это ты про что? Пост выше тебя демонстрирует, что ничего там не пропускается, если выделять так, как предложил MKuznetsov.

hotpil ★★★★
() автор топика
Ответ на: комментарий от hotpil

В посте new int [5] на каждый элемент a, new может выделять где ему угодно, поэтому не непрерывно. А тут ты указатели a сам привязываешь к кускам непрерывного f — вот оно так и получается.

motto
()
Ответ на: комментарий от hotpil

емнип, непрерывно можно ещё

    size_t m;
    constexpr size_t n;

    int (*a)[n] = new int[m][n];

или с VLA (не стандартно)

    size_t m = 2, n = 4;

    int (*a)[n] = (int(*)[n])new int[m * n];
motto
()
Ответ на: комментарий от hotpil

Знаю. Поэтому и говорю: читай матчасть.

Когда ты делаешь malloc() на массив указателей, ты получаешь непрерывный (для тебя, фактически он может быть рваным) кусок памяти; потом в цикле выделяешь на каждый указатель область памяти, получаешь еще непрерывные (для тебя) куски, которые в памяти могут быть расположены совершенно по-разному.

Раз у тебя однопоточное приложение, то адресация идет сплошняком → у тебя только пропуски на выравнивание блоков, выделяемых malloc'ом. А вот была бы она у тебя многопоточная, то между двумя последовательными malloc'ами кто-нибудь еще мог вызвать malloc → у тебя была бы значительно более "рваная" адресация начала каждой строки двумерного массива.

И да, обычно такое делать для массива фиксированного размера бессмысленно: ты больше на разыменовании двух указателей потеряешь, нежели на вычислении адреса в одномерном массиве. Если не веришь — попробуй тест.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от motto

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

hotpil ★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

P.S. В числодробилках обычно еще хитрей делают: под N-мерный массив выделяют фактически одномерную область памяти, но чтобы ускорить обращение к памяти, выравнивают каждую строку.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от hotpil

Динамический массив нужен если обе размерности на этапе выполнения меняются

Чушь-то какая! Ты не сможешь увеличить длины уже созданных строк! Если у тебя массив в обе стороны динамический, то тебе уже "векторы" надо использовать (связные списки в сях). И тормозить это будет жесточайше!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Так как написано во всех примерах, приведенных здесь - обе размерности не являются константами, могут задаваться на этапе выполнения. Ты уверен, что сам-то понимаешь как память выделяется?

hotpil ★★★★
() автор топика
Ответ на: комментарий от hotpil

Япона мать! Да пофиг! Даже если у тебя массив статический, скажем, 1000х1000 интов, ты же не будешь писать int arr[1000][1000], а сделаешь malloc!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

«векторы» надо использовать (связные списки в сях)

Вот научишь, а потом люди будут жаловаться что программа на C медленее, чем на C++.

Begemoth ★★★★★
()
Ответ на: комментарий от geks

Я без понятия, как оно работает. Если через связные списки, то будет в процессе обработки данных. Если через realloc, то в процессе заполнения.

Но тормозить будет стопудово (по сравнению с фиксированным размером) — от этого никуда.

Eddy_Em ☆☆☆☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.