Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [FAQ] Динамические массивы, Обсуждаем статью для FAQ 
:(
    Опции темы
bsa
Дата 26.12.2007, 22:07 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Так как язык С++ добавляет свои средства работы с массивами к имеющимся в языке Си, то рассмотрим сначала то, чем располагает Си, а затем уже то, что привносит С++.

Динамические массивы в Си

Массив - это набор однотипных данных, доступ к которым может быть осуществлен по индексу, т.е. по номеру элемента. В Си принято нумеровать элементы с нуля, поэтому первый элемент всегда имеет индекс 0, а последний - (N-1), где N - это размер массива (количество элементов).
Встроенные средства языка программирования Си позволяют создавать статические массивы - массивы, число элементов которых задается на этапе компиляции и в процессе работы программы не меняется. Но как только сложность задач выходит за банальное "Hello, world!", возникает необходимость менять размеры массива в процессе работы программы...
Что представляет собой массив на уровне ЭВМ? Это непрерывный кусок памяти, в который помещаются все элементы массива. Таким образом, для изменения количества элементов в массиве нужно менять размер этого куска. Но для начала его нужно выделить...
Последняя версия стандарта языка Си позволяет создавать автоматические динамические массивы. Они существуют только в пределах текущей области видимости и при выходе из нее уничтожаются. Синтаксис записи аналогичен статическим массивам, только в качестве указателя размера выступает не числовая константа, а переменная:
Код
#include <stdio.h>

int main()
{
    printf("Input size: ");
    fflush(0);
    int n;
    scanf("%d", &n); //вводим число элементов массива
    int array[n];      //выделяется память под n элементов
    int i;
    for(i = 0; i < n; ++i)
        array[i] = i; //присваиваем им значения
    for(i = 0; i < n; ++i)
        printf("%d\n", array[i]); //выводим их значения
    printf("size = %d\n", sizeof(array)/sizeof(*array)); //убеждаемся, 
          //что sizeof работает так же, как и со статическими массивами
    return 0; //память освобождается автоматически
} //при выходе из области видимости
Но очень часто возможности создания таких массивов не достаточно (невозможно сохранить массив, при выходе из функции, его создавшей, изменить его размеры и, если он очень большой, может вызвать крах программы). Поэтому существует возможность создания массивов в динамической памяти. Стоит иметь в виду, что за гибкость предоставляемую ей приходится платить серьезным снижением скорости выделения/освобождения памяти и необходимостью следить за своевременным освобождением, иначе она может просто закончиться.

Стандартная библиотека Си предоставляет средства для работы с динамической памятью, такие как:
malloccalloc - выделение памяти
free - освобождение памяти
realloc - изменение размера выделенной области памяти (может замещать собой и malloc, и free)
Для их использования надо подключить заголовочный файл stdlib.h:
Код
#include <stdlib.h>
malloc() производит выделение памяти, объем которой в байтах указывается в качестве параметра:
Код
void *p = malloc(1024); //выделение 1024 байт памяти
Выделенная таким образом память содержит "мусор" (случайные значения), поэтому перед использованием требуется ее инициализировать.
Функция calloc() производит выделение памяти под набор элементов одинакого размера и его зануление. Первым параметром указывается количество необходимых элементов, а вторым размер элемента в байтах:
Код
int *p = (int*)calloc(256, sizeof(*p)); //выделение памяти под 256 элементов типа int
//это эквивалентно записи
int *p = (int*)malloc(256*sizeof(*p)); //выделение области памяти под 256 элементов типа int
memset(p, 0, sizeof(*p)*256); //обнуление выделенной области
Стоит обратить внимание на использование конструкции sizeof(*p) вместо sizeof(int) или просто числа 4 в качестве размера элемента массива. Эта конструкция, во-первых, позволяет обеспечить платформонезависимость кода (например, на 32-х разрядных машинах размер long равен 4 байтам, а на 64-х разрядных Unix машинах - 8 байт), во-вторых, позволяет уменьшить количество правок кода в случае изменения типа элементов (например, int заменить на double).
Функция realloc() позволяет изменять размер области памяти, которая выделена функциями realloc()malloc() или calloc() (на самом деле, она еще может выделять память, как malloc, и освобождать, как free):
Код
int *p = (int*)calloc(10, sizeof(*p)); //выделение памяти под 10 элементов типа int
p = (int*)realloc(p, 100*sizeof(*p)); //расширение выделенной области памяти под 100 элементов типа int
free(p); //освобождение выделенной памяти
//-----------------------------------------------------
//этот с виду простой код можно заменить следующим (необходимо только подключить #include <string.h>)
//-----------------------------------------------------
int *p = (int*)calloc(10, sizeof(*p)); //выделение памяти под 10 элементов типа int
//на самом деле реализация функции realloc() несколько сложней
int *t = (int*)calloc(100, sizeof(*p)); //выделение памяти под 100 элементов типа int
memcpy(t, p, 10*sizeof(*p)); //копирование содержимого предыдущего массива в новый
free(p); //освобождение памяти от предыдущего массива
p = t; //присвоение p указателя на новый массив

free(p); //освобождение памяти
Как нетрудно заметить, использование realloc() значительно сокращает код и увеличивает его читабельность. Поэтому ее очень удобно использовать для массивов, размер которых меняется в процессе работы программы.
Вот пример использования динамического массива:
Код
#include <stdlib.h>
#include <stdio.h>
int main()
{
    int i;    //счетчик цикла
    int n;    //в эту переменную будет введено количество элементов в массиве
    int *p;    //в эту переменную будет помещен указатель на динамический массив
    printf("Input number of elements: ");
    fflush(NULL);        //эта функция сбрасывает файловые буфера
    scanf("%d", &n);    //вводим число в переменную n
    p = (int*)malloc( n*sizeof(*p) );
    //можно это сделать так:
    for(i = 0; i < n; ++i)
        p[i] = i*10;    //присваиваем элементам массива удесятеренное значение индекса
    for(i = 0; i < n; ++i)
        printf("%d ", p[i]);    //выводим все элементы массива через пробел в одну строчку
    printf("\n");
    free(p);    //освобождаем память, выделенную под массив
    return 0; //успешное завершение программы
}
В данном примере был создан массив из n элементов типа int, причем число n вводилось с клавиатуры. Указатель на начало массива был присвоен переменной p. Дальнешие операции над p ничем не отличаются от оных для статических массивов. Разве что, sizeof(p) вернет размер указателя p, а не размер массива в байтах.
Как нетрудно заметить, в конце функции идет освобождение памяти, выделенной под массив. Чтобы избежать утечек памяти, нужно всегда освобождать память, как только она перестала быть нужной.
Динамические массивы нельзя копировать путем присваивания указателей:
Код
int *p = (int*)malloc(sizeof(*p)*10);
int *t = (int*)malloc(sizeof(*t)*10);
....
p = t; //возможно, логическая ошибка
Хотя результат и будет похож на требуемый, но изменение массива, на который ссылается указатель t, приведет и к изменению массива, на который указывает p, так как они теперь указывают на один и тотже массив. Да и освободить память, которая изначально была выделена под массив p, теперь нельзя (если, конечно, значение указателя p не было сохранено предварительно). Чтобы этого не происходило, нужно воспользоваться функцией memcpy(), которая объявлена в стандартном заголовочном файле string.h:
Код
int *p = (int*)malloc(sizeof(*p)*10);
int *t = (int*)malloc(sizeof(*t)*10);
....
memcpy(p, t, sizeof(*p)*10);
Она скопирует данные из массива t в массив p.
Стоит иметь в виду, что указатели на внутренние элементы динамического массива использовать не очень безопасно. Так как после очередного изменения размера массива они могут стать неверны, что приведет к возникновению трудно отслеживаемых ошибок. Указатели на внутренние элементы стоит применять только там, где не предполагается изменений размеров массива.

Создать полностью динамический многомерный массив стандартными средствами языка Си невозможно (как создать частично динамический массив будет сказано ниже). Но можно сымитировать одним из двух способов:
1. через массив массивов
2. через одномерный массив

Рассмотрим первый вариант реализации многомерных динамических массивов на примере двумерного.
Для этого создадим указатель на указатель на, например, int:
Код
int* *p; //это указатель на указатель на int
int i, n, m;
//вводим n и m с клавиатуры
...
//выделяем память под массив указателей
p = (int **)calloc(n, sizeof(*p)); //p теперь указывает на массив указателей на int
//выделяем память для каждой строки массива
for(i = 0; i < n; ++i)
   p[i] = (int*)calloc(m, sizeof(*p[i]));
//теперь можно получить доступ к каждому элементу двумерного массива: p[i][j], где 0 <= i < n, 0 <= j < m
...
//после завершения работы с массивом, необходимо освободить всю выделенную память
for(i = 0; i < n; ++i)
   free(p[i]);
free(p);

Для второго способа нужно создать одномерный массив, число элементов которого равно произведению всех размерностей:
Код
int *p;
int i, n, m;
//вводим n и m с клавиатуры
...
//выделяем память под массив указателей
p = (int *)calloc(n, sizeof(*p)*m);
//теперь можно получить доступ к каждому элементу двумерного массива: p[i*m + j], где 0 <= i < n, 0 <= j < m
...
//после завершения работы с массивом, необходимо освободить память
free(p);
Как нетрудно заметить, сократился объем выделяемой памяти, но зато сократилась и скорость доступа к элементам за счет необходимости производить умножение. Для устранения этого недостатка можно совместить два этих способа:
Код
int *p;
int **r;
int i, n, m;
//вводим n и m с клавиатуры
...
//выделяем память под массив указателей
p = (int *)calloc(n, sizeof(*p)*m);
r = (int**)calloc(n, sizeof(*r));
for(i = 0; i < n; ++i)
    r[i] = p + i*m;
//теперь можно получить доступ к каждому элементу двумерного массива: r[i][j], где 0 <= i < n, 0 <= j < m
...
//после завершения работы с массивом, необходимо освободить память
free(r);
free(p);
В данном случае создается массив индексов строк, на который ссылается указатель r. Данный способ имеет по одному преимуществу, по сравнению с двумя предыдущими: во-первых, скорость доступа к каждому элементу такая же, как и в первом способе, во-вторых, скорость создания/удаления массива несколько медленней, чем во втором способе, но выше, чем в первом. Хотя, стоит иметь в виду, что в случае изменения размеров массива необходимо пересчитывать индексный массив.

Как вариант можно создать многомерный массив, у которого только одна размерность динамическая, при этом скорость работы с ним аналогична статическому массиву (это не относится ко времени выделения памяти). Динамической может быть только первая размерность (например, для двумерного массива это количество строк).
Для этого надо создать указатель на массив, размерность которого на один меньше необходимой (например, чтобы получить динамический двумерный массив, нужно создать указатель на одномерный массив с нужным числом столбцов). Например:
Код
int (*pArray)[10]; // круглые скобки обязательны
Это указатель на массив int, состоящий из 10 столбцов. Из него можно создать двумерный массив с изменяемым числом строк. Или:
Код
double (*pArray)[5][10];
Это уже указатель на двумерный массив double, из которого можно получить трехмерный массив с изменяемым количеством "плоскостей" (трехмерный массив можно представить в виде параллелепипеда (пирог "Наполеон"): pArray[z][y][x], где z - это изменяемая глубина, y - постоянная высота, x - постоянная ширина). В данном случае под "плоскостью" понимается двумерный массив постоянных размеров.
После определения указателя нужно выделить под массив память (далее для простоты рассматривается двумерный массив):
Код
int (*pArray)[10];
pArray = ( int(*)[10] )calloc( 50, sizeof(*pArray) );
В данном случае памяти было выделено на 50 строк. Так как память выделяется непрерывным куском и компилятор языка Си не осуществляет проверки выхода за границы массива, то этот прием позволяет получить доступ ко всем строкам массива так, как это делается в статических массивах:
Код
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
        int rowCount = 0;
        int i,j;
        int (*p)[10];
        scanf("%d", &rowCount);
        if (rowCount <= 0)
             rowCount = 1; //нельзя выделить память под менее, чем одну строку
        p = (int (*)[10])calloc( rowCount, sizeof(*p) );
        for(i = 0; i < rowCount; ++i)
                for(j = 0; j < 10; ++j)
                        p[i][j] = i * 10 + j;
        for(i = 0; i < rowCount; ++i) {
                for(j = 0; j < 10; ++j)
                        printf("%3d ", p[i][j]);
                printf("\n");
        }
        free(p);
        return 0;
}


---------------------------------------------------------------------------------------------------------------------
Динамические массивы в Си++

Массив - это набор однотипных данных, доступ к которым может быть осуществлен по индексу, т.е. по номеру элемента. В Си++, так же как и вв Си, принято нумеровать элементы с нуля, поэтому первый элемент всегда имеет индекс 0, а последний - (N-1), где N - это размер массива (количество элементов).
Средства языка программирования Си++ позволяют создавать статические массивы - массивы, число элементов которых задается на этапе компиляции и в процессе работы программы не меняется. Но как только сложность задач выходит за банальное "Hello, world!", возникает необходимость менять размеры массива в процессе работы программы...
Что представляет собой массив на уровне ЭВМ? Это непрерывный кусок памяти, в который помещаются все элементы массива. Таким образом, для изменения количества элементов в массиве нужно менять размер области памяти.

В языке С++ есть встроенные средства, для работы с динамической памятью - new[] и delete[], позволяющие выделять  память под массивы и освобождать ее. Чтобы выделить память с помощью new нужно указать тип элемента массива после ключевого слова new и их количество в квадратных скобках. Чтобы освободить память, занимаемую выделенным таким образом массивом необходимо вызвать delete[]. В отличие от free(), delete[] может принимать в качестве аргумента и нулевой указатель, в этом случае он ничего не сделает. Пример:
Код
#include <iostream>
int main()
{
    std::cout << "Input number of elements: " << std::flush; //выводим данную строку на экран
    int n;
    std::cin >> n;    //вводим количество элементов массива
    int *p = new int[n];    //выделяем память
    for(int i = 0; i < n; ++i)
        array[i] = i*10;    //присваиваем элементам массива удесятеренное значение индекса
    for(int i = 0; i < n; ++i)
        std::cout << array[i] << " ";    //выводим все элементы массива через пробел в одну строчку
    std::cout << std::endl;
    delete []p;    //освобождаем память
    return 0;
}
Но пользоваться ими не сильно удобно, так как постоянно нужно помнить о необходимости освобождения памяти, да и встроенных функций для изменения размеров массива нет (нужно создать еще один массив необходимой длины, скопировать данные из старого массива, удалить старый массив). Поэтому есть более комфортные средства для работы с динамическими массивами, которые включены в стандартную библиотеку шаблонов (STL). В частности, шаблон для работы с простейшими массивами называется vector. Для работы с ним требуется подключить специальный модуль:
Код
#include <vector>
После чего в пространстве имен std появится шаблон vector...
Так как vector это шаблон, то нужно указать тип объекта, которые будут храниться в массиве. Это делается с помощью угловых скобок: std::vector<int>. Вот небольшой пример использования шаблона vector:
Код
#include <vector>
#include <iostream>
int main()
{
    std::cout << "Input number of elements: " << std::flush; //выводим данную строку на экран
    int n;
    std::cin >> n;    //вводим количество элементов массива
    std::vector<int> array(n);    //создаем массив из n элементов.
    //в дальнейшем, для изменения количества элементов можно использоваться array.resize(n)
    for(int i = 0; i < n; ++i)
        array[i] = i*10;    //присваиваем элементам массива удесятеренное значение индекса
    for(std::vector<int>::const_iterator i = array.begin(), end = array.end(); i != end; ++i)
        std::cout << *i << " ";    //выводим все элементы массива через пробел в одну строчку
    std::cout << std::endl;
    return 0;
}
Как нетрудно заметить, не нужно беспокоиться о расчете необходимого объема памяти и ее освобождении. А в остальном все тоже самое, разве что добавился еще один способ последовательного перебора элементов массива - итераторы (это такой вид универсальных "указателей", инкремент/декремент которых приводит к указанию на следующий/предыдущий элемент). Массивы, созданные с использованием шаблона std::vector, можно присваивать друг другу, главное чтобы тип хранимых объектов был одинаковым:
Код
std::vector<int> a;
std::vector<int> b;
...
a = b; //ок
Стоит иметь в виду, что бесконтрольное использование итераторов и указателей на внутренние элементы динамических массивов довольно опасно. Так как после очередного изменения размера массива они могут стать неверны, что приведет к возникновению трудно отслеживаемых ошибок. Итераторы стоит применять только там, где не предполагается изменений размеров массива.

