Как сделать массив глобальным

Обновлено: 07.07.2024

Изучение простых, многомерных и динамических массивов.

Массив

В практике программирования нередко возникает необходимость обработать большое количество однотипных данных. Допустим, распределить недельную прибыль кафе по дням. Что для этого нужно? Использовать переменные типа currency , как раз для таких случаев и применяемые. И сколько переменных нам нужно? Ну, ясен вопрос - по переменной на день, всего семь штук. Давайте посмотрим, как такую задачу можно было бы решить на Lazarus (пример академический, выполнять его не нужно):

Довольно длинное объявление получилось, правда? А если бы нужно было посчитать не недельную прибыль , а месячную? Или годовую? Теперь предположим, что нам нужно посчитать сумму этой прибыли. Это выглядело бы примерно так:

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

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

Массив - это формальное объединение нескольких однотипных переменных в единый набор, с одним общим именем.

Фактически, получается цепочка однотипных переменных под общим именем, где у каждой такой переменной имеется собственный номер в ячейке - индекс. Такие переменные называются элементами массива, каждый элемент имеет свой номер. Объявляется массив в разделе переменных следующим образом:

Ключевое слово array указывает, что это будет массив . Числа в квадратных скобках разделяются двумя точками и обозначают диапазон индексов. Так, [1..7] означает, что индексы массива будут от 1 до 7, то есть, 7 штук. После ключевого слова of указывается тип массива , такой же тип будет и у каждого элемента массива. В результате, компилятор создает в оперативной памяти семь ячеек по 8 байт каждая (тип currency занимает 8 байт ):

Размещение элементов массива a в памяти

Тип данных , используемый в массивах, так же может быть любым. Во многих других языках программирования диапазон индексов всегда начинается с 0. В языках, основанных на Паскале, диапазон может начинаться с любой цифры: с 0, 1, или 438, если вам так нравится. Хотя программисты обычно начинают диапазон либо с 0, либо с 1, в зависимости от обстоятельств. Пример объявления различных массивов:

Хорошо, массивы мы объявили. Что с ними делать дальше? Мы можем обратиться к любому элементу массива, указав после имени в квадратных скобках индекс этого элемента. Так, мы можем присвоить значение элементу или получить его значение . Другими словами, мы можем обращаться с элементами массива, как с отдельными переменными. Примеры:

Ну, ладно, мы научились создавать и использовать массивы. Но какие же преимущества у массивов в отличие от простых однотипных переменных? О первом таком преимуществе мы уже говорили, вот как просто можно объявить массив с элементами, рассчитанными на год:

Попробуйте-ка объявить 365 отдельных переменных! Второе преимущество гораздо важней: обрабатывать элементы массива намного проще, чем отдельные переменные. Например, нам нужно создать программу, которая бы могла сделать перевод температур из привычных нам Цельсиев в непривычные американские Фаренгейты. И пусть диапазон возможных температур будет от -100 градусов до +200. Идея такова: пользователь вводит нужную температуру, а программа выводит результат на экран. Конечно, проще было бы делать нужный расчет в момент, когда пользователь введет свои данные, и нажмет кнопку "рассчитать". Но мы поступим по -другому: мы сначала сделаем все расчеты и поместим результаты в массив , а затем будем просто выводить нужные данные. Массив сделаем глобальным, чтобы заполнять его в одном событии, а выводить данные в другом. Открываем Lazarus с новым проектом, сохраняем его сразу в папку 13-01 там, где у нас хранятся все учебные проекты. Проект сохраним под именем MyTemp, а модуль главной формы, как обычно - Main. Займемся главной формой, измените у нее следующие параметры:

  • Name = fMain
  • Caption = Перевод температурных шкал
  • BorderStyle = bsDialog
  • Position = poMainFormCenter

Далее, перейдите на вкладку Additional Палитры компонентов, найдите и установите на форму компонент TStaticText , который предназначен для вывода на экран пояснительного текста, в том числе и многострочного. Если вы забыли, то найти нужный компонент просто: нужно просто подвести указатель мыши к компоненту, и через короткое время появится всплывающая подсказка с именем компонента.

В принципе, для этих целей можно использовать и простую метку TLabel , но было бы интересней познакомиться и с другими компонентами. В Инспекторе объектов в свойстве Caption нажмите на кнопку "…" справа от свойства:

Свойство Caption компонента TStaticText

В открывшемся редакторе напишите следующий текст:

Именно так, в две строки. Затем измените размеры компонента на форме, чтобы текст отображался точно в таком виде, как мы ввели. И еще: в свойстве Alignment выберите taRightJustify , чтобы текст выравнивался по правому краю.

Теперь перейдите на вкладку Misc палитры компонентов, найдите там и установите на форму, правее TStaticText , компонент TSpinEdit , который предназначен для ввода пользователем целых чисел. Этот компонент похож на простой TEdit , но справа от него есть стрелки вверх и вниз, которыми пользователь может прибавлять или убавлять указанное в строке число. Использование этого компонента гарантирует нам, что пользователь не сможет ввести в него ничего, кроме целого числа. А чтобы еще гарантировать правильный диапазон этих чисел, в свойстве MaxValue (максимальное возможное значение ) установите 200, а в MinValue (минимальное возможное значение ) установите -100 (минус сто). Теперь пользователь не сможет ввести в это поле ничего, кроме целых чисел. Если же он попытается превысить максимальное значение , то компонент автоматически установит число 200 - максимально возможное. И наоборот, если указать число меньше, чем -100, компонент установит -100, так что нам не нужно беспокоиться об ошибках. Кроме того, в этом компоненте позже нам понадобятся ещё два свойства: Text (установленное значение в виде строки), и Value (установленное значение в виде целого числа).

По умолчанию, компонент недостаточно широк, поэтому установите в его свойстве Width значение 75. И еще: нам придется обращаться к компоненту по имени, а SpinEdit1 - это слишком длинное имя. Измените его свойство Name на SE1 .

Ну и наконец, установите на форму простую кнопку, в свойстве Caption которой напишите Рассчитать температуру. Надпись на кнопке не уместится, поэтому кнопку придется удлинить. Расположите компоненты на форме примерно так:

Внешний вид формы

Теперь займемся предварительными расчетами. Для начала нам нужно сделать глобальный массив вещественных чисел - температура по Фаренгейту уже не будет целым числом. Значение по Фаренгейту вычисляются так: берется температура по Цельсию, умножается на 9/5, затем к результату прибавляется 32. Поэтому в глобальном разделе var , сразу над ключевым словом implementation объявляем массив atemp :

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

Выделите форму, щелкнув по её свободному месту, затем в Инспекторе объектов перейдите на вкладку События. Нам нужно событие OnCreate - оно возникает только однажды, при создании формы. Щелкните дважды по этому событию, чтобы сгенерировать его. Код события следующий:

Вот теперь, наконец, мы сможем оценить всю прелесть использования массивов! Давайте разберем этот код. В разделе var мы объявили переменную i типа smallint . Это - счетчик для цикла for , который мы использовали в коде. Так как диапазон нужных нам значений располагается от -100 до +200, тип целых чисел smallint - самый подходящий. А теперь обратите внимание на код:

Это - самая главная "фишка" массивов - обработка всего массива, каким бы большим он не был, в простом цикле. Вначале счетчик i принимает значение -100. Внутри цикла мы присваиваем значение одному элементу массива. Если мы заменим переменную i на её значение , как это делает компилятор в процессе работы, то получим следующее:

Таким образом, мы высчитываем перевод температуры из Цельсия в Фаренгейты для конкретной температуры: -100 градусов по Цельсию, и полученный результат присваиваем элементу массива atemp[-100] . Затем цикл повторяется, i увеличивается на единицу, и уже равна -99. Новое значение присваивается новому элементу массива, и так до конца цикла . Как вы думаете, сколько элементов массива будет заполнено в этом цикле? Кто сказал 300?! А про ноль вы забыли? 301 раз будет работать цикл, и 301 различное значение будет присвоено 301 элементу массива. А теперь представьте, как это выглядело бы для отдельных переменных:

Вместо двух строчек цикла мы получили бы 301 строку кода с одинаковыми вычислениями!

Но вернемся к нашему проекту, ведь нам еще нужно вывести на экран результат перевода температур. Сгенерируем для кнопки Button1 событие OnClick . Её код будет совсем простой:

Здесь SE1.Value - это то значение , которое установил пользователь , но уже в виде целого числа! Допустим, пользователь установил значение 35, тогда этот код будет таким:

Многомерный массив

Массивы, которые мы до сих пор разбирали, были одномерными - визуально их можно представить, как цепочку ячеек или одну строку таблицы. Однако бывают ситуации, когда этого недостаточно. Допустим, нужно сохранить какую-то таблицу. Одномерный массив с такой задачей не справится. Для этого существуют многомерные массивы, которые имеют размерность от двух и больше. Например, объявить двухмерные массивы из 5 строк и 10 колонок можно следующим образом:

То есть, в квадратных скобках через запятую указывается диапазон вначале строк, а затем колонок. Визуально, такой массив можно было бы представить так:

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

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

Доработаем наш проект. Что, если мы будем конвертировать нашу температуру не только в Фаренгейты, но и в Кельвины ( единица термодинамической температуры в СИ - Международной Системе Единиц)? Пересчет Цельсия в Кельвины еще проще, чем в Фаренгейты: нужно к температуре по Цельсию прибавить 273,15. Для этого нам потребуется вместо одномерного массива объявить двухмерный. Измените код над служебным словом implementation :

В первой строке у нас будут Фаренгейты, во второй - Кельвины. А колонки мы отведем под требуемый диапазон . Далее, нам потребуется изменить цикл в событии OnCreate формы:

Обратите внимание: поскольку нам в цикле требуется выполнить не один оператор, а два, нам пришлось заключить их в программные скобки begin…end , сделав составной оператор . Далее, все просто: для строки 1 нашего массива мы рассчитываем Фаренгейты, как в прошлый раз. А для строки 2 уже Кельвины.

Но нам потребуется переделать и событие кнопки OnClick :

Но размерность массива может быть и больше. Трехмерный массив визуально можно представить следующим образом:

Визуальное представление трехмерного массива

Объявить подобный массив можно было бы так:

А обращаться к отдельным элементам так:

Как бы выглядел четырехмерный массив визуально вообще невозможно представить. У вас есть возможность работать хоть с десятимерным массивом, однако в практике программирования обычно используют одно- и двухмерные массивы, и очень редко возникает надобность в трехмерном. Не забывайте про один из основных принципов программирования, который сами программисты называют KISS (Keep It Simple, Stupid - будь проще, дурачок). Этот принцип подразумевает, что код программы не стоит усложнять без нужды - сложный код тяжелее воспринимается самим программистом, больше нагружает процессор , а ошибки времени выполнения (run time errors - ошибки, возникающие во время выполнения программы, обычно это логические ошибки ) в таком коде сложнее отслеживать.

Динамический массив

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

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

Объявляются динамические массивы также в разделе var , следующим образом:

Как видите, мы указываем только тип массива , но не его размерность . Память под объявленный массив при этом не отводится. В дальнейшем с динамическим массивом мы можем производить различные операции : устанавливать размерность (длину) массива, увеличивать или уменьшать эту размерность (потому массив и динамический), узнавать высшие и низшие границы диапазона индексов массива, присваивать значения отдельным элементам или наоборот, считывать эти значения. Познакомьтесь с функциями, которые все это проделывают.

SetLength() - устанавливает размер массива. Синтаксис :

Тут следует оговориться, что в отличие от обычного массива, начальный индекс которого может быть любым, индексация динамического массива всегда начинается с нуля. То есть, индексация элементов массива в нашем примере будет от 0 до 4 - всего пять элементов. Как только мы установили размер массива, в памяти выделяется место под него. В нашем примере будет отведено по 4 байта (тип integer ) для 5 элементов массива. Обращаться к этим элементам можно обычным образом:

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

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

то массив усекается. Если последний элемент содержал какие-то данные, они будут потеряны. Освободить память массива можно, присвоив ему нулевую размерность :

Также освободить память можно, присвоив массиву значение nil (ничего, пусто):

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

Динамические массивы могут быть и многомерными. Например, двухмерный массив целых чисел можно объявить так:

Затем такому массиву можно присвоить размерность , например, 4 на 5:

Это будет, как если бы мы объявили простой массив :

Length() - возвращает размер динамического массива, то есть, количество его элементов. Например, нам нужно посмотреть размер массива, и если он пустой, то добавить в него один элемент:

Low() - возвращает нижний индекс массива , у динамических массивов это всегда ноль.

High() - возвращает верхний индекс массива , но это не то же самое, что количество элементов. Если у массива 5 элементов, то Length() вернет 5, а High() вернет 4, так как индексация начинается с нуля.

Пример обхода массива от первого до последнего элемента:

В примере мы каждому элементу присваиваем квадрат его индекса. Давайте поработаем с динамическими массивами на практике. Чтобы не портить наш конвертер температур, закройте его и откройте новый проект. Мудрить мы не будем - нам нужна только форма и простая кнопка на ней. Переименовывать тоже ничего не будем, это же просто пример. Сохраните новый проект в папку 13-02.

Сгенерируйте процедуру OnClick для кнопки, её код будет таким:

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

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

Далее, с помощью цикла for мы обходим весь массив от первого до последнего элемента. В каждый элемент мы записываем строку: " Строка № ", добавляем номер элемента и переход на новую строку. Обратите внимание, для первой строки i будет равно 0, поэтому мы указываем i + 1 :

Организация массива

Память под массив может выделяться автоматически или динамически.

Автоматическое выделение памяти используют, когда размер массива известен на этапе компиляции (т. е. при написании кода).

Динамическое выделение памяти используют, когда размер массива неизвестен на этапе компиляции (допустим, запрашивается у пользователя).

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

Глобальные автоматические массивы в плане переполнения стека безопасны. Но они будут видны во всём коде, лексикографически расположенному после объявления массивов, что может спровоцировать их использование напрямую, минуя их передачу в функции через параметры. Это приведёт к возникновению побочных эффектов работы функций, что затрудняет отладку и делает программы менее надёжными. Такого использования глобальных массивов следует избегать.

Использование автоматических массивов

Автоматические массивы используют, когда размер массива известен на этапе компиляции.

Размер массива в коде настоятельно рекомендуется указывать с помощью именованной константы. Это полезно по нескольким соображениям:

  1. имя константы должно указывать на область её применения — самодокументирование кода;
  2. при необходимости изменить в коде размер массива потребуется внести правку только в одном месте;
  3. размер массива, как правило, используется в циклах прохода по массиву, проверки границы и пр., поэтому использование символического имени избавит от необходимости тщательной проверки и правки всего кода при изменении размера массива.

Тип константного выражения для определения размера (количество элементов) автоматического массива должен быть целочисленный: char , int , unsigned int , long , etc.

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

Пример определения глобального автоматического массива длиной 10 элементов типа int :

Пример определения локального автоматического массива длиной 10 элементов типа int :

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

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

Память для массива выделяется оператором new в форме new тип[количество_элементов] .

Тип выражения, определяющего размер (количество элементов) массива должен быть целочисленным. Также это выражение может быть и константным.

Когда работа с массивом закончена, память, выделенную под массив необходимо освободить. Это делается с помощью оператора delete в форме delete [] имя_переменной . После того, как память освобождена, работать с массивом нельзя.

Пример использования массива с динамическим выделением памяти:

Заполнение массива значениями

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

Заполнение массива случайными числами

Для начала необходим генератор случайных чисел. Ниже приведён код одной из простейших реализаций:

Заполнение массива значениями, естественно, делаем в цикле. Помним, что элементы массива в C/C++ нумеруются с 0. Следовательно последний элемент массива имеет индекс на единицу меньший, чем размер массива.

В примере показано заполнение глобального автоматического массива из 10 элементов типа int случайными значения из диапазона от −100 до 100 включительно:

Обратите внимание на включение заголовочных файлов!

Заполнение массива числами, введёнными пользователем

Как ни странно, это более сложный случай. Дело в том, что во-первых, наличие человека всегда может приводить к некорректному вводу данных (ошибкам), во-вторых, для человека необходимо обеспечить какой-никакой интерфейс, а в-третьих, система потокового ввода-вывода STL имеет свои неприятные особенности.

Оно как бы работает, но если вы попытаетесь в качестве числа (конечно случайно!) ввести 1111111111111111111111111111111111 или 11q, то, в зависимости от компилятора, сможете наблюдать некоторые интересные эффекты работы вашей программы.

Поэтому приходится писать более сложный код:

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

Вывод на консоль значений из массива

Вывод значений массива на консоль реализуется элементарно. В свете уже вышесказанного даже нечего добавить:

Как видно из комментариев, за поиск минимального значения и его индекса отвечает последний фрагмент программы.

Определяются две переменные, одна из которых будет содержать минимальное значение, а вторая — индекс элемента с минимальным значением. Эти переменные инициализируются первым (нулевым) элементом массива и нулём соответственно. Далее, в цикле каждое следующее значение элемента массива сравнивается с уже найденным наименьшим значением и, если текущее значение меньше запомненного, то запоминается текущее значение и его индекс.

Поиск определённого значения в массиве

Поиск определённого значения в неупорядоченном массиве осуществляется с помощью алгоритма линейного поиска. Этот простейший алгоритм заключается в последовательном переборе элементов массива и сравнением их с искомым значением.

Задачи на поиск в массиве могут быть в двух формах:

  1. найти первое (последнее) вхождение искомого значения
  2. найти все вхождения

Поиск первого вхождения:

Поиск последнего вхождения:

Обратите внимание на следующие моменты.

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

Если искомый элемент найден, то цикл завершается досрочно оператором break : просматривать остальную часть массива не имеет смысла — задача уже выполнена.

Во втором случае переменная i имеет знаковый тип int . Отрицательное значение используется в качестве флага, что весь массив просмотрен, и значение не найдено.

Поиск всех вхождений:

Здесь цикл не прерывается. Массив просматривается полностью.

Сумма/произведение отрицательных элементов массива

Сумма элементов массива с чётными/нечётными индексами

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

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

Обратите внимание, что выделение памяти под массив и её освобождение происходит в одной функции (в данном случае, в main() ). Выделять память в одной функции, а освобождать в другой — плохая идея, чреватая ошибками.

Заключение

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

Создаю динамический массив:

int **map_value = new int*[Image1->Height];
for(int i = 0; i Height; i++)
map_value[i] = new int[Image1->Width];
>

Вопрос, а как его сделать глобальным?

Здравствуйте, Bocman, Вы писали:

B>Создаю динамический массив:

B> int **map_value = new int*[Image1->Height];
B> for(int i = 0; i Height; i++)
B> <
B> map_value[i] = new int[Image1->Width];
B> >

B>Вопрос, а как его сделать глобальным?

Контрвопрос: а на кой? Пхайте все в вектор (будет, правда, линейное размещение), а вектор — в синглтон. Глобальные переменные — зло.

Здравствуйте, Нахлобуч, Вы писали:

Н>Контрвопрос: а на кой? Пхайте все в вектор (будет, правда, линейное размещение), а вектор — в синглтон. Глобальные переменные — зло.


а синглтон — это что?

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

Н>Глобальные переменные — зло.

Тоже соглашусь что глобальность это плохо

Здравствуйте, Bocman, Вы писали:

B>а синглтон — это что?

Автор(ы): Иван Андреев
Дата: 03.08.2003
Описание шаблона проектирования синглетон очень простое — синглетон представляет собой единственный экземпляр класса, с которым работают все клиенты. Применительно к COM шаблон проектирования синглетон гарантирует, что все вызовы CoCreateInstance будут возвращать указатель на интерфейс единственного экземпляра компонента. Удобство использования таких компонентов/классов заключается в том, что клиенты работают с одним и тем же экземпляром, а значит, получают доступ к разделяемому состоянию этого экземпляра. Несмотря на простое описание, не существует "идеальной" реализации этого шаблона ни в языке С++, ни для COM-объектов. Связано это с тем, что любая существующая реализация имеет некоторые ограничения и не может выступать в роли "универсальной" реализации на все случаи жизни.



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

Ну дык вы ведь на С++ пишете. Можно попробовать сгруппировать родственные сущность, их засунуть в объект, а объект — в синглтон (игла в яйце, яйцо в зайце, заяц в утке ).

Здравствуйте, DigitPower, Вы писали:

Н>>Глобальные переменные — зло.

DP>Тоже соглашусь что глобальность это плохо

И все же вопрос остается в силе.

int **map_value = new int*[Image1->Height];
for(int i = 0; i Height; i++)
map_value[i] = new int[Image1->Width];
>

как его сделать глобальным?

Здравствуйте, Bocman, Вы писали:

B>И все же вопрос остается в силе.

B> как его сделать глобальным?

Это выдрано из буста (синглтон Мейерса, кажется)


Соответственно, надо завернуть map_value в класс и.

Здравствуйте, Bocman, Вы писали:

B>И все же вопрос остается в силе.

B> как его сделать глобальным?

Это выдрано из буста (синглтон Мейерса, кажется)


Соответственно, надо завернуть map_value в класс и.

Ну, а где описывать размерность тогда?


Здравствуйте, Нахлобуч, Вы писали:

Н>Здравствуйте, Bocman, Вы писали:

B>>И все же вопрос остается в силе.
Н>
B>> как его сделать глобальным?

Н>Это выдрано из буста (синглтон Мейерса, кажется)

Н>

Н>Соответственно, надо завернуть map_value в класс и.
Н>

Здравствуйте, Bocman, Вы писали:

B>Ну, а где описывать размерность тогда?

Здравствуйте, Bocman, Вы писали:

B>Создаю динамический массив:

B> int **map_value = new int*[Image1->Height];
B> for(int i = 0; i Height; i++)
B> <
B> map_value[i] = new int[Image1->Width];
B> >

B>Вопрос, а как его сделать глобальным?

Просто завести глобальную переменную и все
А лучше обернуть в класс, добавить размерности.

Хотя присоединяюсь к мнению, что это не очень хорошо.

Здравствуйте, Bocman, Вы писали:

B>Создаю динамический массив:

B> int **map_value = new int*[Image1->Height];
B> for(int i = 0; i Height; i++)
B> <
B> map_value[i] = new int[Image1->Width];
B> >

B>Вопрос, а как его сделать глобальным?

Не делать его static и поместить строку
int** map_value;
в одном из c / cpp файлов.
Чтобы сделать его ОБЪЯВЛЕНИЕ видимым другим c / cpp файлам, вставь в хедер
extern int **map_value;
У себя в коде инициализации примерно так:
map_value = new int*[Image1->Height];
for(int i = 0; i Height; i++)
map_value[i] = new int[Image1->Width];
>

Спасибо!
Именно это мне и нужно было.

Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Bocman, Вы писали:

B>>Создаю динамический массив:

B>> int **map_value = new int*[Image1->Height];
B>> for(int i = 0; i Height; i++)
B>> <
B>> map_value[i] = new int[Image1->Width];
B>> >

B>>Вопрос, а как его сделать глобальным?

А>Не делать его static и поместить строку
А>int** map_value;
А>в одном из c / cpp файлов.
А>Чтобы сделать его ОБЪЯВЛЕНИЕ видимым другим c / cpp файлам, вставь в хедер
А>extern int **map_value;
А>У себя в коде инициализации примерно так:
А> map_value = new int*[Image1->Height];
А> for(int i = 0; i Height; i++)
А> <
А> map_value[i] = new int[Image1->Width];
А> >

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



Локальные массивы выделяются на стеке при входе в функцию. Массив такого размера просто переполняет стек.

Локальные массивы выделяются на стеке при входе в функцию. Массив такого размера просто переполняет стек.


Спасибо
Первый совет, дал результат.
Второй опробую и сообщу
О Вашем любезном предложении помочь в предыдущей моей теме напишу в приват.

В каждой функции по копии массива! Лучше передавать массив по указателю, а создать один экземпляр в функции main()!

В каждой функции по копии массива! Лучше передавать массив по указателю, а создать один экземпляр в функции main()!


Ну почему же по копии?
Первая функция отработала, и освободила память.Имена массивов то разные, т.е массивы разные и в каждый момент используется только ОДИН массив, остальные или уже освобождены или еще не объявлены.
Возможно текст излишен, но функциональность ИМХО такая же.



Как вариант, можно еще увеличить размер стека в настройках проекта Linker->System
Stack Commit Size
Stack Reserve Size
//но имхо все же лучше динамичски выделять

Локальные массивы выделяются на стеке при входе в функцию. Массив такого размера просто переполняет стек.


Я уже задавал вопрос на форуме о выделении памяти, но ,к сожалению, мало что понял.
Чем динамическое выделение памяти лучше



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


Выделяешь память только тогда, когда это надо и столько, сколько надо (позже можно перевыделить). Иначе у тебя получиться что ты выделил 8000*2048*3*2 байт, хотя скорее всего они тебе все сразу и не нужны.



А вообще работать с сырой памятью это доставляет много проблем, а использовать STL контейнеры, так, например, std::vector очень оптимизированная штука и ее стоит предпочесть работе с сишными массивами

ЗЫ: ну это ессно все если вы работаете на С++ а не на чистом С

А вообще работать с сырой памятью это доставляет много проблем, а использовать STL контейнеры, так, например, std::vector очень оптимизированная штука и ее стоит предпочесть работе с сишными массивами

ЗЫ: ну это ессно все если вы работаете на С++ а не на чистом С

Я уже задавал вопрос на форуме о выделении памяти, но ,к сожалению, мало что понял.
Чем динамическое выделение памяти лучше

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

Проверить так это или нет для конкретного компилятора - легко.
Сравни размеры программы с глобальным массивом и без него.

Читайте также: