Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.72/25: Рейтинг темы: голосов - 25, средняя оценка - 4.72
0 / 0 / 0
Регистрация: 27.11.2014
Сообщений: 20

Освобождение динамической памяти

25.12.2018, 16:19. Показов 4668. Ответов 23
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, объясните, пожалуйста, как правильно удалять выделенную динамическую память? Вот пример задачи, где массив произвольного размера может быть введен пользователем или взят из файла. Соответственно при вызове соответствующей функции выделяется память, массив вводится и сохраняется в выделенной памяти, чтобы его можно было вывести на экран. Если после этого снова вызывается функция ввода массива пользователем/из файла, то ранее выделенная память должна быть удалена, а новая выделиться, но компилятор мою интерпретацию такой логики не поддерживает.

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <cstring>
#include <conio.h>
#include <fstream>
 
using namespace std;
 
void menu()
{
    cout << "1 - Ввести массив с клавиатуры"<<endl;
    cout << "2 - Ввести массив из файла" << endl;
    cout << "3 - Вывести массив на экран" << endl;
}
 
int* Input(int Arsize)
{
    int *arr = new int[Arsize];
 
    for (int i(0); i < Arsize; i++)//заполнение массива
    {
        cout << "Введите " << i+1 << "-ый элемент массива" << endl;
        cin >> arr[i];
    }
    return arr;
}
 
void Output(int * Arr, int arsize)
{
    for (int i(0); i < arsize; i++)//вывод массива
    {
        cout << *(Arr + i) << " ";
    }
    cout << endl;
}
 
 
int main()
{
 
    using namespace std;
    setlocale(LC_ALL, "Russian");
    int* massiv=NULL;
    int size;
    int temp;
    char choice;
 
    ofstream fout;
    ifstream fin;
 
    do
    {
        system("cls");
        menu();//вызов меню
 
        cin >> choice;
        switch (choice)
        {
        case '1': //ввод массива с клавиатуры
        {
            delete [] massiv;
            cout << "введите размерность массива" << endl;
            cin >> size;
            massiv = Input(size);
            break;
        }
 
        case '2':
        {
            delete [] massiv;
            fin.open("textfile.txt");
            if (!fin.is_open())
            {
                cout << "файл не найден";
                _getch();
                break;
            }
 
            int i = 0;
            while (!fin.eof()) //сосчитаем кол-во членов в массиве в текстовом файле
            {
                fin >> temp;
                i++;
                size=i;
            }
            //cout << size << endl; //вывод количества файлов в массиве
 
            int *massiv = new int[size];
            //massiv = NULL;
 
            fin.seekg(0);//перевод каретки в начало строки
 
            for (int i(0); i < size; i++)
            {
                fin >> massiv[i];
                cout << massiv[i] << " ";
            }
 
            _getch();
            break;
        }
 
        case '3': //вывод массива на экран
        {
            system("cls");
            if (massiv == NULL)
                cout << "массив пустой" << endl;
            else
                Output(massiv, size);
            _getch();
            break;
        }
 
    } while (choice !='q');
 
    return 0;
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.12.2018, 16:19
Ответы с готовыми решениями:

Освобождение динамической памяти
После первого вызова функции(при повторном) пишет ошибку. В функции sort один из элементов массива становится недоступным для чтения. Если...

Освобождение динамической памяти
Здравствуйте! Была задача реализовать сложение длинных чисел с помощью стеков. Сам стек реализовал просто, но всё же проблемы есть -...

Освобождение динамической памяти в vs
Вообщем попался я тут, и так, код: //#define _CRT_SECURE_NO_WARNINGS добавить в vs #include &lt;iostream&gt; #include...

23
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
25.12.2018, 17:02
87 строка: создаете локальную переменную, перекрывающую глобальную. Выделяете под нее память, но не освобождаете.
60, 69 строки: возможна попытка освобождения невыделенной памяти
17 строка: не проверяете успешность выделения памяти (грубая ошибка)
116 строка: не освобождаете память в конце программы
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
25.12.2018, 17:11
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
17 строка: не проверяете успешность выделения памяти (грубая ошибка)
Это не ошибка, это системная функция.
1) Стандартный new в случае ошибки не возвращает nullptr, а выбрасывает исключение.
2) Выбрасывает если повезет. Ибо если используется overcommit, об ошибке вы узнаете лишь при попытке записать в "выделенную" память.
0
0 / 0 / 0
Регистрация: 27.11.2014
Сообщений: 20
25.12.2018, 17:56  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
87 строка: создаете локальную переменную, перекрывающую глобальную. Выделяете под нее память, но не освобождаете.
А есть что-то плохое в том, что переменная в процессе программы приобретает другое значение? Объявить massiv перед case было необходимо, потому что если объявлять ее внутри одной метки, внутри других она видна не будет.
Как правильно освободить память? Нельзя же удалить её сразу после заполнения массива

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
60, 69 строки: возможна попытка освобождения невыделенной памяти
Добавляю вот такую проверку
C++
1
2
    if (!(massiv == NULL))
        delete[] massiv;
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
17 строка: не проверяете успешность выделения памяти (грубая ошибка)
Как это сделать?

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
116 строка: не освобождаете память в конце программы
Добавил в конце
C++
1
2
3
4
} while (choice !='q');
    return 0;
    delete[] massiv;
}
Если пытаться записать из файла после заполнения с клавиатуры, то с первой попытки массив из файла выводится, со второй выводится абракадабра, а на третьей ничего не происходит. если сразу записывать из файла, срабатывает ошибка как раз на второй метке
C++ (Qt)
1
delete[] massiv;
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
25.12.2018, 18:24
Цитата Сообщение от Renji Посмотреть сообщение
1) Стандартный new в случае ошибки не возвращает nullptr, а выбрасывает исключение.
Я не говорил "проверять на nullptr", я говорил "проверять успешность выделения".
Какая разница, будет ли это if или try-catch? Все равно программа не может продолжать выполнение если не смогла выделить память. Такие ошибки надо отлавливать всегда.
Цитата Сообщение от kousnetsov Посмотреть сообщение
А есть что-то плохое в том, что переменная в процессе программы приобретает другое значение? Объявить massiv перед case было необходимо, потому что если объявлять ее внутри одной метки, внутри других она видна не будет.
Само по себе это не плохо, вот только вы пользуетесь данной возможностью неправильно. Между метками виден тот massiv, который глобальный, а не тот который локальный. Это две разные переменные. Просто удалите объявление локальной.
Цитата Сообщение от kousnetsov Посмотреть сообщение
Как правильно освободить память? Нельзя же удалить её сразу после заполнения массива
Как обычно: удаляем как только она стала ненужной. Либо перед выделением нового массива взамен старого, либо при выходе из программы.
Цитата Сообщение от kousnetsov Посмотреть сообщение
Как это сделать?
Для выделения памяти в стиле Си:
C
1
2
3
4
massiv = (int*)malloc(sizeof(int)*Arsize);
if(massiv == NULL){/*ошибка!*/}
...
free(massiv);
В стиле С++:
C++
1
2
3
4
5
try{
  massiv = new int[Arsize];
}catch(std::bad_alloc){
  /*ошибка*/
}
на С++ в стиле Си:
C++
1
2
noexcept(massiv = new int[Arsize]);
if( massiv == NULL ){/*Ошибка*/}
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
25.12.2018, 18:33
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Какая разница, будет ли это if или try-catch? Все равно программа не может продолжать выполнение если не смогла выделить память. Такие ошибки надо отлавливать всегда.
Разница в том, что не обработанные исключения и так уже гарантированно вызывают std::terminate. Минимальная обработка таких ошибок уже сделана компилятором. А не минимальная в данном случае непонятно кому и зачем нужна.
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
25.12.2018, 19:32
Угу. А потом в более сложной программе не возникнет даже мысли поставить проверку, поскольку привычки нет. И будет ТС искать проблему где угодно, но не в операторе new, или недооткрытом файле, который точно так же поленился проверить, или еще в каком не менее дурацком месте.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
25.12.2018, 20:35
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Угу. А потом в более сложной программе не возникнет даже мысли поставить проверку, поскольку привычки нет. И будет ТС искать проблему где угодно, но не в операторе new, или недооткрытом файле, который точно так же поленился проверить, или еще в каком не менее дурацком месте.
Давайте с ТЗ определимся.
Если стоит задача найти проблему с отладчиком, он сам подсветит необработанный throw.
Если стоит задача найти проблему без отладчика, надо минимум стек-трейс делать. Потому как что толку от диагностического сообщения "где-то вылетел bad_alloc, подробности неизвестны"? Но стек-трейс это для топикстартера явно слишком круто.
Если же стоит задача просто аварийно закрыть программу, так это уже компилятор сделал.
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
25.12.2018, 23:16
Моя задача в данном случае - приучить ТСа всегда делать проверку возвращаемого значения, всегда явно освобождать память и закрывать открытые ресурсы (вроде файлов). Если это дойдет до автоматизма на учебных примерах, он не будет отвлекаться на подобную рутину в будущем. А это чуть более информативные сообщения об ошибках программы вроде "программа упала степенно завершилась, поскольку не удалось выделить 100500 ГБ памяти. Временные файлы удалены, сетевые подключения закрыты"
Сколько раз уже видел здесь как новички даже открытие файла не проверяют, а потом жалуются "почему программа не работает". А она просто входной файл не там ищет.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
26.12.2018, 00:10
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Моя задача в данном случае - приучить ТСа всегда делать проверку возвращаемого значения, всегда явно освобождать память и закрывать открытые ресурсы (вроде файлов).
Для закрытия файлов деструктор есть. Опять же, вызываемый при броске исключения автоматически. Разумеется, если функция использует возвращаемое значение чтобы рапортовать об ошибке, это значение надо проверять. Но функции полагающиеся на механизм исключений, несколько на иной механизм обработки ошибок рассчитаны. И не надо пытаться забивать шурупы молотком.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Сколько раз уже видел здесь как новички даже открытие файла не проверяют, а потом жалуются "почему программа не работает". А она просто входной файл не там ищет.
Это не проблема новичков. Это проблема кривого дизайна std::ifstream, который рапортует об ошибке конструктора через флаг ошибки. Тогда как люди нормальные (например, писавшие std::vector) при сбое конструктора кидают исключение.
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
26.12.2018, 00:44
Программа может захватывать не только std::ifstream файлы. И далеко не для все из них оформлены в виде объектов с деструкторами.
Цитата Сообщение от Renji Посмотреть сообщение
Это не проблема новичков. Это проблема кривого дизайна std::ifstream
Да они ничего не проверяют. Ни std::ifstream, ни new, ни fopen, ни malloc. Проблема тут не в дизайне конкретного ресурса, а в самом подходе.
Цитата Сообщение от Renji Посмотреть сообщение
Тогда как люди нормальные (например, писавшие std::vector) при сбое конструктора кидают исключение.
Исключения далеко не самый эффективный способ обработки ошибок. Та же проверка возвращаемого значения гораздо быстрее и проще.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
26.12.2018, 01:14
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Программа может захватывать не только std::ifstream файлы. И далеко не для все из них оформлены в виде объектов с деструкторами.
Ну, Си-стайл код это отдельная песня. Хотя, ничто не мешает обернуть fopen в файловый класс.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Исключения далеко не самый эффективный способ обработки ошибок. Та же проверка возвращаемого значения гораздо быстрее и проще.
Как раз сложнее.
Во-первых, что будем делать с ошибками в функциях типа std::log? Проверять возвращаемое значение - нельзя впихнуть std::log в выражение. Использовать errno - глобальная переменная и проблемы с потокобезопасностью (да, errno сделали thread_local, но он не бесплатен).

Во-вторых, обработка ошибок это по большей части просто "заверши функцию и перебрось код ошибки дальше". И только пять return спустя исполнение добирается до обработчика ошибок рисующего красивое окошко "что-то сбойнуло". Исключения это перебрасывание делают сами, а с кодами ошибки лишняя писанина.

А скорость - зависит от реализации обработчика исключений. Его можно делать и в стиле "все накладные расходы переносятся на момент возбуждения ошибки" (а этот момент возможно и не настанет никогда).
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
26.12.2018, 08:25
Как минимум, в "красивом окошке" написать где именно возникла ошибка. Какой именно файл недоступен, сколько именно памяти не хватило.
Если ошибка возникла во время записи логов (что с ними вообще может случиться, файл что ли не создается?) напрямую сообщить пользователю что пошло не так и как это исправить.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
26.12.2018, 17:00
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Как минимум, в "красивом окошке" написать где именно возникла ошибка. Какой именно файл недоступен, сколько именно памяти не хватило.
Это все надо писать не в окошке, а в std::exception::what. А окошко должно лишь показывать что в what написано. Другой вопрос, что стандартные исключения не пишут туда ничего кроме своего названия. Вот здесь собственно мы и подходим к написанию трассировки стека (место ошибки сохранять) и запихиванию ее в конструктор исключения. Ну или как минимум:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<cstdio>
#include<exception>
 
#define ERROR_POS __FILE__,__LINE__,__FUNCTION__
class MyException:public std::exception
{
public:
    MyException(const char*file,int line,const char*function)
    {
        snprintf(data,1024,"error in file %s line %d function %s",file,line,function);
    }
 
    const char*what()const noexcept{return data;}
 
    char data[1024];
};
 
int main()
try
{
    throw MyException(ERROR_POS);
    return 0;
}
catch(const std::exception&error)
{
    std::cout<<error.what()<<std::endl;
}
0
 Аватар для COKPOWEHEU
4078 / 2676 / 432
Регистрация: 09.09.2017
Сообщений: 11,885
27.12.2018, 10:26
Цитата Сообщение от Renji Посмотреть сообщение
окошко должно лишь показывать что в what написано
Нет-нет, в окошке должна быть только простейшая информация для пользователя если он может что-то исправить. Проверить правда доступа, наличие памяти, сети, некорректные данные и т.д., возможно с адресом лога. А вот уже в лог сбрасывать основную информацию для разработчика.
Разумеется, я говорю об общих принципах обработки ошибок. Какой конкретно механизм при этом будет использоваться - проверка возвращаемого значения, проверка errno, отлов исключений - безразлично.
Возвращаясь к теме дискуссии, я настаиваю на обязательной проверке всего что может сломаться, особенно в учебных программах. Ну, разве что арифметику уж слишком сложно проверять каждый раз, да и вероятность такой ошибки невелика.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
27.12.2018, 16:27
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Возвращаясь к теме дискуссии, я настаиваю на обязательной проверке всего что может сломаться, особенно в учебных программах.
Возвращаясь к теме дискуссии, проверить корректность выделения памяти в современных условиях де-факто просто невозможно. Не знаю как Винда, но Линукс по умолчанию позволяет выделять памяти больше чем ее есть физически (оверкоммит). Типа, с прицелом на программы хапающие много памяти "про запас", но по факту не использующие хапнутое. При попытке в эту память что-то записать приходит OOM Killer и убивает кого попало. И никак ты это не отследишь.
1
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
27.12.2018, 17:19
Цитата Сообщение от Renji Посмотреть сообщение
Не знаю как Винда, но Линукс по умолчанию позволяет выделять памяти больше чем ее есть физически (оверкоммит).
Да, на винде аналогично.
Цитата Сообщение от Renji Посмотреть сообщение
приходит OOM Killer и убивает кого попало. И никак ты это не отследишь.
А вот этого у винды нету.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
27.12.2018, 17:22
Цитата Сообщение от Azazel-San Посмотреть сообщение
А вот этого у винды нету.
Хм, а как тогда предлагается отрабатывать ситуацию "при попытке записи надо связать страницу виртуальной памяти с физической, но памяти нема"? Кто запросил связывание, того и по башке?
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
27.12.2018, 17:44
Renji, насколько я помню, если у нас не хватит физической памяти винда сделает файл подкачки (с n-ым размером) и будет пихать туда, затем если этого не хватит она просто начнет увеличивать размер файла подкачки (цифры могут быть поражающие психику), ну и когда и этот файл подкачки закончится (подойдет к какому-то лимиту, когда уже дальше некуда) у винды не остается ничего как экстренно кого-то убить.

Добавлено через 11 минут
Хотя в современных реалиях винда вроде даже перед тем как выделить виртуальную память процессу проверит есть ли место под файл подкачки, вдруг если понадобится и сейчас файлы подкачки себе не позволяют расти так немеренно, а при критических стиациях его не хватки вроде рандомно убивать не будет, начнут всякие Explorerы/видео драйвера лагать, те выполнение замедляется.

зы Т.е. самой поддержки оверкомита у винды нету, но ВП разрешает выделять памятит больше чем есть физической.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
27.12.2018, 17:45
Цитата Сообщение от Azazel-San Посмотреть сообщение
Renji, насколько я помню, если у нас не хватит физической памяти винда сделает файл подкачки (с n-ым размером) и будет пихать туда, затем если этого не хватит она просто начнет увеличивать размер файла подкачки (цифры могут быть поражающие психику), ну и когда и этот файл подкачки закончится (подойдет к какому-то лимиту, когда уже дальше некуда) у винды не остается ничего как экстренно кого-то убить.
Я не про своп. Я про то что Линукс допускает код вида:
C++
1
2
3
    //сто тысяч раз по гигабайту!
    for(int i=0;i<100000;++i)
        new char[1<<30];
При том что ясное дело, ста терабайт свопа нигде не наблюдается.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.12.2018, 17:45
Помогаю со студенческими работами здесь

Освобождение и выделение динамической памяти
Привет народ, такой вопрос: Допустим в main, указателю выделил память, всё разумеется нормально, читаю пишу всё ок, потом передал этот...

Выделение и освобождение динамической памяти в функциях
Каким образом происходит выделение и очистка динамической памяти для массивов (в частности) в функциях? Написал код, но почему то ошибка...

Освобождение динамической памяти из-под прямоугольной матрицы
Добрый вечер! При попытке очищения памяти после завершения работы программы с прямоугольной матрицей m на n мне выдаёт ошибку а-ля...

Резервирование памяти/освобождение памяти для трехмерного массива
Необходимо создать трехмерный массив (A), в котором элементы вдоль направления Z выли бы выровнены по 16 байт. Есть две проблемы: ...

Освобождение памяти в C++
Добрый день! В моей программе в функции выделяется память (new char) под символьный массив, который является элементом структуры. Это...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru