Локальные и глобальные переменные в С++
Каждая переменная имеет свою область видимости, то есть такую область, в которой можно работать с переменной. За пределами этой области, о данной переменной ничего известно не будет, а значит и использовать её нельзя. Итак, переменная находится в области видимости, если к ней можно получить доступ.
Существуют локальные и глобальные переменные. Так вот, переменные, объявленные внутри функции, называются локальными. Локальные переменные имеют свои области видимости, этими областями являются функции, в которых объявлены переменные. Таким образом, в разных функциях можно использовать переменные с одинаковыми именами, что в свою очередь очень удобно. Разделение переменных на глобальные и локальные соответствует одному из главных правил программирования, а именно – принципу наименьших привилегий. То есть, переменные, объявленные внутри одной функции, должны быть доступны только для этой функции и ни чему другому, в конце концов, они создавались именно для этой функции. Глобальные переменные объявляются вне тела какой-либо функции, и поэтому область видимости таких переменных распространяется на всю программу. Обычно глобальные переменные объявляются перед главной функцией, но можно объявлять и после функции main() , но тогда данная переменная не будет доступна в функции main() .
Разработаем программу, в которой будут объявлены две переменные, локальная и глобальная, с одинаковым именем.
// variables.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout
// variables.cpp: определяет точку входа для консольного приложения. #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout
В строках 8 и 12 объявлены переменные одинакового типа с одним и тем же именем variable , но переменная в строке 8 является глобальной переменной, а переменная в строке 12 — это локальная переменная. Функция example() имеет доступ только к глобальной переменной. В то время как функция main() имеет доступ как к локальной так и к глобальной переменным. Если в области видимости есть и локальная и глобальная переменные с одинаковыми именами, то при обращении к ним, будет использоваться ближайшая переменная, а это локальная переменная, это видно по результату работы программы (см. Рисунок 1).
CppStudio.com
local variable = 12 global variable = 48
Рисунок 1 — Локальные и глобальные переменные в С++
Как мы уже сказали, функция main() имеет доступ и к глобальной переменной, но не показали, как получить этот доступ. В С++ существует такая операция, как разрешение области действия :: . Эта операция позволяет обращаться к глобальной переменной из любого места программы.» Все, что нужно сделать, так это поставить двойное двоеточие перед именем переменной. Ниже показан код, верхней программы с одним лишь изменением, и это изменение – операция разрешения доступа в строке 13.
// variables.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout
// variables.cpp: определяет точку входа для консольного приложения. #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout
Операция разрешения области действия ставится перед именем глобальной переменной, и даже, если есть локальная переменная с таким же именем, программа будет работать со значением, содержащимся в глобальной переменной. Результат работы программы (см. Рисунок 2).
CppStudio.com
local variable = 48 global variable = 48
Рисунок 2 — Локальные и глобальные переменные в С++
К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!
Глобальные переменные
В противоположность локальным переменным глобальные переменные видны всей программе и могут использоваться любым участком кода. Они хранят свои значения на протяжении всей работы программы. Глобальные переменные создаются путем объявления вне функции. К ним можно получить доступ в любом выражении, независимо от того, в какой функции находится данное выражение.
В следующей программе можно увидеть, что переменная count объявлена вне функций. Она объявляется перед функцией main(). Тем не менее, она может быть помещена в любое место до первого использования, но не внутри функции. Общепринятым является объявление глобальных переменных в начале программы.
void func1(void) , func2(void);
int count; /* count является глобальной переменной */
int main(void)
count = 100;
func1 ();
return 0; /* сообщение об удачном завершении работы */
>
void func1 (void)
func2 ();
printf("счетчик %d", count); /* выведет 100 */
>
Рассмотрим поближе данный фрагмент программы. Следует понимать, что хотя ни main(), ни func1() не объявляют переменную count, но они оба могут ее использовать. func2() объявляет локальную переменную count. Когда func2() обращается к count, она обращается только к локальной переменной, а не к глобальной. Надо помнить, что если глобальная и локальная переменные имеют одно и то же имя, все ссылки на имя внутри функции, где объявлена локальная переменная, будут относиться к локальной переменной и не будут иметь никакого влияния на глобальную,. это очень удобно. Если забыть об этом, то может показаться, что программа работает странно, даже если все выглядит корректно.
Глобальные переменные хранятся в фиксированной области памяти, устанавливаемой компилятором. Глобальные переменные чрезвычайно полезны, когда одни и те же данные используются в нескольких функциях программы. Следует избегать ненужного использования глобальных переменных по трем причинам:
- Они используют память в течение всего времени работы программы, а не тогда, когда они необходимы.
- Использование глобальных переменных вместо локальных приводит к тому, что функции становятся более частными, поскольку они зависят от переменных, определяемых снаружи.
- Использование большого числа глобальных переменных может вызвать ошибки в программе из-за неизвестных и нежелательных эффектов.
Одним из краеугольных камней структурных языков является разделение кода и данных. В С разделение достигается благодаря использованию локальных переменных и функций. Например, ниже показаны два способа написания mul() — простой функции, вычисляющей произведение двух целых чисел.
| Общий | Частный |
|---|---|
| int mul(int х, int у) return(x*y); > |
int х, у; int mui(void) return(x*y); > |
Обе функции возвращают произведение переменных х и у. Тем не менее общая или параметризированная версия может использоваться для вычисления произведения любых двух чисел, в то время как частная версия может использоваться для вычисления произведения только глобальных переменных х и у.
Объявление глобальной переменной внутри функции
"Глобальная переменная" - неформальный термин с массой вариаций значения. В большинстве контекстов всем "и так понятно" о чем именно идет речь. А вот в рамках такого вопроса-однострочника, не сопровождаемого никаким контекстом, не мешало бы и уточнить более детально, что вы имеете в виду под "объявить глобальную переменную".
5 апр 2017 в 9:21
Вероятно, нельзя. Но это если я правильно понял суть вопроса.
5 апр 2017 в 9:27
@AnT к примеру я обьявил в функцие переменную number в другой функцие модифицировал/использовал и тд. Тоесть переменная будет сформирована в одной функцие но использовать можно везде К примеру я создал массив н-елементов и вместо того чтоб в функцие arr_sort в аргументах вновь указивать н, можна било уже в цикле использовать ету н, которая била сформирована в main.(сори за русский, я украинец)
5 апр 2017 в 18:20
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
Объявить глобальную переменную в функции, то есть переменную с внешним или внутренним связыванием, можно. А, вот, определить такую переменную нельзя, так как глобальная переменная - это переменная определенная вне функции.
#include int x; void f( int i ) < extern int x; x = i; >int main(void)
Вывод программы на консоль
x = 0 x = 10
В этой программе в функции f объявляется глобальная переменная x
extern int x;
Отслеживать
ответ дан 5 апр 2017 в 8:12
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 38 38 серебряных знаков 89 89 бронзовых знаков
Объявить или определить?
Возможно, я несколько путаюсь в терминологии, тогда пусть меня поправят, но если я правильно понимаю, то
int x = 5; // Определение глобальной переменной int main(int argc, const char * argv[]) < extern int x; // Ее объявление, локальное для функции main() printf("%d\n",x); >
Более того, они могут находиться в разных файлах.
Отслеживать
ответ дан 5 апр 2017 в 8:09
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков
Обращаю внимание, что это объявление в плане видимости, но не создание глобальной переменной - она всё равно должна быть объявлена где-то ещё.
5 апр 2017 в 9:25
@Qwertiy Скорее, определена?
5 апр 2017 в 9:26
Да, точно. Опять в терминологии запутался)
5 апр 2017 в 9:27
Всё, что объявлено в функции, видно только в ней. Это основной принцип структурного программирования, называющийся «область видимости».
Возможностью межпроцедурного доступа обладают только глобальные переменные. Крайне желательно использовать static -переменные, уровня .c -файла, но в крайнем случае допустимо использовать и действительно глобальные переменные, уровня всей программы.
- Приписать к локальной переменной модификатор static , тогда она переживёт выход из функции в силу особого смысла этого ключевого слова при локальных переменных;
- Вернуть из функции указатель на эту переменную.
- Передать этот указатель внутрь другой функции, которая сохранит его внутри своей статической локальной переменной.
И это будет работать, так как статические локальные переменные хранятся не на стеке. Однако лучше переместить эту переменную в структуру, как бы хранящую состояние между вызовами, и передавать эту структуру обеим функциям по указателю. Тогда:
- Первая функция будет записывать данные в экземпляр структуры (инициализировать её);
- Вторая функция будет просто читать и писать в эту структуру.
Чтобы посторонние не могли вмешаться в массив, воспользуйтесь шаблоном проектирования «прозрачный указатель»: вынесите обе функции и определение структуры в отдельный .c -файл, а остальной программе предоставьте прототипы функций и краткого определения структуры, достаточного для объявления указателей на неё ( typedef struct MyStruct; ).
Заметьте, в любом случае придётся что-то передавать в качестве параметра второй функции.
Глобальные переменные в C#

13 Aпреля 2010 Программирование
18
0
Сегодня задали интересный вопрос - как и где хранить глобальные переменные. Человек привык создавать в Delphi отдельный модуль, в котором хранил глобальные переменные и методы. Это большая проблема Delphi, что он умеет создавать глобальные переменные. По правилам OOP не должно быть такой возможности, и в C# такой возможности нет!
Но как же тогда поступить, если хочется создать что-то глобальное? Сначала нужно подумать 10 раз, а действительно ли нужна эта глобальность. Забудьте Delphi как страшный сон и вообще забудьте, что может быть такая возможность, как глобальная переменная или метод. Просто подумайте и ответьте себе на следующие вопросы:
1. Действительно ли нужно, чтобы к переменной мог быть доступ откуда угодно? Если нет, то создайте свойство у какого-нибудь самого подходящего класса.
2. Может переменная по смыслу относится к какому-то классу? Если да, то опять же создайте свойство у какого-нибудь самого подходящего класса.
3. Может у вас код логики в классах с визуальным интерфейсом? Если да, то лучше удалить код, и начать писать заново, только проектировать код, а не лепить.
Если ты сейчас думаешь "да задолбал ты, просто скажи, как сделать глобальную переменную или метод", то в таком случае просто говорю:
В таких случаях в C# и других реально объектных языках используют статичные переменные и методы. Просто создайте файл, в который будете кидать весь свой глобальный мусор:
namespace GlobalTrash < class MyGlobalTrash < public static int MiGlobalVariable; public static void MiGlobalFunction() < >> >
Теперь в любом месте программы вы можете обратиться к переменным и методам так: GlobalTrash.MyGlobalTrash.MiGlobalVariable = 10;. Но еще раз хочу посоветовать создавать глобальные переменные только в крайнем случае.
В принципе, можно не создавать отдельный класс и namespace, а использовать класс Program, который итак уже есть в программе в файле Program.cs.
Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым
А еще поделитесь с друзьями
Комментарии
Spider_NET
13 Aпреля 2010
Этим мне и нравиться C#. После перехода с Delphi мне было чертовски непривычно, но потом я прочувствовал эту фичу. И код легче поддерживать (я про static) и все как-то на виду, в отличии от Delphi.
Хотя это относится к старым версия дельфина. В последних версиях, в Delphi появились так называемые классовые методы/переменные - аля статичные.
Все таки хорошо, что Delphi продолжает развиваться.
psycho-coder
14 Aпреля 2010
Я как-то писал клиент для MySQL на C++.NET (изврат конечно), но там нужно было где-то хранить настройки (пароль, имя пользователя, порт, имя базы и т.д.). Пришлось делать через глобальные переменные, т.к. окон было много, приписать к какому то классу было нельзя, а может и можно (на ум ничего не пришло).
Как быть в таких случаях?
Еще намучался с передачей данных между формами, где то можно было напрямую с одной формы на другую, а где то, только через глобы(
Михаил Фленов
14 Aпреля 2010
Зачем настройки соединения нужны окнам? Они нужны там только в одном случае - у тебя код доступа к базе находиться в классах с окнами. Это очень плохо. Нужно отделить это дело.
Сергей
14 Aпреля 2010
Забудьте Delphi как страшный сон
Михаил, зачем же так пренебрежительно?
Не правильно ли было бы сказать "забудьте ваши неправильные навыки кодирования на Delphi, как страшный сон". Сама среда Delphi тут ни в чем не виновата.
Чем объектно-ориентированные способности Delphi слабее чем в C#?
В нормальных книгах по Delphi черным по белому не рекомендуется использование глобальных переменных.
И ничего не мешает в Delphi так же как в твоём примере для C# обернуть все глобальные переменные в класс и обращаться к ним через свойства.
Delphi полностью объектно-ориентированный язык программирования. И ничего не мешает кодировать с его помощью "продвинуто" (100%-тно объектно ориентированно).
psycho-coder
14 Aпреля 2010
Ммм. Нужно выкинуть код доступа к базе в отдельный класс? Тогда значит, нужно передавать из класса данные, которые будут получены из базы, в класс окна и заполнять все поля этими данными?
Михаил Фленов
14 Aпреля 2010
Delphi - очень хороший язык. Но любому программисту, перешедшему с Delphi на C# нужно забыть практически все, что он делал на Delphi.
Точно так же я скажу любому программисту, который переходит с C# или Java на Delphi - "забудьте C# и Java". Иначе не получиться написать успешный проект.
Писать действительно можно одинаково, но не всегда это нужно. Просто у этих языков и библиотек подход разный. Я считаю, что писать нужно с использованием языка и его преимуществ. А не пытаться реализовать в языке преимущества других.
Михаил Фленов
14 Aпреля 2010
Жди отдельную заметку
Михаил Фленов
14 Aпреля 2010
Решил все же не писать заметку.
Подход Delphi: компоненты доступа к данным располагаются в отдельном модуле DataModule. Этот модуль создается при запуске приложения и любая форма обращается к модулю и может выполнять запросы у себя в классе и обрабатывать данные.
В принципе, ты можешь то же самое реализовать на C#. Создай отдельный класс, который будет создаваться при запуске приложения. Это будет у тебя как бы DataModule. Можешь даже называть его так же. Ссылка на класс будет статична (глобальна). В этом классе будет компонент для создания соединения с базой данных и объекта таблиц и запросов. Ты можешь в любом окне обратиться через статичную переменную к этому классу и получить объект любой таблицы для работы с ним. Не нужно хранить глобально все параметры, достаточно одной переменной, указывающий на объект модуля данных.
Но я уже давно говорю, что надо идти дальше и полностью отделять код от логики. Форма должна получать от DataModule не объект, через который можно получить данные, а НЕПОСРЕДСТВЕННО ДАННЫЕ. В формах должны быть вызовы в стиле:
Результатом может быть набор данных, и можно даже в виде массивов, а не в виде Table.
Опять же, в Delphi можно так же сделать, но никто не делает, потому что сама VCL написана в стиле 70-хх годов и примеры с Delphi поставляются в стиле 70-х годов.
psycho-coder
14 Aпреля 2010
2Михаил
Спасибо. Нужно будет подумать над этим хорошенько). А прогу придется переписывать с нуля, т.к. исправлять то что там есть нет смысла.
[offtop]я только что понял, что не могу нормально высказать мысль((([/offtop]
Дмитрий
09 Октября 2010
[QUOTE]
Delphi - очень хороший язык. Но любому программисту, перешедшему с Delphi на C# нужно забыть практически все, что он делал на Delphi.
Точно так же я скажу любому программисту, который переходит с C# или Java на Delphi - "забудьте C# и Java". Иначе не получиться написать успешный проект.
Писать действительно можно одинаково, но не всегда это нужно. Просто у этих языков и библиотек подход разный. Я считаю, что писать нужно с использованием языка и его преимуществ. А не пытаться реализовать в языке преимущества других.
[/QUOTE]
Здравствуйте Михаил!
Для начала хотелось бы выразить Вам признательность и уважение за ваши книги. Буквально недавно я учился программировать по второму изданию Библии Delphi. И это помогло мне совершить "быстрый старт". Это была первая моя бумажная книга по программированию.
Но, я все-таки хочу выразить несогласие с тезисами такими как "забудьте как вы делали в Дельфи". Просто потому что как раз в подходах особой разницы между дельфи и сишарп нету. Есть разница в концепции, но это нас прикладных программистов сильно не волнует.
Вот например, я в своих проектах вообще не использую подпрограммы и переменные вне классов, и даже перемещаю из модуля с классом формы глобальный экземпляр в dpr-файл.
Дальше, с событиями, дженериками, анонимными методами и атрибутами я познакомился в дельфи.
Читая MSDN по C# я практически не встречаю революционно нового - основное уже знакомо по дельфи, не считая специфичных штучек дотнета.
Про различия в архитекуре стандартных библиотек - да, ядро RTL сделано в процедурном стиле. Основная причина этого - быстродействие.
Но главное достоинство дельфи VCL является как раз таки олицетворением ООП подхода, и стала прообразом Windows.Forms.
Я это все к тому что не стоит вешать ярлыки на дельфистов якобы они все используют глобальные переменные. Тут предоставляется свобода и программист сам решает, вот я для себя и выбрал объектно-ориентированный подход.
Почему я изучаю C#? Ответ прост: более богатая стандартная библиотека, WPF, ASP.NET, и легче найти работу.
С уважением, Дмитрий.
Михаил Фленов
10 Октября 2010
"забудьте как вы делали в Дельфи" потому что в Дельфи можно использовать глобальные переменные, а в C# их просто нету (может я что-то упускаю).
У C# и Delphi все же много разного. VCL очень похожа на Delphi, но они только похожи. Лично для меня эти языки больше разные, чем похожие.
Дмитрий
10 Октября 2010
Они изначально должны были быть похожи, хотя бы потому, что их проектировал один человек.
Сначала сишарп много позаимствоал из дельфи, а теперь дельфи заимствует у сишарпа.
С С++ намного меньше схожести, синтаксис не считается, т.к. это не принципиально.
Кто-то не помню точно кто сказал что сишарп это 75% джавы и 25% дельфи. Теперь про дельфи можно сказать что там 50% сишарпа.
Не знаю, может Вы просто совсем не следите за последними версиями дельфи?
Дмитрий
12 Сентября 2011
А как быть например со строкой доступа к БД, которая формируется в окне авторизации и должна быть доступна всему приложению? Где ее хранить?
Михаил Фленов
12 Сентября 2011
Строка подключения не должна быть доступна всему приложению. Она должна быть доступна только одному - двум классам, в которых ты работаешь с данными и где у тебя будут находиться объекты SqlConnection.
Владимир
10 Октября 2012
Проблема - в одном из классов библиотечной сборки нужно установить событие, которое бы виделось в главной сборке, ну и во всех остальных заодно.
Елена111
10 Мая 2021
Спасибо.
Может в реальной жизни глобальные переменные - это и зло, но для моей курсовой - самое то)))
Владимир№66
06 Aпреля 2022
Здравствуйте, Михаил!
Еще вопрос по C# VS.
Происходит неожиданное изменение глобальной переменной типа байт, объявленной в классе Programs. Она вдруг принимает значение 0.
Есть ли возможность в отладчике Vs отследить когда она принимает это значение?
Спасибо!
Михаил Фленов
06 Aпреля 2022
Сегодня отвечал на такой вопрос по почте
Добавить Комментарий
Сегодня читал статью Джоила Спольски о том, что программы контроля версий класса git - это будущее. Я тоже впервый раз не понял, что это за фигня, и почему нельзя было просто использовать SubVersion или что-то подобное, но уже через месяц я написал на твитере, что git - это сила.
Если ты работал с классическими программами контроля версий, то при переходе на git будут проблемы потому, что у него совершенно другой подход к хранению изменений. А точнее, он хранит именно изменения в файле, а не создает версии, как это делают классические системы. Чтобы к этому привыкнуть и понять, нужно время. Это как переход с Windows XP на Vista - это не эволюция, а революция. Нужно сделать усилие и заставить себя разок по бренчить код и мерджить его.
Столько лет мы жили вневедении, как слепые кроты, и думали, что нужно хранить именно версии. Но это серьезное заблуждение, которое делает разработку и управление исходным кодом только дороже. Попробую объяснить силу git на примере. Допустим, что у вас есть основная ветка кода, которую вы компилируете в исполняемый файл версии 1.0. На определенном этапе вы создали новую ветку для работы над новой версией программй 2.0. Теперь нужно пофиксить один баг, который есть в обеих ветках. Вы создаете новую подветку для 2.0 и называем ее "branch2-0/fix1". Фиксим код в этой ветке и в ней будут храниться только изменения fix1, а не весь код. Теперь вы можете смёрджить (даже не знаю, какое тут лучше слово придумать английскому merge, может слить или объединить) фикс с веткой исходников версии 2.0 и веткой исходников версии 1.0, и одним разом зафиксить обе ветки.
Я в интернете особо не шляюсь по страницам и за новостями слежу не так часто, поэтому, может я и торможу, но только что заметил, кто является дизайнером сайта yandex.ru. Если ты не зарегестрированный пользователь, то дизайнером будет Лебедев. Но если ты зарегестрирован и вошел на сайт, то внизу страницы сможешь наблюдать надпись: Дизайн — Студия Артемия Лебедева и имя_твоего_аккаунтк. Я вижу там себя, что я на равне со студией Лебедева являюсь дизайнером.
Явный прикол, но вот интересно, почему показывают имя аккаунта? Если уж прикалываться, то по полной, и нужно показывать полное имя и фамилию. Ведь в Yandex паспорте есть полные данные обо мне. Тогда это выглядело бы прикольнее: Дизайн — Студия Артемия Лебедева и Михаил Фленов.
Компания Microsoft посчитала профессиональных разработчиков программного обеспечения в России. Мне понравился способ, который они использовали. На начало 2010 г. было около 350 тыс. программистов и эти данные получены на основе числа проданных лицензий на средства разработки.
Microsoft наверно не в курсе, что существуют еще другие средства разработки, не от Microsoft. Например, в России очень много профессиональных программистов, которые пишут на Delphi, PHP, и есть даже такие, которые сидят в Linux. У нас на работе полно профессиональных программистов, которые не используют средства разработки Microsoft, а пишут ASP.NET приложения в блокноте. А может таких программистов в Microsoft не считают за профессиональных?
Тем же гениальным методом Microsoft выяснила, что в 2003-м году России насчитывалось около 212 тысяч разработчиков программного обеспечения. Это значит, что в среднем каждый год в России появляются около 20 тыс. новых профессиональных программистов. Интересным тут словом является "новых". Неужели все 20 тысяч программеров являются новыми? На самом же деле, каждый год в России появляется около 20 тысяч легальных профессиональных программистов, использующих технологии Microsoft. Вот так будет на много правильнее. Потому что я уверен, что из этих 20 тысяч, громадное число программеров уже с большим стажем, просто они всегда использовали нелегальный софт.
Сегодня обновил сайт Heapar Software. Причем обновлен не только дизайн небольшой косметикой, но и обновлен компонент для создания отчетов Heapar Small Report . Изменения небольшие, но удобные. Сам их использую в своих утилитах под маркой CyD, которые так же недавно серьезно обновил. Но об этих утилитах чуть позже, потому что версия еще не стабильна. Изменений много, и я наверно поторопился выкладывать ее.
Но вернемся к компоненту Small Report. В нем исправлен глюк с отображением, если для скроллинга использовать колесико. Добавлена возможность скролла с клавиатуры клавишами стрелок и Page Up Page Down, а так же возможность скролла на определенную строку. Это будет удобно для создания закладок в тексте. Опять же, на эту идею меня подтолкнул собственный проект. Я сам использую то, что создаю, иначе нафига создавать?