Функция 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Страница 53 из 85
1.5.3. Передача параметров функции main
Функция main, с которой начинается выполнение программы на языке программирования С, может быть определена с параметрами, которые передаются из внешнего окружения, например, из командной строки. Во внешнем окружении действуют свои правила представления данных, а точнее, все данные представляются в виде строк символов. Для передачи этих строк в функцию main используются два параметра, первый параметр служит для передачи числа передаваемых строк, второй для передачи самих строк. Общепринятые (но не обязательные) имена этих параметров argc и argv. Параметр argc имеет тип int, его значение формируется из анализа командной строки и равно количеству слов в командной строке, включая и имя вызываемой программы (под словом понимается любой текст не содержащий символа пробел). Параметр argv это массив указателей на строки, каждая из которых содержит одно слово из командной строки. Если слово должно содержать символ пробел, то при записи его в командную строку оно должно быть заключено в кавычки.
Функция main может иметь и третий параметр, который принято называть argp, и который служит для передачи в функцию main параметров операционной системы (среды) в которой выполняется программа на языке программирования С.
Заголовок функции main имеет вид:
Если, например, командная строка программы на языке программирования С имеет вид:
A:\>cprog working "C program" 1
то аргументы argc, argv, argp представляются в памяти как показано в схеме на рис.1.
Argc [ 4 ]
argv --> -->
-->
-->
-->
argp --> -->
-->
-->
-->
Рис.1. Схема размещения параметров командной строки
Операционная система поддерживает передачу значений для параметров argc, argv, argp, а на пользователе лежит ответственность за передачу и использование фактических аргументов функции main.
Следующий пример представляет программу печати фактических аргументов, передаваемых в функцию main из операционной системы и параметров операционной системы.
Пример:
int main (int argc, char *argv, char *argp)
{ int i=0;
printf ("\n Имя программы %s", argv);
for (i=1; i>=argc; i++)
printf ("\n аргумент %d равен %s", argv[i]);
printf ("\n Параметры операционной системы:");
while (*argp)
{ printf ("\n %s",*argp);
argp++;
}
return (0);
}
Доступ к параметрам операционной системы можно также получить при помощи библиотечной функции geteuv, ее прототип имеет следующий вид:
char *geteuv (const char *varname);
Аргумент этой функции задает имя параметра среды, указатель на значение которой выдаст функция geteuv. Если указанный параметр не определен в среде в данный момент, то возвращаемое значение NULL.
Используя указатель, полученный функцией geteuv, можно только прочитать значение параметра операционной системы, но нельзя его изменить. Для изменения значения параметра системы предназначена функция puteuv.
Компилятор языка программирования С строит С-программу таким образом, что вначале работы программы выполняется некоторая инициализация, включающая, кроме всего прочего, обработку аргументов, передаваемых функции main, и передачу ей значений параметров среды. Эти действия выполняются библиотечными функциями _setargv и _seteuv, которые всегда помещаются компилятором перед функцией main.
Если программа на языке программирования С не использует передачу аргументов и значений параметров операционной системы, то целесообразно запретить использование библиотечных функций _setargv и _seteuv поместив в языке программирования С-программу перед функцией main функции с такими же именами, но не выполняющие никаких действий (заглушки). Начало программы в этом случае будет иметь вид:
Setargv()
}
-seteuv()
{ return ; /* пустая функция */
}
int main()
{ /* главная функция без аргументов */
...
...
renurn (0);
}
В приведенной программе при вызове библиотечных функций _setargv и _seteuv будут использованы функции помещенные в программу пользователем и не выполняющие никаких действий. Это заметно снизит размер получаемого exe-файла.
Borland С++ поддерживает три аргумента main(). Первые два - это традиционные argc и argv. Это единственные аргументы функции main(), определяемые стандартом ANSI С. Они позволяют передавать аргументы командной строки в программу. Аргументы командной строки - это информация, следующая за именем программы в командной строке операционной системы. Например, когда программа компилируется с помощью строчного компилятора Borland, набирается, как правило, bcc имя_ программы
Где имя_программы - это программа, которую необходимо откомпилировать. Имя программы передается компилятору в качестве аргумента.
Параметр argc содержит число аргументов командной строки и является целым числом. Он всегда равен, по крайней мере, 1, поскольку имя программы квалифицируется как первый аргумент. Параметр argv - это указатель на массив символьных указателей. Каждый элемент данного массива указывает на аргумент командной строки. Все аргументы командной строки - это строки. Все числа конвертируются программой во внутренний формат. Следующая программа выводит «Hello», а затем имя пользователя, если его набрать прямо за именем программы:
#include
{
if(argc!=2)
{
printf ("You forgot to type your name\n");
return 1;
}
printf("Hello %s", argv);
return 0;
}
Если назвать данную программу name, а имя пользователя Сергей, то для запуска программы следует набрать:
name Сергей.
В результате работы программы появится:
«Hello Сергей».
Аргументы командной строки должны отделяться пробелами или табуляциями. Запятые, точки с запятыми и им подобные символы не рассматриваются как разделители. Например:
Состоит из трех строк, в то время как
Herb,Rick,Fred
Это одна строка - запятые не являются разделителями.
Если необходимо передать строку, содержащую пробелы или табуляции в виде одного аргумента, следует ее заключить в двойные кавычки. Например, это один аргумент:
"this is a test"
Важно правильно объявить argv. Наиболее типичным методом является:
Пустые скобки указывают на то, что массив не имеет фиксированной длины. Можно получить доступ к отдельным элементам с помощью индексации argv. Например, argv указывает на первую строку, всегда содержащую имя программы. argv указывает на следующую строку и так далее.
Ниже приведен небольшой пример по использованию аргументов командной строки. Он отсчитывает в обратном порядке от значения, указанного в командной строке, и при достижении нуля подает сигнал. Обратим внимание, что первый аргумент содержит число, преобразованное в целое число с использованием стандартной функции atoi(). Если в качестве второго аргумента присутствует строка "display", то на экране будет отображаться сам счетчик.
/* программа отсчета */
#include
#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;
}
Обратим внимание, что если не указаны аргументы, появляется сообщение об ошибке. Это наиболее типично для программ, использующих аргументы командной строки для выдачи инструкций, если была попытка запустить программу без правильной информации.
Для доступа к отдельным символам командной строки следует добавить второй индекс к argv. Например, следующая программа выводит все аргументы, с которыми она вызывалась, по одному символу за раз:
#include
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;
}
Надо помнить, что первый индекс предназначен для доступа к строке, а второй - для доступа к символу строки.
Обычно argc и argv используются для получения исходных команд. Теоретически можно иметь до 32767 аргументов, но большинство операционных систем не позволяют даже близко подойти к этому. Обычно данные аргументы используются для указания имени файла или опций. Использование аргументов командной строки придает программе профессиональный вид и допускает использование программы в командных файлах.
Если подсоединить файл WILDARGS.OBJ, поставляемый с Borland С++, то можно будет использовать шаблоны в аргументах типа *.EXE. (Borland С++ автоматически обрабатывает шаблоны и соответствующим образом увеличивает argc.) Например, если подсоединить к следующей программе WILDARGS.OBJ, она выдаст, сколько файлов соответствует имени указанного в командной строке файла:
/* Скомпонуйте данную программу с WILDARGS.OBJ */
#include
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;
}
Если назвать данную программу WA, затем запустить ее как указано ниже, получим число файлов, имеющих расширение ЕХE, и список имен этих файлов:
Помимо argc и argv Borland С++ также предоставляет третий аргумент командной строки -env. Параметр env позволяет программе получить доступ к информации о среде операционной системы. Параметр env должен следовать за argc и argv и объявляется следующим образом:
Как можно видеть, env объявляется так же, как и argv. Так же, как и argv, это указатель на массив строк. Каждая строка - это строка среды, определенная операционной системой. Параметр env не имеет аналога параметра argc, который сообщал бы, сколько имеется строк среды. Вместо этого последняя строка среды нулевая. Следующая программа выводит все строки среды, определенные на текущий момент в операционной системе:
/* данная программа выводит все строки окружения */
#include
int main(int argc, char *argv, char *env)
{
int t;
for(t=0; env[t]/ t++)
printf("%s\n", env[t]);
return 0;
}
Обратим внимание, что хотя argc и argv не используются программой, они должны присутствовать в списке параметров. С не знает имена параметров. Вместо этого их использование определяется по порядку объявления параметров. Фактически можно обозвать параметр как угодно. Поскольку argc, argv и env - это традиционные имена, то лучше их использовать и далее, чтобы любой человек, читающий программу, мог мгновенно понять, что это аргументы функции main().
Для программ типичной задачей является поиск значения, определенного в строке среды. Например, содержимое строки PATH позволяет программам использовать пути поиска. Следующая программа демонстрирует, как найти строки, объявляющие стандартные пути поиска. Она использует стандартную библиотечную функцию strstr(), имеющую следующий прототип:
Char *strstr(const char *str1, const char *str2);
Функция strstr() ищет строку, на которую указывает str1 в строке, на которую указывает str2. Если такая строка найдена, то возвращается указатель на первое положение. Если не найдено соответствий, то функция возвращает NULL.
/* программа ищет среди строк окружения строку, содержащую PATH */
#include
#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;
}
Любая программа на языке С начинается с вызова функции main(). Эта функция должна быть в каждой программе.
Как и любая другая функция, функция main() может иметь параметры. Иногда при запуске программы бывает полезно передать ей какую-либо информацию. Такая информация передается функции main() с помощью аргументов командной строки. Аргументы командной строки – это информация, которая вводится в командной строке вслед за именем программы при запуске программы на выполнение не из среды разработки программы. Например, чтобы запустить архивацию файла task.cpp, необходимо в командной строке набрать следующее:
winrar a archTask task.cpp // winrar.exe a archTask task.cpp
где winrar – имя программы-архиватора, а строки «a », «archTask » и «task . cpp » представляет собой аргументы командной строки, которые говорят программе, что надо создать архив («a ») с именем archTask из одного файла task . cpp .
При передаче параметров в функцию main() ее надо определять так:
int main(int argc, char *argv) { } // или void main(...){}
Параметр argc содержит количество аргументов в командной строке и является целым числом, причем он всегда не меньше 1, потому что первым аргументом всегда передается имя программы (имя программы с полным путем к программе).
Параметр argv является указателем на массив указателей на строки. В этом массиве каждый элемент указывает на очередной аргумент командной строки. Пустые квадратные скобки указывают на то, что у массива неопределенная длина. Получить доступ к отдельным аргументам можно с помощью индексации массива argv. Например, argv указывает на первую символьную строку, которой всегда является имя программы; argv указывает на первый аргумент и так далее. Список аргументов ограничен NULL, т.е. argv == NULL.
Чтобы получить доступ к отдельному символу одного из аргументов командной строки, надо использовать в argv второй индекс. Т.е., первый индекс argv обеспечивает доступ к строке, а второй индекс – доступ к ее отдельным символам.
Все аргументы командной строки являются строковыми, поэтому преобразование числовых параметров в нужный формат должно быть предусмотрено в программе при ее разработке.
Пример программы с разными способами перевода чисел в символьном формате в целые и вещественные числа:
#include
#include
// при запуске задаем, например, такие аргументы: 100 2.7
void main(int a, char *b) {
k = strtol(b, &ptr, 10); // ptr = адрес места ошибки в строке
f = strtod(b, &ptr);
sscanf(b, "%d", &k);
sscanf(b, "%lf", &f);
Имена argc и argv являются традиционными, но не обязательными. Эти два параметра в функции main() можно называть как угодно.
Простой пример использования аргументов командной строки:
int main(int argc, char *argv) {
if (argc != 4) {
printf("Неверные параметры запуска программы!\n");
k = atoi(argv); // преобразование параметра-числа
printf("Привет, %s из группы %s %d-го курса",
Если имя программы – task, а ваше имя «Вася», группа «ПМ-11» с первого курса, то для запуска программы следует в командную строку ввести:
task Вася ПМ-11 1
В результате выполнения программы на экране появится сообщение: «Привет, Вася из группы ПМ-11 1-го курса».
Обратите внимание: если не все аргументы командной строки будут заданы, то будет выведено сообщение об ошибке. В программах с аргументами командной строки часто делается следующее: в случае, когда пользователь запускает эти программы без ввода нужной информации, выводятся инструкции о том, как правильно указывать аргументы.
Аргументы командной строки необходимо отделять друг от друга пробелом. Если в самом аргумента есть пробелы, то, чтобы из него не получилось несколько аргументов, этот аргумент надо заключать в двойные кавычки. В результате вся строка в кавычках будет считаться одним аргументом. Например, программу можно запустить так: task “Вася и Петя” ПМ-21 2. В результате выполнения программы на экране появится сообщение: «Привет, Вася и Петя из группы ПМ-21 2-го курса».
Что такое char *argv? Это массив, элементами которого служат указатели , то есть массив указателей . Значит при передаче параметров в main() ее можно определять и так:
void main(int argc, char **argv) {
Задача. Вывести на экран все аргументы командной строки (имя программы выводить не надо).
#include
void main(int argc, char *argv){
for (i = 1; i < argc; i++)
printf("%s\n", argv[i]);
Второй вариант ================
#include
void main(int argc, char **argv){
while((p=*argv) != NULL) {
printf("%s\n", p);
Обычно аргументы командной строки используют для того, чтобы передать программе начальные данные, которые понадобятся ей при запуске (например, через аргументы командной строки часто передаются такие данные, как имя файла или параметры запуска программы).
Когда для программы не требуются параметры командной строки, в списке параметров функции main() используют ключевое слово void (или просто ничего не указывают).
Как отлаживать в BC программы, требующие аргументы командной строки. В меню Run→Arguments... необходимо ввести аргументы командной строки. Имя программы указывать не надо. Дальше можно просто запускать и отлаживать программу в среде разработки как обычно.
Пожалуйста, приостановите работу AdBlock на этом сайте.
Итак, зачем нужны пользовательские функции? Пользовательские функции нужны для того, чтобы программистам было проще писать программы.
Помните, мы говорили о парадигмах программирования, а точнее о структурном программировании. Основной идеей там было то, что любую программу можно можно написать используя только три основных конструкции: следование, условие и цикл. Теперь к этим конструкциям мы добавим ещё одну – «подпрограммы» – и получим новую парадигму процедурное программирование» .
Отличие лишь в том, что отдельные кусочки нашей основной программы (в частности, повторяющиеся) мы будем записывать в виде отдельных функций (подпрограмм, процедур) и по мере необходимости их вызывать. По сути, программа теперь будет описывать взаимодействие различных функций.
Итак, в этом уроке мы подробно обсудим то, как функции устроены изнутри. А также научимся создавать свои собственные пользовательские функции.
Как устроены функции
Вспомним информацию с первого урока. Все функции, в том числе и те, которые пишет пользователь, устроены сходным образом. У них имеется две основных составных части: заголовок функции и тело функции.
Листинг 1.
Int main(void){ // заголовок функции // в фигурных скобках записано тело функции }
С телом функции всё ясно: там описывается алгоритм работы функции. Давайте разберёмся с заголовком. Он состоит из трёх обязательных частей:
- тип возвращаемого значения;
- имя функции;
- аргументы функции.
Сначала записывается тип возвращаемого значения, например, int
, как в функции main
. Если функция не должна возвращать никакое значение в программу, то на этом месте пишется ключевое слово void
. Казалось бы, что раз функция ничего не возвращает, то и не нужно ничего писать. Раньше, кстати, в языке Си так и было сделано, но потом для единообразия всё-таки добавили. Сейчас современные компиляторы будут выдавать предупреждения/ошибки, если вы не укажете тип возвращаемого значения.
В некоторых языках программирования функции, которые не возвращают никакого значения, называют процедурами (например, pascal). Более того, для создания функций и процедур предусмотрен различный синтаксис. В языке Си такой дискриминации нет.
После типа возвращаемого значения записывается имя функции. Ну а уж после имени указываются типы и количество аргументов, которые передаются в функцию.
Давайте посмотрим на заголовки уже знакомых нам функций.
Листинг 2.
// функция с именем srand, принимающая целое число, ничего не возвращает void srand(int) //функция с именем sqrt, принимающая вещественное число типа float, возвращает вещественное число типа float float sqrt(float) //функция с именем rand, которая не принимает аргументов, возвращает целое число int rand(void) //функция с именем pow, принимающая два аргумента типа double, возвращает вещественное число типа double double pow(double, double)
Как создать свою функцию
Для того чтобы создать свою функцию, необходимо её полностью описать. Тут действует общее правило: прежде чем использовать – объяви и опиши, как должно работать. Для этого вернёмся к схеме структуры программы на языке Си, которая у нас была в самом первом уроке. Отметим на ней те места, где можно описывать функции.
Рис.1 Уточнение структуры программы. Объявление функций.
Как видите, имеется аж два места, где это можно сделать.
Давайте посмотрим на пример, который иллюстрируют создание пользовательской функции вычисления максимального из двух чисел.
Листинг 3.
#include
Давайте я подробно опишу, как будет работать эта программа. Выполняется тело функции main . Создются целые переменные x , y и m . В переменные x и y считываются данные с клавиатуры. Допустим мы ввели 3 5 , тогда x = 3 , y = 5 . Это вам всё и так должно быть понятно. Теперь следующая строчка
Листинг 4.
M = max_num(x,y);
Переменной m надо присвоить то, что находится справа от знака = . Там у нас указано имя функции, которую мы создали сами. Компьютер ищет объявление и описание этой функции. Оно находится выше. Согласно этому объявлению данная функция должна принять два целочисленных значения. В нашем случае это значения, записанные в переменных x и y . Т.е. числа 3 и 5 . Обратите внимание, что в функцию передаются не сами переменные x и y , а только значения (два числа), которые в них хранятся. То, что на самом деле передаётся в функцию при её вызове в программе, называется фактическими параметрами функции.
Теперь начинает выполняться функция max_num . Первым делом для каждого параметра, описанного в заголовке функции, создается отдельная временная переменная. В нашем случае создаются две целочисленных переменных с именами a и b . Этим переменным присваиваются значения фактических параметров. Сами же параметры, описанные в заголовке функции, называются формальными параметрами. Итак, формальным параметрам a и b присваиваются значения фактических параметров 3 и 5 соответственно. Теперь a = 3 , b = 5 . Дальше внутри функции мы можем работать с этими переменными так, как будто они обычные переменные.
Создаётся целочисленная переменная с именем max , ей присваивается значение b . Дальше проверяется условие a > b . Если оно истинно, то значение в переменной max следует заменить на a .
Далее следует оператор return , который возвращает в вызывающую программу (функцию main ) значение, записанное в переменной max , т.е. 5 . После чего переменные a , b и max удаляются из памяти. А мы возвращаемся к строке
Листинг 5.
M = max_num(x,y);
Функция max_num вернула значение 5 , значит теперь справа от знака = записано 5 . Это значение записывается в переменную m. Дальше на экран выводится строчка, и программа завершается.
Внимательно прочитайте последние 4 абазаца ещё раз, чтобы до конца уяснить, как работает программа.
А я пока расскажу, зачем нужен нижний блок описания функций. Представьте себе, что в вашей программе вы написали 20 небольших функций. И все они описаны перед функцией main . Не очень-то удобно добираться до основной программы так долго. Чтобы решить эту проблему, функции можно описывать в нижнем блоке.
Но просто так перенести туда полностью код функции не удастся, т.к. тогда нарушится правило: прежде чем что-то использовать, необходимо это объявить. Чтобы избежать подобной проблемы, необходимо использовать прототип функции.
Прототип функции полностью повторяет заголовок функции, после которого стоит ; . Указав прототип в верхнем блоке, в нижнем мы уже можем полностью описать функцию. Для примера выше это могло бы выглядеть так:
Листинг 6.
#include
Всё очень просто. Обратите внимание, что у прототипа функции можно не указывать имена формальных параметров, достаточно просто указать их типы. В примере выше я именно так и сделал.