Создать полностью динамический многомерный массив стандартными средствами языка Си++ невозможно (как создать частично динамический массив будет сказано ниже). Но можно сымитировать одним из двух способов:
1. через массив массивов
2. через одномерный массив

Рассмотрим первый вариант реализации многомерных динамических массивов на примере двумерного:
Код
typedef std::vector< std::vector<int> > Int2dArray; //так несколько удобней
Int2dArray array(n, Int2dArray::value_type(m)); //Int2dArray::value_type - это std::vector<int> в данном случае
array[0][1] = 10;

Для второго способа нужно создать одномерный массив, число элементов которого равно произведению всех размерностей:
Код
int i, n, m;
//вводим n и m с клавиатуры
...
//выделяем память под массив указателей
std::vector<int> array(m*n);
//теперь можно получить доступ к каждому элементу двумерного массива: array[i*m + j], где 0 <= i < n, 0 <= j < m
...
Правда, за счет сокращения объемов выделяемой памяти, сократилась и скорость доступа к элементам из-за появления операции умножения.
Можно совместить два этих способа:
Код
typedef std::vector<int> IntArray;
typedef std::vector<IntArray::iterator> IntArrayIndexes;
IntArray array;
IntArrayIndexes indexes;
int m, n;
//вводим m и n
array.resize(m*n);
indexes.resize(n);
for(IntArrayIndexes::iterator i = indexes.begin(); i != indexes.end(); ++i)
     *i = array.begin() + (i - indexes.begin()) * m;
В данном случае создается массив индексов строк indexes. Данный способ имеет по одному преимуществу, по сравнению с двумя предыдущими: во-первых, скорость доступа к каждому элементу такая же, как и в первом способе, во-вторых, скорость создания/удаления массива несколько медленней, чем во втором способе, но выше, чем в первом.

Как вариант можно создать многомерный массив, у которого только одна размерность динамическая, при этом скорость работы с ним аналогична статическому массиву. Динамической может быть только первая размерность (например, для двумерного массива это количество строк).
Для этого надо создать указатель на массив, размерность которого на один меньше необходимой (например, чтобы получить динамический двумерный массив, нужно создать указатель на одномерный массив с нужным числом столбцов). Например:
Код
int (*pArray)[10]; // круглые скобки обязательны
Это указатель на массив int, состоящий из 10 столбцов. Из него можно создать двумерный массив с изменяемым числом строк. Или:
Код
double (*pArray)[5][10];
Это уже указатель на двумерный массив double, из которого можно получить трехмерный массив с изменяемым количеством "плоскостей" (трехмерный массив можно представить в виде параллелепипеда (пирог "Наполеон"): pArray[z][y][x], где z - это изменяемая глубина, y - постоянная высота, x - постоянная ширина). В данном случае под "плоскостью" понимается двумерный массив постоянных размеров.
После определения указателя нужно выделить под массив память (далее для простоты рассматривается двумерный массив):
Код
typedef int (*ArrayRow)[10];
ArrayRow pArray;
pArray = new ArrayRow[50];
В данном случае памяти было выделено на 50 строк. Так как память выделяется непрерывным куском и компилятор языка Си++ не осуществляет проверки выхода за границы массива, то этот прием позволяет получить доступ ко всем строкам массива так, как это делается в статических массивах:
Код
#include <iomanip>

int main()
{
        int rowCount = 0;
        std::cin >> rowCount;
        if (rowCount <= 0)
             rowCount = 1; //нельзя выделить память под менее, чем одну строку
        int (*p)[10] = new int[rowCount][10];
        for(int i = 0; i < rowCount; ++i)
                for(int j = 0; j < 10; ++j)
                        p[i][j] = i * 10 + j;
        for(int i = 0; i < rowCount; ++i) {
                for(int j = 0; j < 10; ++j)
                        std::cout << std::setw(3) << p[i][j] << ' ';
                std::cout << std::endl;
        }
        delete []p;
        return 0;
}


Назад к FAQ

Это сообщение отредактировал(а) bsa - 26.7.2011, 11:01
PM   Вверх
archimed7592
Дата 26.12.2007, 22:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



bsa, а где-же new/delete? smile

Ещё, прошу добавить ссылки:
1. На википедию(массив)
2. На cppreference.com или куда-нибудь ещё(malloc, free, realloc и т.д.)


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Damarus
Дата 27.12.2007, 01:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 671
Регистрация: 6.5.2006

Репутация: нет
Всего: 29



bsa, можно ещё написать про многомерные динамические массивы.
PM MAIL ICQ Jabber   Вверх
archimed7592
Дата 27.12.2007, 01:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Damarus, согласен - а я проглядел smile. Достаточно будет двухмерного.



--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Shaggie
Дата 28.12.2007, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 570
Регистрация: 21.12.2006
Где: outer space

Репутация: нет
Всего: 72



Скорее всего, на момент чтения ФАКа информация для читающего будет очень новая и неизвестная. Поэтому следующие моменты немножко напрягли:
Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
std::vector<int> array(n);    //создаем массив из n элементов

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
    for(std::vector<int>::const_iterator i = array.begin(); i != array.end(); ++i)
        std::cout << *i << " ";    //выводим все элементы массива через пробел в одну строчку

И без объяснений... Я бы порекомендовал, во-первых, вкратце описать использование шаблонов в объявлении вектора (хотя бы так - "динамический массив должен содержать примитивы или объекты определённого типа, который мы указываем вот таким способом"), и, во-вторых, описать итератор как специальный тип указателя, используемый для перебора элементов в сложных коллекциях.


--------------------
Цитата(alina3000 @  6.3.2014,  10:47 Найти цитируемый пост)
Сорри что не по теме 
PM MAIL ICQ GTalk Jabber   Вверх
archimed7592
Дата 3.1.2008, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Внимательно прочитал статью. Всё отлично. Есть только одно замечание.

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Создать динамический многомерный массив средствами языка невозможно.

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


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
bsa
Дата 3.1.2008, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



archimed7592, ты имеешь в виду что-то типа:
Код
int (*p)[1][10] = (int (*)[1][10])malloc( sizeof(*p)*10 )
Я просто такими извратами не занимался, поэтому боюсь накосячить...
Так что этот пункт прошу проверить отдельно и с пристрастием.
PM   Вверх
archimed7592
Дата 3.1.2008, 14:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Цитата(bsa @  3.1.2008,  13:36 Найти цитируемый пост)
ты имеешь в виду что-то типа:

Да. На С++ это будет выглядеть так:
Код

int n;
std::cin >> n;
int (*arr)[5][6] = new int [n][5][6];


Теория тут следующая:
1. Скорость доступа [почти] такая же как у статических массивов.
2. Скорость создания такая же, как у одномерного динамического массива.
3. arr[i][j][k] == *((int *)arr + (i * 5 + j) * 6 + k) (могу ошибаться, но вроде так) - компилятор сам делает эти вычисления(как и со статическими массивами).
4. При создании такого массива, динамической может быть только первая(крайняя левая) размерность(остальные константы).


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

Это сообщение отредактировал(а) archimed7592 - 3.1.2008, 14:37


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
archimed7592
Дата 3.1.2008, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
#define ROW_COUNT 50

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


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
JackYF
Дата 3.1.2008, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 6
Всего: 162



Извиняюсь за занудность, но я же назначался вычитщиком? smile

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Массив это набор

Массив - это набор

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
а последний (N-1)

а последний - (N-1)

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Таким образом для

таким образом, для

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
достаточно, для организации

достаточно для организации

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Разве что sizeof(p) вернет размер

Разве что, sizeof(p) ...

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
И чтобы избежать утечек памяти нужно

И, чтобы избежать утечек памяти, нужно

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Чтобы этого не происходило нужно опять воспользоваться функцией memcpy():

... не происходило, нужно ...

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Для работы с ним, требуется подключить специальный модуль:

запятая не нужна

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
Но можно сэмитировать одним из двух способов:

сЫмитировать

У меня всё, сама статья понравилась.

Добавлено через 2 минуты и 43 секунды
Цитата(archimed7592 @  3.1.2008,  16:20 Найти цитируемый пост)
то отправлю к главреду

P.S. а кто главред?


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Alexeis
Дата 3.1.2008, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 4
Всего: 459



  Хотелось бы еще про динамические строки, как частный случай массивов переменной длинны. 

Цитата(JackYF @  3.1.2008,  15:33 Найти цитируемый пост)
P.S. а кто главред? 

Напрашивается ГлавВред smile 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
archimed7592
Дата 3.1.2008, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Цитата(JackYF @  3.1.2008,  16:33 Найти цитируемый пост)
P.S. а кто главред? 

Ты smile.


Цитата(Alexeis @  3.1.2008,  16:55 Найти цитируемый пост)
 Хотелось бы еще про динамические строки, как частный случай массивов переменной длинны.

Только если отдельной статьёй, а то слишком много получится(разве о них не написано в прикреплённой теме "указатели, строки, классы"?)


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
bsa
Дата 3.1.2008, 17:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(Alexeis @ 3.1.2008,  16:55)
Хотелось бы еще про динамические строки, как частный случай массивов переменной длинны.

Не. Разве что разместить ссылку на статью про строки, как частный вариант массивов. Но не более того.
А то мне уже самому страшно смотреть на то, что получилось - ОЧЕНЬ МНОГО!

Добавлено @ 17:16
Цитата(man 3 alloca)
CONFORMING TO
       There  is  evidence  that  the alloca() function appeared in 32v, pwb, pwb.2, 3bsd, and 4bsd.  There is a man page for it in 4.3BSD.  Linux
       uses the GNU version.  This function is not in POSIX.1-2001.
Думаю, упоминать alloca не стоит.

archimed7592: Оффтоп про alloca перенесён в отдельную тему.


Это сообщение отредактировал(а) archimed7592 - 10.1.2008, 23:51
PM   Вверх
Fazil6
Дата 3.1.2008, 17:48 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 7
Всего: 60



Цитата(bsa @  26.12.2007,  21:07 Найти цитируемый пост)
В языке С++ есть встроенные средства, для работы с динамической памятью - new[] и delete[]. Это аналоги calloc и free соответственно:

Цитата(bsa @  26.12.2007,  21:07 Найти цитируемый пост)
Но пользоваться ими не сильно удобней, чем аналогами из Си.

хм... почему это? 
Вообще тема new/delete нераскрыта...
Лучше статья будет читаться, если разбить ее хотябы на подразделы с собственными подзаголовками причем раз уж пытаешься объять необъятное, то четко разделить C и С++, а вообще как и раньше мои претензии по объему.
Опять же я, например, так и не понял почему рассмотрение началось с функции realloc , а не calloc и резонный вопрос почему для выделения памяти существуют 2 функции 
Цитата(bsa @  26.12.2007,  21:07 Найти цитируемый пост)
malloc, calloc - выделение памяти



Это сообщение отредактировал(а) Fazil6 - 3.1.2008, 17:49
PM MAIL   Вверх
archimed7592
Дата 10.1.2008, 22:51 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
int *p = (int*)calloc(256, sizeof(*p)); //выделение памяти под 256 элементов типа int
//это эквивалентно записи
int *p = (int*)malloc(256*sizeof(*p));

Ты уверен, что это эквивалентно? ;)
Могу заблуждаться, но, IIRC, помимо всего прочего, calloc инициализирует выделенную область памяти нулями.

Цитата(bsa @  26.12.2007,  22:07 Найти цитируемый пост)
realloc() функция другого уровня. Она позволяет выделять, освобождать и изменять размер области памяти, которая выделена функциями realloc(), malloc() или calloc():

У меня будет маленькая просьба, относительно realloc: либо из статьи вообще убрать упоминания(как в тексте, так и в коде) о том, что с помощью realloc можно и выделять и освобождать память, либо вынести это в примечание. Для этого есть несколько причин:
1. Информация "излишняя" т.е., воспользовавшись этой информацией, новичек не сможет сделать ничего такого чего он не мог бы сделать с помощью malloc+free.
2. Использовать realloc как универсальную ф-цию нужно в достаточно редких случаях и отличить эти случаи от тех, где надо бы воспользоваться malloc+free сможет не каждый новичек, а, как следствие, статья некоторых новичков статья научит плохому стилю, чего хотелось бы не допускать.


И ещё одна просьба: насколько я понял ты отделил Си от С++(я чесслово уже не помню как было прежде). Дык вот, информация о многомерных массивах осталась в "смешанном" виде - нужно разделить. Потом посмотрим, но учти, что, скорее всего, будем делить на две статьи(одна для Си, другая для плюс-плюс).

Добавлено @ 22:53
Кстати, если про calloc не заблуждаюсь, то неплохо было бы об этом написать.

M
archimed7592
Немного почикал тему. Не обижайтесь, чьи неинформативные посты поудалял - свои удалил тоже :-D.


Это сообщение отредактировал(а) archimed7592 - 10.1.2008, 23:55


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

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

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1430 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.