Динамическое выделение памяти

Язык C++ / Динамическое выделение памяти

 

В С работать с динамической памятью можно при помощи соответствующих функций распределения памяти (calloc, malloc, free), для чего необходимо подключить библиотеку

#include <malloc.h>

С++ использует новые методы работы с динамической памятью при помощи операторов new и delete:

  • new — для выделения памяти;
  • delete — для освобождения памяти.

Оператор new используется в следующих формах:

new тип;  // для переменных
new тип[размер];  // для массивов

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

int *ptr_i;
double *ptr_d;
struct person *human;
...
ptr_i = new int;
ptr_d = new double[10];
human = new struct person;

Память, отведенная в результате выполнения new, будет считаться распределенной до тех пор, пока не будет выполнена операция delete.

Освобождение памяти связано с тем, как выделялась память – для одного элемента или для нескольких. В соответствии с этим существует и две формы применения delete:

delete указатель;  // для одного элемента
delete[] указатель;  // для массива

Например, для приведенного выше случая, освободить память необходимо следующим образом:

delete ptr_i;
delete[] ptr_d;
delete human;

Освобождаться с помощью delete может только память, выделенная оператором new.
Пример Создание динамического массива

#include <iostream>
using namespace std;
int main() {
  int size;
  int *dan;
  system("chcp 1251");
  system("cls");
  cout << "Ввести размерность массива: ";
  cin >> size;
  dan = new int[size];
  for (int i=0; i<size; i++) {
    cout << "dan[" << i << "]= ";
    cin >> dan[i];
  }
  for (int i=0; i<size; i++)
    cout << dan[i] << " ";
  delete[] dan;
  cin.get(); cin.get();
  return 0;
}

Результат выполнения
Операторы new и delete

Указатель dan – базовый адрес динамически распределяемого массива, число элементов которого равно size. Операцией delete освобождается память, распределенная при помощи new.
Назад


Назад: Язык C++

Комментариев к записи: 17

  • Почему то не могу ответить на ваш пост, поэтому приходтся создать новую ветку.
    условия задачи:

    Возводить в степень можно гораздо быстрее, чем за n умножений! Для этого нужно воспользоваться следующими рекуррентными соотношениями:

    an = (a2)n/2  при четном n,

    an = a × an−1 при нечетном n.

    Реализуйте алгоритм быстрого возведения в степень с помощью рекурсивной функции.
    Формат входных данных
    Вводятся действительное число a и целое неотрицательное число n.
    Формат выходных данных

    Выведите ответ на задачу.
    Но следующая задача которую надо решить тоже с помощью рекурсии это найти все возможные расстановки ферзей.

    Дано число N. Определите, сколькими способами можно расставить на доске N×N N ферзей, не бьющих друг друга.

    Формат входных данных

    Задано единственное число N. (N ≤ 10)

    ///////////////////////////////
    Но если сосчитать все возможные варианты расстановки ферзей на поле это 8 в степени 64?
    или 8 в степени 8 Но даже если это просто 8^8 то это будет 16.777.216!!!
    Задачку с рекурсиями дает Yandex а с длинными строчками Mail.ru Выглядит так что уметь решать их для них это очень важно.

     


  • Вот у меня стоит задача создать функцию, которая будет динамически увеличивать размер строки.
    Но вот засада, данный код принимает размер строки длинною только в 4094 символа. Почему так происходит? И как это можно обойти?

    #include <iostream>
    #include <cstring>
    char *resize(const char *str, unsigned size, unsigned new_size);
    char *getline();
    using namespace std;

    int main()
    {
    char *s;
    s= getline();
    cout<<s<<endl;
    }
    // Принимает строку, размер этой строки, новый размер строки, возвращает указатель на новую строку.
    char *resize(const char *str, unsigned size, unsigned new_size)
    {
    char *ns = new char [sizeof(char)*new_size];
    for (unsigned i=0;i<new_size&&i<size;i++)
    {
    ns[i]=str[i];
    }
    delete []str;
    return ns;
    }
    // Получаем строку и увеличиваем ее понеобходимости.
    char *getline() //
    {
    unsigned j=1;    //размер массива
    char *temp= new char [j]{‘\0’};
    char c;
    while(std::cin.get(c) && c != ‘\n’ && c != std::cin.eof())
    {
    temp[j-1]=c;
    temp=resize (temp,j,++j);
    }
    temp[j-1]=’\0′;
    return temp;
    }


    • Елена Вставская

      Честно говоря, не сталкивалась с подобной проблемой, но она действительно имеет место.
      Может быть, можно ввести данные в несколько строк?


      • К сожалению это невозможно. Необходимо обработать строку длиною в тысяч сто символов.
        PS прохожу курс на Stepic.org https://stepik.org/lesson/542/step/10
        Там никто не отвечает. На форумах сидят такие же как и я, ничего не знают. Поэтому решил тут спросить)

        В параллейном курсе stepic https://stepik.org/lesson/13027/step/12 необходимо создать рекурсию которая будет способна возвести 1.000001 в степень 1000000
        Но при такой глубине у меня рекурсия не работает. Происходит переполнение стека.

        Как же работать с памятью то?


        • Елена Вставская

          А вот с этой задачей, видимо предполагается использование динамического программирования.
          1,000001 * 1,000001 = 1,000002000001
          1,000002000001 * 1,000001 = 1,000003000003000001
          и т.д.
          То есть надо выявить закономерность, как изменяется число при умножении его на 1,000001 и в соответствии с этим сформировать результат.
          P.S. В результате получится число e.


          • Так рекурсивная функция должна правильно обработать все возможные возведения в степень,
            не только 1.000001 в степени 1000000
            да и на третем шаге число 1,000003000003000001 уже выйдет за пределы всего что только можно.
            a^n = (a^2)^(n/2)  при четном n,
            a^n = a × a^(n−1) при нечетном n.
            Рекурсию то я создал. Но она не может уйти в глубину на 1.000.000 Максимум можно уйти в глубь около 86.674 раза. А по условию задачи необходимо что бы рекурсия была способна войти вглубь на 1.000.000.
            ////////////////////////////////////////////////////////////////////////////////////////////////
            #include <iostream>
            using namespace std;
            double m(double a, unsigned int n);
            double mm(double a, double n);
            int main()
            {
            double a=1.000001;
            unsigned int b=10000; // максимально возможная степень:86674
            if (b%2==0)cout<< mm (a,b);
            if (b%2!=0)cout<< m(a,b);
            }
            double m(double a, unsigned int n)
            {
            if (n==0)return 1;
            return a*m(a,n-1);
            }
            double mm(double a, double n)
            {
            if (n==0)return 1;
            return (m(m(a,2),(n/2)));
            }
            ///////////////////////////////////////////////////////////////////
            PS в 50-60% случаях при вооде защитного кода графическая надпись не обновляется, поэтому происходит неверный ввод кода. И после неверного ввода весь текст что был введен пропадает, очень обидно.
            То есть можно зайти на одну и туже страницу 10 раз и всегда будет одно и тоже графическое число например: «Шесть тысяч восемьсот восемьдесят два». Но данный код неверный. Перезагрузка страницы F5 не помогает.


          • Елена Вставская

            А как предлагает решать задачу тот, кто условие придумал?
            P.S. Отключила на время кэширование сайта, чтобы избежать проблемы с капчей. Посмотрим, будет лучше или хуже.


  • я написал программу как мне устанавливать на другие компьютеры и как выложить в интернет


    • Елена Вставская

      Проще всего выложить вконтакте или на github.com.
      Но можно создать свой сайт и заниматься его оформлением и наполнением.
      А вообще пока у меня до обучения размещению информации в Интернете дело не дошло 🙂


  • А реально ли создать или написать чтобы выложить в интернет чтобы все скачивали и пользовались что я создам на языке c++?


  • Увы нет Елена. Ранее я уже писал на форуме в теме http://prog-cpp.ru/c-alloc/. Решил использовать этот же алгоритм:

    /*

    This prog introduces an advanced input in dynamic array.

    The array is pretty clever. Its reallocates itself memory

    as same as its need. The another pretty thing: very

    comfortable input.

     

    Dont be disapeared if you′ll see, the same output on screen.

    Prog created in used only for concept idea, how its good

    can to be to use this input.

    To example: input a row of numbers 1 2 3 4 5

    then press Enter, to continue input 5 4 3 2 1

    press Enter again. For another way — break —

    press ESC. Pressing ESC again will terminate the

    prog, but pressing any key will free array and let

    to continue input the new array.

    Be careful, amount of numbers in string must

    equial with another string. Else prog will

    terminate with the error code.

    */

    #include <iostream>

    #include <conio.h>

     

    #define ESC 27

    #define EOS ′\n′

     

    using namespace std;

     

    int main() {

    do {

    system("CLS");

    //creating the dynamic array[0][0] with only one free space

    float **a = (float**)malloc(sizeof(float*));

    a[0] = (float*)malloc(sizeof(float));

    int volume = 0, i = 0;//volume contains used space(bytes) in array, ′i′ need for counting below

    do {

    cout << "Enter " << i + 1 << " string: ";

    do {

    cin >> a[i][_msize(a[i]) / sizeof(float) — 1];//the ′j′ is memory of *p divided by 4, for first one 4/4 = 1, next 8/4 and etc

    if (cin.rdbuf()->in_avail() != 1) a[i] = (float*)realloc(a[i], _msize(a[i]) + sizeof(float));//realocates memory only if buffer contains more then 1 number in stack

    } while (cin.get() != EOS);//while not in the end of buffer >′cin′

     

    volume += _msize(a[i]);//increases volume 4/8/16 and etc

     

    a = (float**)realloc(a, _msize(a) * sizeof(float*));//reallocates new pointer

    a[i+1] = (float*)malloc(sizeof(float));//allocates memory for new p[]

    i++;

    } while (_getch() != ESC);//while you dont press ESC

    cout << endl << "Result achived:" << endl << endl;

    volume /= _msize(a[0]);//strings in array calc

    //output on screen

    for (int i = 0; i < volume; i++) {

    for (int j = _msize(a[i]) / sizeof(float); j > 0; j—) {//′j′ is a amount of numbers in string, 1 1 1 1 all size is 16, divided by 4 = 4

    cout << a[i][_msize(a[i]) / sizeof(float) — j] << " ";

    }

    cout << endl;

    free(a[i]);//frees memory in *p

    }

    free(a);//frees memory in **p

     

    } while (_getch() != ESC);//while you dont press ESC

    return 0;

    }

    Вот тут в прототипе все работает корректно. Однако при попытке создании структуры что-то пошло не так.


    • Елена Вставская

      А где в Вашей реализации строки

      float **a = (float**)malloc(sizeof(float*));
      a[0] = (float*)malloc(sizeof(float));

      ???
      Это и есть изначальное выделение памяти — то, о чем я говорила.


      • То есть, вы хотите сказать что:

        typedef struct {    
        float **matrix;
        }matrix;
        A.matrix = (float**)malloc(sizeof(float));
        A.matrix[0] = (float*)malloc(sizeof(float));

        Не эквивалентно:

        float **a = (float**)malloc(sizeof(float*));
        a[0] = (float*)malloc(sizeof(float));

        • Елена Вставская

          Борис,
          1) В функции input_matrix(matrix m) Вы работаете с копией матрицы, а не с ее оригиналом, поэтому после возврата из функции введенные данные недоступны. Один из способов решения этой проблемы:

          matrix input_matrix(matrix m) {

          return m;
          }

          2) Я не поняла назначение цикла dowhile в main(), но у меня он работать отказывается.
          3) Очистка памяти в конце функции производится неверно. Один из вариантов очистки памяти

          int h = A.volume / _msize(A.matrix[0]);
          // это вычисление обязательно сделать до цикла, поскольку количество строк в цикле будет меняться
          for(int i=0; i<h; i++)
          free(A.matrix[i]);
          free(A.matrix);


  • Доброго времени суток!

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

    Привожу пример кода:

    #include <iostream>
    #include <conio.h>
    #define ESC 27
    #define′\n′
    using namespace std;
     
    typedef struct {
        float **matrix;
        unsigned int volume;
        char name;
    }matrix;
     
    //функция ввода.
    void input_matrix(matrix m) {
        //если значения вводились ранее, удалить текущую матрицу
        if (m.volume != 0) {
            m.volume /= _msize(m.matrix[0]);
            for (int i = 0; i < m.volume; i++) {
                free(m.matrix[i]);
            }
            free(m.matrix);
            m.volume = 0;
        }
     
        int i = 0;
     
        do {
            cout << "Enter " << i + 1 << " string of matrix " << m.name << ": ";
            do {
                cin >> m.matrix[i][_msize(m.matrix[i]) / sizeof(float) — 1];  //текущий размер массива / размер типа = кол-во элементов в массиве. -1 это свободная ячейка
                if (cin.rdbuf()->in_avail() != 1) m.matrix[i] =
                    (float*)realloc(m.matrix[i], _msize(m.matrix[i]) + sizeof(float));  // если в очереди буфера больше 1 символа, записать и увеличить массив m[]
            } while (cin.get() != EOS);   //считать все из буфера cin, то есть до ‘\n’
            m.volume += _msize(m.matrix[i]);                      //суммирую кол-во затрачиваемой памяти
            m.matrix = (float**)realloc(m.matrix, _msize(m.matrix) * sizeof(float*));   //увеличить массив m
            m.matrix[i + 1] = (float*)malloc(sizeof(float));       //выделить память под новые элементы m[]
            i++;
        } while (_getch() != ESC);  //пока не нажал ESC повторять, увеличивая строки массива
    }
    //функция вывода на консоль
    void out_matrix(matrix m) {
        cout << "Matrix " << m.name << ":" << endl;  //вывод имени матрицы
        for (int i = 0; i < m.volume / _msize(m.matrix[0]); i++) {                  // подсчет строк путем деления общего объема на длину строки
            for (int j = _msize(m.matrix[i]) / sizeof(float); j > 0; j—) {         //подсчет элементов путем деления длины строки на тип памяти(float = 4)
                cout << m.matrix[i][_msize(m.matrix[i]) / sizeof(float) — j] << " "; //вывод элементов
            }
            cout << endl;
        }
        cout << endl;
    }
     
    int main() {
        //для примера я создам объект структуры с названием А
        matrix A;
        A.matrix = (float**)malloc(sizeof(float));
        A.matrix[0] = (float*)malloc(sizeof(float)); //выделяю 4 байта, 1 ячейка
        A.name = ′A′;   //имя задам константно
        A.volume = 0;   //начальный объем
     
        do {
            input_matrix(A);
            out_matrix(A);
            cout << "Volume: " << A.volume << endl;
        } while ( _getch() != ESC);
     
      for (int i = 0; i < A.volume; i++)      
    free(A.matrix[i]);
      free(A.matrix);
    return 0;
    }

    • Елена Вставская

      Я, конечно, не уверена на 100%, но по-моему ошибка состоит в том, что когда Вы вводите элементы первой строки матрицы, указатель на эту строку еще не определен — операция

      m.matrix = (float**)realloc(m.matrix, _msize(m.matrix) * sizeof(float*)); //увеличить массив m

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


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *