Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.99/89: Рейтинг темы: голосов - 89, средняя оценка - 4.99
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170

Массивы: Если размер массива неизвестен

27.02.2016, 22:05. Показов 18267. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте уважаемые программисты! Объясните пожалуйста, как правильно(по стандартам С++) создавать массив, который в процессе работы программы будет расширяться, но заранее не известно на сколько? Т.е. какой именно размер указывать? К примеру может есть какой-то максимальный размер или всегда нужно учитывать особенности программы в которой используется массив и примерно выставлять?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
27.02.2016, 22:05
Ответы с готовыми решениями:

Ввод в массив, размер которого заранее неизвестен
Здравствуйте! Помогите решить проблему. При компиляции кода выдает ошибку. Скрин ошибки во вложении. Идея в том, что бы организовать...

Как записать массив числовых данных в Excel, если размер массива заранее неизвестен
Здравствуйте! Подскажите как записать массив числовых данных в Excel, если размер массива заранее неизвестен + заголовки столбцов массива...

Как при уменьшении экрана центрировать картинку, если размер её изначально неизвестен
Неужели решения этой задачи средствами css так и нету? как при уменьшении экрана центрировать картинку если размер её изначально не...

17
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
27.02.2016, 22:12
std::vector
1
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
27.02.2016, 22:19  [ТС]
Но если я еще не проходил вектора, и мне нужно в программе реализовать такой массив? это первое, а второе по стандарту размер массива константа, хотя я сомневаюсь что у меня всегда она остается константой, да и вообще я не понимаю если по стандарту опять же размер массива константа, а часто приходиться низлогать ее если так можно выразиться...почему так? парадокс какой-то...типа необъяснимый потому-что просто так устроен компьютер, как к примеру некоторые вещи объясняются таким способом про нюансы в ассемблере?
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
27.02.2016, 22:26
Лучший ответ Сообщение было отмечено vikiroy как решение

Решение

Цитата Сообщение от vikiroy Посмотреть сообщение
Но если я еще не проходил вектора
Динамическая память тогда.
1
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
27.02.2016, 22:31  [ТС]
Динамическая память тогда
Спасибо! Наверное ваши ответы полноценны, просто у меня не было еще темы даже про динамическую память...может мне значит рано еще об этом думать, но в задаче автор хочет как-бы реализовать, может есть еще какой-то способ? если нет, тогда обойдусь константным большим каким-то массивом или путем проб и ошибок найду примерно такой размер который будет соответствовать моему условию!
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
27.02.2016, 22:32
Цитата Сообщение от vikiroy Посмотреть сообщение
Наверное ваши ответы полноценны
Очень далеко от правды, но я сейчас не в состоянии вести полноценный диалог
1
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
27.02.2016, 22:39  [ТС]
Я понял, ну-ладно, бывает)))

Добавлено через 3 минуты
Может кто-то еще подскажет?
0
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 30
28.02.2016, 00:32
Цитата Сообщение от vikiroy Посмотреть сообщение
Может кто-то еще подскажет?
например, так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    int Size = 100 ; // пусть нам надо 100 ячеек памяти
    char *My_Arr = new char [Size] ; // создадим указатель на массив типа char
    //  и запросим у операционной системы подряд Size ячеек памяти типа char для нашего массива
    // массив готов к использованию
    // посмотрим, например, что хранилось в этих ячейках памяти до нас
    for (int i = 0 ; i < Size ; i = i + 1 )
    {
    std::cout << My_Arr[i] << " " ; // напечатаем каждый элемент массива через пробел
    }
    std::cout << "||" << std::endl ; // закончим печать двумя черточками и перейдем на новую строку
    delete [] My_Arr ; // нам больше не нужна эта память, поэтому вернем её операционной системе
                        // теперь мы не знаем, что будет там храниться, т.к. это уже не наша память
    Sleep (10000) ; // подождем 10сек, чтобы окно не сразу закрылось
return 0 ;
}
0
Эксперт .NET
 Аватар для Usaga
14071 / 9289 / 1346
Регистрация: 21.01.2016
Сообщений: 34,850
28.02.2016, 07:22
Цитата Сообщение от vikiroy Посмотреть сообщение
Но если я еще не проходил вектора
Посмотреть примеры использования такой штуки как std::vector не так уж и долго. Быстрее, чем вести переписку на форуме.
0
nd2
3438 / 2817 / 1249
Регистрация: 29.01.2016
Сообщений: 9,427
28.02.2016, 09:37
Лучший ответ Сообщение было отмечено vikiroy как решение

Решение

Цитата Сообщение от vikiroy Посмотреть сообщение
а второе по стандарту размер массива константа, хотя я сомневаюсь что у меня всегда она остается константой, да и вообще я не понимаю если по стандарту опять же размер массива константа, а часто приходиться низлогать ее если так можно выразиться...почему так?
Константы бываю разные. По стандарту, размер массива - константное выражение: выражение, значение которого может быть вычислено во время компиляции. Изменить его потом не получится, поэтому не знаю, что ты имеешь ввиду под "часто приходиться низлогать"? А есть константы, которые могут инициализироваться значениями и неконстантных переменных, но это не константные выражения, и они не могут определять размер массива. Напрмер:
C++
1
2
3
4
    int n = 10;
    //... здесь, значение n, во время работы программы, может измениться
    const int N = n; // N - неконстантное выражение
    int arr[N]; // ошибка
C++
1
2
3
    const int N = 10; // N - константное выражение
    //... значение N, во время работы программы, не может измениться
    int arr[N]; // Ok
2
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
28.02.2016, 13:36  [ТС]
Посмотреть примеры использования такой штуки как std::vector не так уж и долго. Быстрее, чем вести переписку на форуме.
Странные вещи пишешь) чего мне забегать вперед, если я по книге изучаю массивы(векторов и поныне не было) и задачи которые я решаю стоят в конце этой же темы, и направленны конкретно на закрепление пройденного материала, зачем мне здались вектора в этом случае??? может такое описание будет понятней?...
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
28.02.2016, 13:46
Цитата Сообщение от vikiroy Посмотреть сообщение
и направленны конкретно на закрепление пройденного материала,
Может тогда стоит перечитать тему.
0
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
28.02.2016, 13:50  [ТС]
Может тогда стоит перечитать тему.
Может и стоит...а может я хочу знать больше)
0
0 / 0 / 0
Регистрация: 11.02.2016
Сообщений: 1
28.02.2016, 13:54
Смотри в сторону указателей хороший пример на хабре , должно помочь, или смотри в сторону vector::
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
28.02.2016, 13:57
Цитата Сообщение от vikiroy Посмотреть сообщение
а может я хочу знать больше
Вы же писали, что не хотите знать, что такое std::vector.

А если из темы не усвоили, как выделять память под массив в рантайме... перечитайте.
0
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
28.02.2016, 14:03  [ТС]
Смотри в сторону указателей хороший пример на хабре , должно помочь, или смотри в сторону vector::
я просто думаю что по не знанию языка придумал себе головную боль и пытаюсь ее устранить изощренными методами какими-то, поэтому я сделаю пока все что мне нужно с ограниченным размером массива, который подберу методом проб и ошибок, и буду двигаться дальше)

Добавлено через 2 минуты
А если из темы не усвоили, как выделять память под массив в рантайме... перечитайте.
я извиняюсь но вы не учитываете одно, что учебный материал у каждого автора претендует на уникальность, так же как и подход к обучению, если я сказал что не было у меня еще никаких приколов про выделение памяти, векторов и так далее, значит так и есть!
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
28.02.2016, 17:31
Лучший ответ Сообщение было отмечено vikiroy как решение

Решение

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void foo(){
   int arr[5] = {0} ;
   /*
   Это массив. 
   Расположен он будет на стеке функции
   Его размер должен быть известен во время компиляции.
   Если размер неизвестен, то можно воспользоваться следующими вариантами:
   1) Зарезервировать места сразу под большое число элементов, но это приведет либо 
       к большому перерасходу памяти, а ведь стек не резиновый, либо 
       к жесткому ограничению кол-ва элементов, которые можно в этот массив положить
   2) Можно при необходимости запрашивать динамической памяти рюмочку, ну или стаканчик,
       но порой приходится целую бочку памяти просить.
       Причем придется руками следить за выделением/освобождением (без RAII), 
       копированием элементов в новую память, размерами и т.д.
   3) Можно использовать готовые обертки, например, std::vector,
       которые, при правильном использовании берут часть головной боли на себя,
       подставляя под удар своё страшное и хрупкое шаблонное тельце.
   4) Забыть и никогда не вспоминать о c++.
   */
}

В данный момент нас интересует вариант №2.
Ну что же, можно познакомиться и с динамическим выделением памяти.
Итак, если Вашему приложению понадобилась динамическая память,
то можно запросить себе еще некоторое количество памяти во время выполнения.
При этом нужно внимательно следить за тем, чтобы не произошло утечки памяти.
Дело в том, что то, что мы выделили динамически,
мы должны сами же и освободить, когда оно нам больше не нужно.


В C для выделения памяти есть функции malloc, calloc, realloc, но это в C.
Эти функции ничего не знают о устройстве C++
и просто выделяют (точнее, просят у системы) "сырой" непрерывный кусок памяти
заданного размера (в байтах), и возвращают при этом указатель на "нечто" (void*).
Причем, если память выделить не удалось, то вернется "NULL".
Для освобождения памяти используется функция free, она также ничего не знает о C++.


