МегаПредмет

ПОЗНАВАТЕЛЬНОЕ

Сила воли ведет к действию, а позитивные действия формируют позитивное отношение


Как определить диапазон голоса - ваш вокал


Игровые автоматы с быстрым выводом


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


Целительная привычка


Как самому избавиться от обидчивости


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


Тренинг уверенности в себе


Вкуснейший "Салат из свеклы с чесноком"


Натюрморт и его изобразительные возможности


Применение, как принимать мумие? Мумие для волос, лица, при переломах, при кровотечении и т.д.


Как научиться брать на себя ответственность


Зачем нужны границы в отношениях с детьми?


Световозвращающие элементы на детской одежде


Как победить свой возраст? Восемь уникальных способов, которые помогут достичь долголетия


Как слышать голос Бога


Классификация ожирения по ИМТ (ВОЗ)


Глава 3. Завет мужчины с женщиной


Оси и плоскости тела человека


Оси и плоскости тела человека - Тело человека состоит из определенных топографических частей и участков, в которых расположены органы, мышцы, сосуды, нервы и т.д.


Отёска стен и прирубка косяков Отёска стен и прирубка косяков - Когда на доме не достаёт окон и дверей, красивое высокое крыльцо ещё только в воображении, приходится подниматься с улицы в дом по трапу.


Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) - В простых моделях рынка спрос и предложение обычно полагают зависящими только от текущей цены на товар.

Общий случай двумерного массива





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

 

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

 

#define MAXVAL 1000

 

void *Malloc ( size_t size );

double **MakeMatr ( size_t n, size_t m );

void DelMatr ( double *Matr[] );

void RandomMatr ( double *Matr[], int n, int m );

void OutMatr ( char *name,

double *Matr[], int n, int m );

 

void main( void )

{

int n = 5, m = 6;

double **A;

/* Выделение памяти под матрицу */

A = MakeMatr(n, m);

/* Заполнение матрицы значениями и распечатка */

RandomMatr(A, n, m);

OutMatr("A", A, n, m);

/* освобождение памяти */

DelMatr(A);

}

 

void RandomMatr (double *Matr[], int n, int m)

{

int i, j;

for(i = 0; i < n; i++)

for(j = 0; j < m; j++)

Matr[i][j] = random(MAXVAL) + 1;

}

 

void OutMatr( char *name, double *Matr[], int n, int m )

{

int i, j;

printf("\nМатрица %s\n---------------\n", name);

for(i = 0; i < n; i++)

{

for(j = 0; j < m; j++)

printf("%8.1lf ", Matr[i][j]);

printf("\n");

}

}

 

void *Malloc( size_t size )

{

void *p = malloc(size);

if( !p )

{ printf("Недостаточно памяти!\n"); exit(1); }

return p;

}

 

/* Конструктор матрицы */

double **MakeMatr( size_t n, size_t m )

{

double **Matr; size_t i;

Matr = (double**) Malloc( (n + 1) * sizeof(double *) );

for(i = 0; i < n; i++)

Matr[i] = (double *) Malloc( m * sizeof(double) );

Matr[n] = NULL;

return Matr;

}

 

/* Деструктор матрицы */

void DelMatr( double *Matr[] )

{

size_t i;

for(i = 0; Matr[i]; i++) free(Matr[i]);

free(Matr);

}

 

Вначале в функции-конструкторе MakeMatr() выделяется вектор памяти размером n+1 элементов для хранения указателей на double. Затем для каждой из n строк массива выделяется память и адрес ее записывается в ранее выделенный вектор указателей. В последний элемент вектора заносится величина NULL, которая в деструкторе будет сигнализировать о конце вектора. Иначе в деструктор пришлось бы передавать дополнительный параметр n.

Рассмотренная схема выделения памяти не имеет практических ограничений даже для 16-разрядной сегментной модели памяти. Нужно лишь чтобы размер строки и размер вектора указателей не превышал сегмента.

Если массив целиком укладывается в сегмент, то для работы с ним можно предложить следующую схему с меньшими накладными расходами на выделение памяти:

 

/* Конструктор матрицы */

double **MakeMatr( size_t n, size_t m )

{

double **Matr; size_t i;

Matr = (double**) Malloc( n * sizeof(double *)

+ n * m * sizeof(double) );

for(i = 0; i < n; i++)

Matr[i] = (double *)(Matr + n) + i * m;

return Matr;

}

 

/* Деструктор матрицы */

void DelMatr( double *Matr[] )

{

free(Matr);

}

 

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

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

 

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

 

#define MAXVAL 1000

 

void *Malloc ( size_t size );

double **MakeMatr ( size_t n, size_t m );

void DelMatr ( double *Matr[] );

size_t GetN ( double *Matr[] );

size_t GetM ( double *Matr[] );

void RandomMatr ( double *Matr[] );

void OutMatr ( char *name, double *Matr[] );

 

void main( void )

{

int n = 5, m = 6;



double **A;

/* Выделение памяти под матрицу */

A = MakeMatr(n, m);

/* Заполнение матрицы значениями и распечатка */

RandomMatr( A );

OutMatr("A", A );

/* освобождение памяти */

DelMatr(A);

}

 

void RandomMatr ( double *Matr[] )

{

int i, j, n = GetN(Matr), m = GetM(Matr);

for(i = 0; i < n; i++)

for(j = 0; j < m; j++)

Matr[i][j] = random(MAXVAL) + 1;

}

 

void OutMatr( char *name, double *Matr[] )

{

int i, j, n = GetN(Matr), m = GetM(Matr);

printf("\nМатрица %s\n---------------\n", name);

for(i = 0; i < n; i++)

{

for(j = 0; j < m; j++)

printf("%8.1lf ", Matr[i][j]);

printf("\n");

}

}

 

void * Malloc( size_t size )

{

void *p = malloc(size);

if( !p )

{ printf("Недостаточно памяти!\n"); exit(1); }

return p;

}

 

/* Конструктор матрицы */

double **MakeMatr( size_t n, size_t m )

{

double **Matr; size_t i;

Matr = (double**) Malloc( 2 * sizeof(size_t)

+ n * sizeof(double *) );

(size_t *)Matr += 2;

for(i=0; i<n; i++)

Matr[i] = (double *) Malloc( m * sizeof(double) );

Matr[n] = NULL;

*( (size_t *)Matr - 2 ) = n;

*( (size_t *)Matr - 1 ) = m;

return Matr;

}

 

size_t GetN( double *Matr[] )

{

return *( (size_t *)Matr - 2 );

}

 

size_t GetM( double *Matr[] )

{

return *( (size_t *)Matr - 1 );

}

 

/* Деструктор матрицы */

void DelMatr( double *Matr[] )

{

size_t i, n = GetN(Matr);

for(i = 0; i < n; i++) free(Matr[i]);

free( (size_t *)Matr - 2 );

}

 

В конструкторе теперь выделяется память для хранения n указателей на double и для двух величин типа size_t, которые служат для хранения размеров матрицы. Выделять дополнительный элемент для занесения NULL теперь нет необходимости, так как теперь с помощью функций GetN() и GetM() можно получить соответствующие размеры массива. Способ индексации не изменяется и она по-прежнему выполняется в стиле индексации двумерных массивов.

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





©2015 www.megapredmet.ru Все права принадлежат авторам размещенных материалов.