Для чего используется главная функция main. Аргументы функции main(). Области видимости и время жизни переменных
Для чего нужны функции в C?
Функции в Си применяются для выполнения определённых действий в рамках общей программы. Программист сам решает какие именно действия вывести в функции. Особенно удобно применять функции для многократно повторяющихся действий.
Простой пример функции в Cи
Пример функции в Cи:
#include
Это очень простая программа на Си. Она просто выводит строку «Functions in C». В программе имеется единственная функция под названием main. Рассмотрим эту функцию подробно. В заголовке функции, т.е. в строке
int – это тип возвращаемого функцией значения;
main - это имя функции;
(void) - это перечень аргументов функции. Слово void указывает, что у данной функции нет аргументов;
return – это оператор, который завершает выполнение функции и возвращает результат работы функции в точку вызова этой функции;
EXIT_SUCCESS - это значение, равное нулю. Оно определено в файле stdlib.h;
часть функции после заголовка, заключенная в фигурные скобки
{
puts("Functions in C");
return EXIT_SUCCESS;
}
называют телом функции.
Итак, когда мы работаем с функцией надо указать имя функции, у нас это main, тип возвращаемого функцией значения, у нас это int, дать перечень аргументов в круглых скобках после имени функции, у нас нет аргументов, поэтому пишем void, в теле функции выполнить какие-то действия (ради них и создавалась функция) и вернуть результат работы функции оператором return. Вот основное, что нужно знать про функции в C.
Как из одной функции в Cи вызвать другую функцию?
Рассмотрим пример вызова функций в Си:
/*
Author: @author Subbotin B.P..h>
#include
Запускаем на выполнение и получаем:
В этом примере создана функция sum, которая складывает два целых числа и возвращает результат. Разберём подробно устройство этой функции.
Заголовок функции sum:
int sum(int a, int b)
здесь int - это тип возвращаемого функцией значения;
sum - это имя функции;
(int a, int b) - в круглых скобках после имени функции дан перечень её аргументов: первый аргумент int a, второй аргумент int b. Имена аргументов являются формальными, т.е. при вызове функции мы не обязаны отправлять в эту функцию в качестве аргументов значения перемнных с именами a и b. В функции main мы вызываем функцию sum так: sum(d, e);. Но важно, чтоб переданные в функцию аргументы совпадали по типу с объявленными в функции.
В теле функции sum, т.е. внутри фигурных скобок после заголовка функции, мы создаем локальную переменную int c, присваиваем ей значение суммы a плюс b и возвращаем её в качестве результата работы функции опрератором return.
Теперь посмотрим как функция sum вызывается из функции main.
Вот функция main:
Int main(void) { puts("Functions in C"); int d = 1; int e = 2; int f = sum(d, e); printf("1 + 2 = %d", f); return EXIT_SUCCESS; }
Сначала мы создаём две переменных типа int
Int d = 1; int e = 2;
их мы передадим в функцию sum в качестве значений аргументов.
int f = sum(d, e);
её значением будет результат работы функции sum, т.е. мы вызываем функцию sum, которая возвратит значение типа int, его-то мы и присваиваем переменной f. В качестве аргументов передаём d и f. Но в заголовке функции sum
int sum(int a, int b)
аргументы называются a и b, почему тогда мы передаем d и f? Потому что в заголовке функций пишут формальные аргументы, т.е. НЕ важны названия аргументов, а важны их типы. У функции sum оба аргумента имеют тип int, значит при вызове этой функции надо передать два аргумента типа int с любыми названиями.
Ещё одна тонкость. Функция должна быть объявлена до места её первого вызова. В нашем примере так и было: сначала объявлена функция sum, а уж после мы вызываем её из функции main. Если функция объявляется после места её вызова, то следует использовать прототип функции.
Прототип функции в Си
Рассмотрим пример функциив Си:
/*
Author: @author Subbotin B.P..h>
#include
В этом примере функция sum определена ниже места её вызова в функции main. В таком случае надо использовать прототип функции sum. Прототип у нас объявлен выше функции main:
int sum(int a, int b);
Прототип - это заголовок функции, который завершается точкой с запятой. Прототип - это объявление функции, которая будет ниже определена. Именно так у нас и сделано: мы объявили прототип функции
int f = sum(d, e);
а ниже функции main определяем функцию sum, которая предварительно была объявлена в прототипе:
Int sum(int a, int b) { int c = 0; c = a + b; return c; }
Чем объявление функции в Си отличается от определения функции в Си?
Когда мы пишем прототип функции, например так:
int sum(int a, int b);
то мы объявляем функцию.
А когда мы реализуем функцию, т.е. записываем не только заголовок, но и тело функции, например:
Int sum(int a, int b) { int c = 0; c = a + b; return c; }
то мы определяем функцию.
Оператор return
Оператор return завершает работу функции в C и возвращает результат её работы в точку вызова. Пример:
Int sum(int a, int b) { int c = 0; c = a + b; return c; }
Эту функцию можно упростить:
Int sum(int a, int b) { return a + b; }
здесь оператор return вернёт значение суммы a + b.
Операторов return в одной функции может быть несколько. Пример:
Int sum(int a, int b) { if(a > 2) { return 0;// Первый случай; } if(b < 0) { return 0;// Второй случай; } return a + b; }
Если в примере значение аргумента a окажется больше двух, то функция вернет ноль (первый случай) и всё, что ниже комментария «// Первый случай;» выполнятся не будет. Если a будет меньше двух, но b будет меньше нуля, то функция завершит свою работу и всё, что ниже комментария «// Второй случай;» выполнятся не будет.
И только если оба предыдущих условия не выполняются, то выполнение программы дойдёт до последнего оператора return и будет возвращена сумма a + b.
Передача аргументов функции по значению
Аргументы можно передавать в функцию C по значению. Пример:
/*
Author: @author Subbotin B.P..h>
#include
В примере, в функции main, создаём переменную int d = 10. Передаём по значению эту переменную в функцию sum(d). Внутри функции sum значение переменной увеличивается на 5. Но в функции main значение d не изменится, ведь она была передана по значению. Это означает, что было передано значение переменной, а не сама переменная. Об этом говорит и результат работы программы:
т.е. после возврата из функции sum значеие d не изменилось, тогда как внутри функции sum оно менялось.
Передача указателей функции Си
Если в качестве аргумента функции передавать вместо значения переменной указатель на эту переменную, то значение этой переменной может меняться. Для примера берём программу из предыдущего раздела, несколько изменив её:
/*
Author: @author Subbotin B.P..h>
#include
В этом варианте программы я перешел от передачи аргумента по значению к передаче указателя на переменную. Рассмотрим подробнее этот момент.
printf("sum = %d\n", sum(&d));
в функцию sum передается не значение переменной d, равное 10-ти, а адрес этой переменной, вот так:
Теперь посмотрим на функцию sum:
Int sum(int *a) { return *a += 5; }
Аргументом её является указатель на int. Мы знаем, что указатель - это переменная, значением которой является адрес какого-то объекта. Адрес переменной d отправляем в функцию sum:
Внутри sum указатель int *a разыменовывается. Это позволяет от указателя перейти к самой переменной, на которую и указывает наш указатель. А в нашем случае это переменная d, т.е. выражение
равносильно выражению
Результат: функция sum изменяет значение переменной d:
На этот раз изменяется значение d после возврата из sum, чего не наблюдалось в предыдущм пункте, когда мы передавали аргумент по значению.
C/C++ в Eclipse
Все примеры для этой статьи я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть . Если вы работаете в другой среде, то примеры и там будут работать.
Минимальной программой на C++ является
Int main() { } // the minimal C++ program
В этой программе представлено объявление функции main, которая не принимает никаких аргументов. Фигурные скобки отражают группировку в C++ и в данном случае показывают тело функции main. То есть начало функции main - открывающая скобка, и конец функции main - закрывающая скобка. Двойной слэш показывает начало комментария. Комментарии игнорируются компилятором и служат для уточнения информации в коде.
Каждая программа, написанная на C++, имеет в себе функцию main() , с которой начинается запуск программы. Функция main(), как правило, возвращает результат своего выполнения, о чем сигнализирует int (integer - целочисленный), который написан перед функцией main() . При правильном, успешном завершении функция main() возвращает в качестве результата 0 . Значение результата, отличное от нуля сигнализирует о нештатном завершении программы.
Возвращаемое программой значение по завершению может использоваться в операционной системе для служебных целей.
Типичным примером первой программы на любом языке программирования является вывод текста "Hello, World!":
#include
Но так ли всё просто в данной программе? В целом, уже одна эта маленькая программа несёт в себе очень большой пласт информации, который необходимо понимать для разработки на C++.
- Директива
#include
#include
сообщает компилятору о том, что необходимо подключить некий заголовочный файл, компоненты которого планируется использовать в файле, где объявлена функция main() . iostream - это стандартная библиотека ввода вывода из STL. То есть здесь уже используется функционал библиотек, хоть и являющихся для языка стандартом. И последний момент - это угловые скобки, в которых находится название библиотеки, которые говорят о том, что это включение внешних файлов в проект, а не тех которые находятся в составе проекта. Те же файлы, которые находятся в составе проекта подключаются обрамляясь в обычные кавычки, например #include "myclass.h". Такое подключение библиотек является стандартом. Например, в Visual Studio при несоблюдении данного стандарта будут выпадать ошибки.
std - это использование пространства имён, в котором находится оператор вывода cout. Пространства имён были введены в C++ для того, чтобы убрать конфликты имён между библиотеками и проектом разработчика, если где-то имеются повторяющиеся наименования функций или классов. В Java для разрешения конфликтов имён используется система пакетов.
cout - это оператор вывода, у которого перегружен оператор << , чтобы не использовать отдельную функцию для вывода текста в консоль.
Это помимо того, что запись функции main может иметь различный вид, хотя стандартом являются две записи:
- int main()
- int main(int argc, char* argv)
Можно встретить ещё записи типа void main() и т.д. Но это ошибочные записи, хотя в некоторых компиляторах они будут компилироваться, причём даже без ошибок и предупреждений.
В записи int main(int argc, char* argv) передаются аргументы:
- argc - указывает количество переданных аргументов. Всегда не меньше 1, поскольку всегда передаётся имя программы
- argv - массив указателей на аргументы, которые передаются в качестве строковых переменных.
Если argc больше 1, значит при запуске программы были переданы дополнительные аргументы.
Проверка может выглядеть следующим образом:
#include В целом, есть большое количество моментов, которые необходимо понимать в C++ даже для небольшой программы, но от этого только интереснее;-) Я знаю, что поток старый, но несколько лет назад этот вопрос беспокоил меня, поэтому я хотел бросить свою половину процента (если это). Я всегда рассматриваю функции C, как если бы они фиксировали количество аргументов независимо от контекста, если только они не используют va_args. То есть, я верю, что ВСЕГДА имеют прототип: Int main(int argc, char **argv).
даже если аргументы не переданы, функция имеет эти аргументы в стеке, потому что основная функция не имеет перегрузки функций. C имеет возможность иметь примитивную перегрузку, просто делая вид, что аргумент отсутствует. В этом случае аргумент все еще передается и находится в стеке, но вы никогда не обращаетесь к нему, поэтому он просто уменьшает размер исходного кода. Высказывание int main() просто означает, что я знаю, что функция может иметь параметры, но я их не использую, поэтому я пишу int main(). Высказывание int main (void) говорит о том, что main НЕКОТОРНО не имеет аргументов и подразумевает наличие двух разных прототипов функций: Int main(void);
int main(int argc, char **argv);
Так как C не имеет функции перегрузки, это несколько вводит меня в заблуждение, и я не доверяю коду с основным (void) в нем. Я бы не стал, если main NEVER принял какие-либо параметры, и в этом случае main (void) будет полностью в порядке. ПРИМЕЧАНИЕ. В некоторых реализациях есть больше параметров в основном, чем argc и argv, таких как env, но это меня не беспокоит, потому что я знаю, что я не говорю прямо, что это только два параметра, но это минимальные параметры, и все в порядке, чтобы иметь больше, но не меньше. Это противоречит прямому утверждению int main (void), который кричит на меня, поскольку ЭТОТ ФУНКЦИЯ НЕТ ПАРАМЕТРОВ, что неверно, поскольку это так, они просто опускаются. Вот мой базовый код:
/* sample.c - build into sample. */
#include ./sample У меня явно есть аргументы У функции явно есть аргументы, переданные ей, несмотря на то, что она явно не говорит о том, что она не набирает void в прототип функции. Как указано выше: (6.7.6.3p10) Частный случай неименованного параметра типа void как только элемент в списке указывает, что функция не имеет параметров. Таким образом, говоря, что функция имеет пустоту как аргумент, но фактически наличие аргументов в стеке является противоречием. Моя точка зрения заключается в том, что аргументы все еще существуют, поэтому явное утверждение о том, что main не содержит аргументов, является нечестным. Честным способом было бы сказать int main(), который не утверждает ничего о том, сколько параметров у него есть, только о том, сколько параметров вам нужно. ПРИМЕЧАНИЕ2: _argc, _pargv зависят от системы, чтобы найти ваши значения, которые вы должны найти, запустив эту программу:
/* findargs.c */
#include Эти значения должны оставаться правильными для вашей конкретной системы. Borland С++ поддерживает три аргумента main(). Первые два - это традиционные argc и argv. Это единственные аргументы функции main(), определяемые стандартом ANSI С. Они позволяют передавать аргументы командной строки в программу. Аргументы командной строки - это информация, следующая за именем программы в командной строке операционной системы. Например, когда программа компилируется с помощью строчного компилятора Borland, набирается, как правило, bcc имя_ программы
Где имя_программы
- это программа, которую необходимо откомпилировать. Имя программы передается компилятору в качестве аргумента. Параметр argc содержит число аргументов командной строки и является целым числом. Он всегда равен, по крайней мере, 1, поскольку имя программы квалифицируется как первый аргумент. Параметр argv - это указатель на массив символьных указателей. Каждый элемент данного массива указывает на аргумент командной строки. Все аргументы командной строки - это строки. Все числа конвертируются программой во внутренний формат. Следующая программа выводит «Hello», а затем имя пользователя, если его набрать прямо за именем программы:
#include Если назвать данную программу name, а имя пользователя Сергей, то для запуска программы следует набрать: Аргументы командной строки должны отделяться пробелами или табуляциями. Запятые, точки с запятыми и им подобные символы не рассматриваются как разделители. Например: Состоит из трех строк, в то время как Herb,Rick,Fred Это одна строка - запятые не являются разделителями. Если необходимо передать строку, содержащую пробелы или табуляции в виде одного аргумента, следует ее заключить в двойные кавычки. Например, это один аргумент:
"this is a test" Важно правильно объявить argv. Наиболее типичным методом является: Пустые скобки указывают на то, что массив не имеет фиксированной длины. Можно получить доступ к отдельным элементам с помощью индексации argv. Например, argv указывает на первую строку, всегда содержащую имя программы. argv указывает на следующую строку и так далее. Ниже приведен небольшой пример по использованию аргументов командной строки. Он отсчитывает в обратном порядке от значения, указанного в командной строке, и при достижении нуля подает сигнал. Обратим внимание, что первый аргумент содержит число, преобразованное в целое число с использованием стандартной функции atoi(). Если в качестве второго аргумента присутствует строка "display", то на экране будет отображаться сам счетчик.
/* программа отсчета */
#include Обратим внимание, что если не указаны аргументы, появляется сообщение об ошибке. Это наиболее типично для программ, использующих аргументы командной строки для выдачи инструкций, если была попытка запустить программу без правильной информации. Для доступа к отдельным символам командной строки следует добавить второй индекс к argv. Например, следующая программа выводит все аргументы, с которыми она вызывалась, по одному символу за раз:
#include Надо помнить, что первый индекс предназначен для доступа к строке, а второй - для доступа к символу строки. Обычно argc и argv используются для получения исходных команд. Теоретически можно иметь до 32767 аргументов, но большинство операционных систем не позволяют даже близко подойти к этому. Обычно данные аргументы используются для указания имени файла или опций. Использование аргументов командной строки придает программе профессиональный вид и допускает использование программы в командных файлах. Если подсоединить файл WILDARGS.OBJ, поставляемый с Borland С++, то можно будет использовать шаблоны в аргументах типа *.EXE. (Borland С++ автоматически обрабатывает шаблоны и соответствующим образом увеличивает argc.) Например, если подсоединить к следующей программе WILDARGS.OBJ, она выдаст, сколько файлов соответствует имени указанного в командной строке файла:
/* Скомпонуйте данную программу с WILDARGS.OBJ */
#include Если назвать данную программу WA, затем запустить ее как указано ниже, получим число файлов, имеющих расширение ЕХE, и список имен этих файлов: Помимо argc и argv Borland С++ также предоставляет третий аргумент командной строки -env. Параметр env позволяет программе получить доступ к информации о среде операционной системы. Параметр env должен следовать за argc и argv и объявляется следующим образом: Как можно видеть, env объявляется так же, как и argv. Так же, как и argv, это указатель на массив строк. Каждая строка - это строка среды, определенная операционной системой. Параметр env не имеет аналога параметра argc, который сообщал бы, сколько имеется строк среды. Вместо этого последняя строка среды нулевая. Следующая программа выводит все строки среды, определенные на текущий момент в операционной системе:
/* данная программа выводит все строки окружения */
#include Обратим внимание, что хотя argc и argv не используются программой, они должны присутствовать в списке параметров. С не знает имена параметров. Вместо этого их использование определяется по порядку объявления параметров. Фактически можно обозвать параметр как угодно. Поскольку argc, argv и env - это традиционные имена, то лучше их использовать и далее, чтобы любой человек, читающий программу, мог мгновенно понять, что это аргументы функции main(). Для программ типичной задачей является поиск значения, определенного в строке среды. Например, содержимое строки PATH позволяет программам использовать пути поиска. Следующая программа демонстрирует, как найти строки, объявляющие стандартные пути поиска. Она использует стандартную библиотечную функцию strstr(), имеющую следующий прототип: Char *strstr(const char *str1, const char *str2); Функция strstr() ищет строку, на которую указывает str1 в строке, на которую указывает str2. Если такая строка найдена, то возвращается указатель на первое положение. Если не найдено соответствий, то функция возвращает NULL.
/* программа ищет среди строк окружения строку, содержащую PATH */
#include Функция main.
Каждая программа на С и C++ должна иметь функцию main;
причем ваше дело, где вы ее поместите. Некоторые программисты
помещают ее в начале файла, некоторые в конце. Однако независимо
от ее положения необходимо помнить следующее:
Аргументы функции "main".
Запускающая процедура Borland C++ посылает функции main три
параметра (аргумента): argc, argv и env.
- argc, целое, - это число аргументов командной строки,
посылаемое функции main,
- argv это массив указателей на строки (char * ).
Под версией DOS 3.x и более поздними argv
определяется как полный маршрут запускаемой программы.
При работе под более ранними версиями DOS argv указывает
на нулевую строку ("").
argv указывает на первую после имени программы строку
командной строки.
argv указывает на вторую после имени программы строку
командной строки.
argv указывает на последний аргумент, посылаемый
функции main.
argv содержит NULL.
- env также является массивом указателей на строки. Каждый
элемент env содержит строку вида ENVVAR=значение.
ENVVAR - это имя переменной среды, типа PATH или 87.
<значение> это значение данной переменной окружения,
например C:\DOS;C:\TOOLS (для PATH) или YES (для 87).
Заметим, однако, что если вы описываете некоторые из этих
аргументов, то вы должны описывать их в таком порядке: argc,
argv, env. Например, допустимы следующие объявления аргументов:
main()
main(int argc) /* допустимо но не очень хорошо */
main(int argc, char *argv)
main(int argc, char *argv, char *env)
Объявление main(int argc) не очень удобно тем, что зная
количество параметров, вы не имеете доступа к ним самим.
Аргумент env всегда доступен через глобальную переменную
environ. Смотрите описание переменной environ (в Главе 3) и
функции putenv и getenv (в Главе 2).
Параметры argc и argv также доступны через переменные_argc
и _argv.
Пример программы, использующей argc, argv и env.
Это пример программы ARGS.EXE, которая демонстрирует
простейший путь использования аргументов, посылаемых функции
main.
/* программа ARGS.C */
#include
{
if(argc!=2)
{
printf ("You forgot to type your name\n");
return 1;
}
printf("Hello %s", argv);
return 0;
}
name Сергей.
В результате работы программы появится:
«Hello Сергей».
#include
# include
int main(int argc, char *argv)
{
int disp, count;
if(argc<2)
{
printf("You must enter the length of the count\n");
printf ("on the command line. Try again.\n");
return 1;
}
if (argc==3 && !strcmp(argv,"display")) disp = 1;
else disp = 0;
for(count=atoi(argv); count; -count)
if (disp) printf("%d ", count);
printf("%c", "\a"); /* на большинстве компьютеров это звонок */
return 0;
}
int main(int argc, char *argv)
{
int t, i;
for(t=0; t
i = 0;
while(argv[t][i])
{
printf("%c", argv[t][i]);
}
printf (" ");
}
return 0;
}
int main(int argc, char *argv)
{
register int i;
printf("%d files match specified name\n", argc-1);
printf("They are: ");
for(i=1; i
return 0;
}
int main(int argc, char *argv, char *env)
{
int t;
for(t=0; env[t]/ t++)
printf("%s\n", env[t]);
return 0;
}
#include
int main (int argc, char *argv, char *env)
{
int t;
for(t=0; env[t]; t++)
{
if(strstr(env[t], "PATH"))
printf("%s\n", env[t]);
}
return 0;
}Рекомендуем также