В C++ для выделения такой же "сырой" памяти имеется operator newoperator new[]).
Отличие operator new от operator new[] - фактически в том,
что можно более эффективнее реализовать собственные версии этих операторов.
Так что всё, что сказано про operator new, относится и к operator new[].
Конечно, если где-то есть разница, я укажу.
operator new так же запрашивает непрерывный кусок памяти,
и возвращает указатель на "нечто" (void*).
Никакие конструкторы эта штуковина тоже не вызывает,
но уже знает о исключениях и если выделение зафейлится,
то, кинет исключение, а не вернет nullptr. На самом деле,
сначала еще попытает счастье с new_handler, но мы опустим этот момент.
Также есть версия, которая не кидает исключение,
а возвращает nullptr в случае неудачи
и версия, которая совсем не выделяет память,
а просто параметр-указатель проходит там "транзитом",
причем можно еще и перегружать operator new, но сейчас не об этом.
Для освобождения памяти, выделенной с помощью operator new используется operator delete.
Для освобождения памяти, выделенной с помощью operator new[] используется operator delete[].


В C++ чаще для выделения памяти используется new-expression (не путать с operator new ).
Имеются две версии new-expression - new и new[].
Первая версия выделяет количество памяти,
достаточное для хранения одного элемента заданного типа
и применяет соответствующий тип инициализации,
например, вызывает конструктор без параметров.

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

new-expression фактически работает в два этапа:
1) Запрашивает память, вызывая operator new (вторая версия вызывает operator new[]),
причем количество байт рассчитывает самостоятельно,
основываясь на размере типа и количестве необходимых элементов (для первой версии это один элемент).
Плюс может приписать некоторое количество байт для собственных нужд,
например, для хранения количества элементов под которые выделена память.
2) Затем производит инициализацию элемента (вторая версия производит инициализацию всех элементов).
Если инициализатор не указан, то будет использована default-initialization,
если указан - direct-initialization.
Ситуацию, когда при инициализации вылетает исключение пока не будем рассматривать.

Если из new-expression не вылетит исключение,
то вернется указатель на выделенный кусок памяти,
либо будет возвращен nullptr, если была использована версия operator new,
которая не выкидывает исключение в случае неудачи.
Для освобождения памяти, выделенной с помощью new-expression, используется delete-expression.
delete-expression также имеет две версии: delete и delete[]
Соответственно, для освобождения памяти,
выделенной с помощью new используется delete,
а для памяти, выделенной с помощью new[] - delete[]

delete-expression фактически, также работает в два этапа:
1) Вызывает деструктор объекта (delete[] вызывает деструкторы объектов).
2) Освобождает память, вызывая operator delete (delete[] вызывает operator delete[]).
Пока мы не освободим память, она так и будет считаться занятой.


Важно!
Если мы потеряем последний указатель на выделенную память,
и более никак не сможем добраться до адреса,
который вернула соответствующая функция выделения,
то, соответственно, мы не сможем освободить
эту память и она так и будет висеть занятой
до самого конца работы приложения.
То есть память эту мы не сможем использовать (т.к. у нас нет её адреса),
но при этом она будет помечена как "занятая", т.е. будет бесполезная трата памяти.
Такая ситуация называется "утечка памяти".
И за этими утечками не так просто уследить,
если использовать "голые" указатели.



Напишем несколько примеров и посмотрим на результат:
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
#include <iostream>
#include <cstdlib>
 
 
 
struct Test
{
    Test() { std::cout << "ctor. address: " << this << std::endl; }
    Test(const Test& src) { std::cout << "cctor. address: " << this << "; source address: " << &src << std::endl; }
    Test& operator=(const Test& src) { std::cout << "assign. address: " << this << "; source address: " << &src << std::endl; return *this; }
    ~Test() { std::cout << "dtor. address: " << this << std::endl; }
    double x;//Не будем его использовать, просто чтобы место занимало
};
 
 
 
int main()
{
    size_t count = 0 ;
    std::cout << "input count-> " ;
    std::cout.flush();
    std::cin >> count ;
    if(count==0){
        std::cerr << "\nerror: invalid count\n";
        return -1;
    }
    //////////////////////////////////////////////
    std::cout << "\nTest malloc for " << count << " elements:\n" ;
    //выделяем память в количестве, достаточном для хранения введенного числа элементов
    Test * test_ptr = (Test*)malloc(sizeof(Test)*count);//Требуется явный каст к Test*, т.к. в c++ запрещен неявный каст от void*.
    std::cout << "memory address: " << test_ptr << std::endl;
    //освобождаем память:
    free(test_ptr);
    //////////////////////////////////////////////
    test_ptr = nullptr;//возьмите за правило обнулять указатели, которые больше не валидны.
    std::cout << "end of main" << std::endl;
}
http://rextester.com/VAIF67989
Как видим, память выделилась, но конструкторы не вызывались.

operator new тоже ничего не будет вызывать,
а также выделит кусок памяти, поэтому пропустим его,
перейдем сразу к new-expression:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    //////////////////////////////////////////////
    std::cout << "\nTest new:\n" ;
    //выделяем память в количестве, достаточном для хранения одного элемента
    Test * test_ptr = new Test();
    std::cout << "memory address: " << test_ptr << std::endl;
    //освобождаем память:
    delete test_ptr;//Выделялось с помощью new, поэтому здесь delete
    test_ptr = nullptr;
    std::cout << "\nTest new[] for " << count << " elements:\n" ;
    //выделяем память в количестве, достаточном для хранения введенного числа элемента
    test_ptr = new Test[count];//Указываем уже не число байт, а количество элементов
    std::cout << "memory address: " << test_ptr << std::endl;
    //освобождаем память:
    delete[] test_ptr;//Выделялось с помощью new[], поэтому здесь delete[]
    //////////////////////////////////////////////
http://rextester.com/YVNMB97286

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

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
int main()
{
    std::cout << "\nTest reallocate memory:\n" ;
    //Значения могут быть вычеслены в рантайме, но чтобын е городить огород я задам их прямо в коде
    //Выделяем память в количестве, достаточном для хранения трех элементов
    Test * test_ptr = new Test[3];
    std::cout << "memory address: " << test_ptr << std::endl;
 
    //А теперь нам вдруг потребовалось "расширить" этот "массив" еще на один элемент.
    //Необходимо выделить память под 4 элемента:
    Test * test_ptr_temp = new Test[4];
    //И скопировать в новую память старые элементы:
    for(size_t i = 0 ; i < 3; ++i){
        test_ptr_temp[i] = test_ptr[i];
    }
    //Теперь, память, занимаемая массивом из трех элементов нам более не нужна.
    //Освобождаем её:
    delete[] test_ptr;//Выделялось с помощью new[], поэтому здесь delete[]
    test_ptr = test_ptr_temp; //Всё, теперь у нас по адресу, который содержится в test_ptr лежит 4 элемента
    test_ptr_temp = nullptr;
    //Поработали
    std::cout << "big work" << std::endl;
    //Теперь освобождаем память:
    delete[] test_ptr;//Выделялось с помощью new[], поэтому здесь delete[]
    test_ptr = nullptr;
    std::cout << "end of main" << std::endl;
}
http://rextester.com/DPE96044

В этом примере показано как можно "расширить" выделенный кусок памяти.
Конечно, выделять память и копировать элементы при каждом чихе не очень эффективно,
но это лишь пример.
Например, std::vector работает по такому же принципу,
только там память выделяется сразу с запасом и используется placement new
для создания элементов (конечно, всё немного сложнее и вся эта фигня завернута в аллокатор).
если нужно, могу подробнее описать, но не думаю,
что на данном этапе обучения это будет очень понятно,
собственно, поэтому и в этом посте содержатся некоторые допущения,
и нет сложных примеров, а также placement new, перегрузок операторов new/delete и т.д.
11
67 / 5 / 3
Регистрация: 30.11.2015
Сообщений: 170
28.02.2016, 18:55  [ТС]
Очень познавательно! Но если я буду разбираться сейчас с динамическим выделением памяти, мне надо будет все бросить и резко начинать учить указатели, а у меня тема указатели и строки, как раз будет после выполнения моих заданий.

Но ваш труд у меня останется несомненно! И я обязательно его изучу(пока что только просмотрел) когда придет время знакомства с динамическим выделением памяти! Спасибо вам большое!

А пока я воспользуюсь вашим советом и на этом этапе ограничусь размером массива предусмотрительно большим чем он может быть, а именно
1) Зарезервировать места сразу под большое число элементов, но это приведет либо
к большому перерасходу памяти, а ведь стек не резиновый, либо
к жесткому ограничению кол-ва. элементов, которые можно в этот массив положить
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.02.2016, 18:55
Помогаю со студенческими работами здесь

Ошибка: размер в памяти неизвестен
Приветствую. Есть функция на Си, задача которой - установить выбранный видеорежим. setvid(unsigned char m) { union REGS r1;...

Как подключить файл, если адрес неизвестен?
В макете для установки на CMS подключается баннер вот таким образом: &lt;?php include (&quot;my-files/banner-bottom.php&quot;); //...

Как скопировать файл, если его путь неизвестен
Нужно скопировать файл,который будет с неизвестный названием и местом. Как такое сделать?Файл должен скопироваься в C:\Windows\system32...

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

Массивы: функция rand() и размер массива. Совместимости
Здравствуйте уважаемые программисты! Всех с праздником!) В общем переписываю одну и ту же программу который раз, ну чуть модифицирую, и...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
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
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru