Параметры функции main (argc, argv). Пользовательские функции в си

Эти обучающие уроки предназначены для всех, независимо от того, новичок вы в программировании или у вас уже есть обширный опыт программирования на других языках! Данный материал для тех, кто хочет изучить языки С/С++ от самых его основ до сложнейших конструкций.

C++ является языком программирования, знание этого языка программирования позволит вам управлять вашим компьютером на высшем уровне. В идеале вы сможете заставить компьютер сделать всё, что сами захотите. Наш сайт поможет вам в освоении языка программирования C++.

Установка /IDE

Самое первое, что вы должны сделать, прежде чем приступить к изучении C++, это убедиться, что у вас есть IDE — интегрированная среда разработки (программа в которой вы будете программировать). Если у вас нет IDE, тогда вам сюда . Когда определитесь с выбором IDE, установите её и потренируйтесь создавать простые проекты.

Введение в язык C++

Язык C++ представляет собой набор команд, которые говорят компьютеру, что необходимо сделать. Этот набор команд, обычно называется исходный код или просто код. Командами являются или «функции» или «ключевые слова». Ключевые слова(зарезервированные слова С/С++) являются основными строительными блоками языка. Функции являются сложными строительными блоками, так как записаны они в терминах более простых функций — вы это увидите в нашей самой первой программе, которая показана ниже. Такая структура функций напоминает содержание книги. Содержание может показывать главы книги, каждая глава в книге может иметь своё собственное содержание, состоящее из пунктов, каждый пункт может иметь свои подпункты. Хотя C++ предоставляет много общих функций и зарезервированных слов, которые вы можете использовать, все-таки возникает потребность в написании своих собственных функций.

В какой же части программы начало? Каждая программа в C++ имеет одну функцию, её называют главная или main-функция, выполнение программы начинается именно с этой функции. Из главной функции, вы также можете вызывать любые другие функции, неважно, являются ли они написанными нами, или, как упоминалось ранее, предоставляются компилятором.

Так как же получить доступ к этим Стандартным функциям? Чтобы получить доступ к стандартным функциям, которые поставляются с компилятором, необходимо подключить заголовочный файл используя препроцессорную директиву — #include . Почему это эффективно? Давайте посмотрим на примере рабочей программы:

#include << "Моя первая программа на С++\n"; cin.get(); }

Рассмотрим подробно элементы программы. #include это директива «препроцессору», которая сообщает компилятору поместить код из заголовочного файла iostream в нашу программу перед тем как создать исполняемый файл. Подключив к программе заголовочный файл вы получаете доступ к множеству различных функций, которые можете использовать в своей программе. Например, оператору сout требуется iostream . Строка using namespace std; сообщает компилятору, что нужно использовать группу функций, которые являются частью стандартной библиотеки std . В том числе эта строка позволяет программе использовать операторы, такие как cout . Точка с запятой является частью синтаксиса C++. Она сообщает компилятору, что это конец команды. Чуть позже вы увидите, что точка с запятой используется для завершения большинства команд в C++.

Следующая важная строка программы int main() . Эта строка сообщает компилятору, что есть функция с именем main , и что функция возвращает целое число типа int . Фигурные скобки { и } сигнализируют о начале { и конце } функции. Фигурные скобки используются и в других блоках кода, но обозначают всегда одно — начало и конец блока, соответственно.

В C++ объект cout используется для отображения текста (произносится как «Cи аут»). Он использует символы << , известные как «оператор сдвига», чтобы указать, что отправляется к выводу на экран. Результатом вызова функции cout << является отображение текста на экране. Последовательность \n фактически рассматривается как единый символ, который обозначает новую строку (мы поговорим об этом позже более подробно). Символ \n перемещает курсор на экране на следующую строку. Опять же, обратите внимание на точку с запятой, её добавляют в конец, после каждого оператора С++.

Следующая команда cin.get() . Это еще один вызов функции, которая считывает данные из входного потока данных и ожидает нажатия клавиши ENTER. Эта команда сохраняет консольное окно от закрытия, до тех пор пока не будет нажата клавиша ENTER. Это даёт вам время для того, чтобы посмотреть результат выполнения программы.

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

#include using namespace std; int main() { cout<<"Моя первая программа на С++\n"; cin.get(); return 1; }

Для закрепления материала, наберите код программы в своей IDE и запустите его. После того, как программа запустилась, и вы увидели результат работы, поэкспериментируйте немного с оператором cout . Это поможет вам привыкнуть к языку.

Обязательно комментируйте свои программы!

Добавляйте комментарии к коду, чтобы сделать его понятнее не только для себя но и для других. Компилятор игнорирует комментарии при выполнении кода, что позволяет использовать любое количество комментариев, чтобы описать реальный код. Чтобы создать комментарий используйте или // , который сообщает компилятору, что остальная часть строки является комментарием или /* и затем */ . Когда вы учитесь программировать, полезно иметь возможность комментировать некоторые участки кода, для того, чтобы увидеть, как изменяется результат работы программы. Подробно прочитать о технике комментирования, вы можете .

Что делать со всеми этими типами переменных?

Иногда это может сбить с толку — иметь несколько типов переменных, когда кажется, что некоторые типы переменных являются избыточными. Очень важно использовать правильный тип переменной, так как некоторым переменным, требуется больше памяти, чем другим. Кроме того, из-за способа хранения в памяти, числа с плавающей точкой, типы данных float и double являются «неточным», и не должны использоваться, когда необходимо сохранить точное целое значение.

Объявление переменных в C++

Чтобы объявить переменную используется синтаксис тип <имя>; . Вот некоторые примеры объявления переменных:

Int num; char character; float num_float;

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

Int x, y, z, d;

Если вы смотрели внимательно, вы, возможно, видели, что объявление переменной всегда сопровождается точкой с запятой. Подробнее о соглашении — «об именовании переменных», можно .

Распространенные ошибки при объявлении переменных в C++

Если вы попытаетесь использовать переменную, которую не объявили, ваша программа не будет скомпилирована, и вы получите сообщение об ошибке. В C++, все ключевые слова языка, все функции и все переменные чувствительны к регистру.

Использование переменных

Итак, теперь вы знаете, как объявить переменную. Вот пример программы, демонстрирующий использование переменной:

#include using namespace std; int main() { int number; cout << "Введите число: "; cin >> number; cin.ignore(); cout << "Вы ввели: "<< number <<"\n"; cin.get(); }

Давайте рассмотрим эту программу и изучим её код, строку за строкой. Ключевое слово int говорит о том, что number — целое число. Функция cin >> считывает значение в number , пользователь должен нажать ввод после введенного числа. cin.ignore () — функция, которая считывает символ и игнорирует его. Мы организовали свой ввод в программу, после ввода числа, мы нажимаем клавишу ENTER, символ который также передаётся в поток ввода. Нам это не нужно, поэтому мы его отбрасываем. Имейте в виду, что переменная была объявлена целого типа, если пользователь попытается ввести десятичное число, то оно будет обрезано (то есть десятичная часть числа будет игнорироваться). Попробуйте ввести десятичное число или последовательность символов, когда вы запустите пример программы, ответ будет зависеть от входного значения.

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

Изменение и сравнение величин

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

  • * умножение,
  • - вычитание,
  • + сложение,
  • / деление,
  • = присвоение,
  • == равенство,
  • > больше,
  • < меньше.
  • != неравно
  • >= больше или равно
  • <= меньше или равно

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

Вот несколько примеров:

A = 4 * 6; // использование строчного комментария и точки с запятой, a равно 24 a = a + 5; // равно сумме исходного значения и пяти a == 5 // не присваивается пять, выполняется проверка, а равно 5 или нет

Вы часто будете использовать == в таких конструкциях, как условные операторы и циклы.

A < 5 // Проверка, a менее пяти? a > 5 // Проверка, a больше пяти? a == 5 // Проверка, a равно пяти? a != 5 // Проверка, а неравно пяти? a >= 5 // Проверка, a больше или равно пяти? a <= 5 // Проверка, a меньше или равно пяти?

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

9 ответов

Некоторые из функций языка C начинаются как хаки, которые только что сработали.

Одной из этих функций является несколько подписей для основного, а также списков аргументов переменной длины.

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

Это так, если вызывающие соглашения таковы, что:

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

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

;; pseudo-assembly-language ;; main(argc, argv, envp); call push envp ;; rightmost argument push argv ;; push argc ;; leftmost argument ends up on top of stack call main pop ;; caller cleans up pop pop

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

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

/* I"m adding envp to show that even a popular platform-specific variant can be handled. */ extern int main(int argc, char **argv, char **envp); void __start(void) { /* This is the real startup function for the executable. It performs a bunch of library initialization. */ /* ... */ /* And then: */ exit(main(argc_from_somewhere, argv_from_somewhere, envp_from_somewhere)); }

Другими словами, этот начальный модуль всегда вызывает основной аргумент с тремя аргументами. Если main не принимает никаких аргументов или только int, char ** , он работает нормально, а также если он не принимает никаких аргументов из-за соглашений о вызовах.

Если бы вы делали такие вещи в своей программе, это было бы непереносимо и считалось бы поведением undefined по ISO C: объявлением и вызовом функции одним способом и определением ее в другой. Но трюк запуска компилятора не должен быть переносимым; он не руководствуется правилами для переносных программ.

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

То есть вы пишете это:

Int main(void) { /* ... */ }

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

Int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore) { /* ... */ }

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

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

Компиляторы для языка C99 всегда должны в некоторой степени относиться к main , чтобы поддерживать хак, что если функция завершается без оператора return , поведение выглядит так, как если бы выполнялось return 0 . Это, опять же, можно рассматривать с помощью преобразования кода. Компилятор замечает, что скомпилирована функция с именем main . Затем он проверяет, может ли конец тела потенциально достижим. Если это так, он вставляет return 0;

Нет никакой перегрузки main даже в С++. Основная функция - это точка входа для программы, и должно существовать только одно определение.

Для стандартного C

Для размещенной среды (обычной), стандарт C99 говорит:

5.1.2.2.1 Запуск программы

Функция, вызванная при запуске программы, называется main . Реализация не объявляет прототипа для этой функции. Это должно быть определенный с типом возврата int и без параметров:

Int main(void) { /* ... */ }

или с двумя параметрами (называемыми здесь argc и argv , хотя любые имена могут использоваться, поскольку они являются локальными для функции, в которой они объявляются):

Int main(int argc, char *argv) { /* ... */ }

или эквивалент; 9) или каким-либо другим способом реализации.

9) Таким образом, int можно заменить на имя typedef, определенное как int , или тип argv можно записать как char **argv , и и так далее.

Для стандартного С++:

3.6.1 Основная функция

1 Программа должна содержать глобальную функцию main, которая является назначенным началом программы. [...]

2 Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена . Он должен имеют тип возвращаемого типа int, но в противном случае его тип определяется реализацией. Все реализации должны допускать оба следующих определения main:

Int main() { /* ... */ }

Int main(int argc, char* argv) { /* ... */ }

В стандарте С++ явно говорится: "Он [основная функция] должен иметь тип возвращаемого типа int, но в противном случае его тип определяется реализацией" и требует тех же двух сигнатур, что и стандарт C.

В размещенной среде (среда C, которая также поддерживает библиотеки C) - операционная система вызывает main .

В не-размещенной среде (один предназначен для встроенных приложений) вы всегда можете изменить точку входа (или выйти) вашей программы, используя директивы предварительного процессора, такие как

#pragma startup #pragma exit

Если приоритет является необязательным интегральным числом.

Запуск Pragma выполняет функцию перед тем, как основной (приоритетный) и выход прагмы выполняет функцию после основной функции. Если существует более одной директивы запуска, приоритет определяет, что будет выполняться первым.

Это одна из странных асимметрий и специальных правил языка C и С++.

По-моему, он существует только по историческим причинам, и нет реальной серьезной логики. Обратите внимание, что main является особенным также по другим причинам (например, main в С++ не может быть рекурсивным, и вы не можете взять его адрес, а на C99/С++ вы можете опустить окончательный оператор return).

Обратите внимание, что даже в С++ это не перегрузка... либо программа имеет первую форму, либо имеет вторую форму; он не может иметь обоих.

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

main - пользовательская функция; реализация не объявляет прототип для него.

То же самое верно для foo или bar , но вы можете определять функции с этими именами так, как вам нравится.

Различие заключается в том, что main вызывается реализацией (среда выполнения), а не только вашим собственным кодом. Реализация не ограничивается обычной семантикой вызова функции C, поэтому она может (и должна) иметь дело с несколькими вариантами, но не требует обработки бесконечно многих возможностей. Форма int main(int argc, char *argv) допускает аргументы командной строки, а int main(void) в C или int main() в С++ - это просто удобство для простых программ, которые не требуют обработки аргументов командной строки.

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

И, как и многие другие на C и С++, детали в значительной степени являются результатом истории и произвольных решений, сделанных разработчиками языков и их предшественников.

Обратите внимание, что оба C и С++ допускают другие определения, определенные для реализации для main , но редко есть веские основания для их использования. А для автономных реализаций (таких как встроенные системы без ОС) точка входа в программу определяется реализацией и необязательно даже называется main .

main - это просто имя для начального адреса, решенного компоновщиком, где main - имя по умолчанию. Все имена функций в программе - это начальные адреса, где начинается функция.

Возможности языков семейства Си по истине безграничны, однако, в этой свободе кроются и недостатки: всегда нужно программисту держать ухо востро и контроллировать "переполнение буфера", чтобы потом программа не вылетала в "синий экран" на массе разнообразных версий Windows и железа у пользователей. Те же крэкеры и реверсеры специально ищут в коде программ на Си уязвимости, куда можно подсадить любой вирусный код, об этом более подробно автор рассказывал в своём видеокурсе . Я там многое узнал и теперь мой код стал значительно более безопасный.

Функция 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 #include void main(int argc, char *argv, char *env) { int i; printf("Значение argc равно %d \n\n",argc); printf("В командной строке содержится %d параметров \n\n",argc); for (i=0; i<=argc; i++) printf(" argv[%d]: %s\n",i,argv[i]); printf("Среда содержит следующие строки:\n"); for (i=0; env[i] != NULL; i++) printf(" env[%d]: %s\n",i,env[i]); return 0; } Предположим, что вы запускаете программу ARGS.EXE со следующей командной строкой: C:> args first_arg "arg with blanks" 3 4 "last but one" stop! Заметим, что вы можете послать аргумент с пробелами, заключив его в двойные кавычки, как показано на примере "argument with blanks" и "last but one" в примере вызова программы. В результате работы программы вы получите примерно следующее: Значение argc равно 7 В командной строке содержится 7 параметров argv: c:\turboc\testargs.exe argv: first_arg argv: arg with blank argv: 3 argv: 4 argv: last but one argv: stop! Среда содержит следующие строки: env: COMSPEC=C:\COMMAND.COM env: PROMPT=$p $g env: PATH=C:\SPRINT;C:\DOS;C:\BC Максимальная общая длина командной строки, посылаемая функции main (включая пробелы и имя самой программы), не может превышать 128 символов; это ограничения DOS. Символы маскирования в командной строке Аргументы командной строки могут содержать символы маскирования. При этом они могут расширяться для всех имен файлов, которые совпадают с аргументом так, как это делается, например, с командой DOS copy. Для использования символов маскирования необходимо при связывании вашей программы редактором связей подсоединить к ней объектный файл WILDARGS.OBJ, который поставляется с Borland C++. Если файл WILDARGS.OBJ подсоединен к вашей программе, то вы можете в командной строке использовать аргументы типа "*.*". При этом имена всех файлов, подходящих к данной маске, заносятся в массив argv. Максимальный размер массива argv зависит только от объема динамической области памяти. Если под данную маску не нашлось подходящих файлов, то аргумент передается в том виде, в каком он был набран в командной строке. (Т.е. функции main передается строка, содержащая символы маскирования). Аргументы, заключенные в двойные кавычки ("..."), не расширяются. Пример. Следующие команды компилируют файл ARGS.C и связывают его с модулем WILDARGS.OBJ, а затем запускают получившуюся программу ARGS.EXE: bcc args wildarg.obj args C:\BORLANDC\INCLUDE\*.H "*.C" При запуске ARGS.EXE первый аргумент расширяется до имен всех файлов с расширением H в директории Borland C++ INCLUDE. Отметим, что все строки включают полный маршрут (к примеру C:\TC\INCLUDE\ALLOC.H). Аргумент *.C не расширяется, т.к. он заключен в кавычки. Если вы работаете в Интегрированном Окружении (BC.EXE), то вам просто нужно указать в меню проекта имя файла проекта, который должен содержать следующие строки: ARGS WILDARGS.OBJ Затем с помощью команд "Run/Arguments" следует установить параметры командной строки. Замечание. Если вы хотите, чтобы обработка символов маскирования происходила всегда, т.е. чтобы WILDARGS.OBJ автоматически подсоединялся редактором связей, вы должны модифицировать вашу стандартную библиотеку C?.LIB, добавив в нее файл WILDARGS.OBJ. Для этого удалите из библиотеки SETARGV и добавьте WILDARGS. Это можно сделать с помощью следующих команд (мы подразумеваем, что стандартные библиотеки и WILDARGS.OBJ содержатся в текущей директории): TLIB описана в главе 7 "Утилиты" документа "User"s Guide". tlib cs -setargv +wildargs tlib cc -setargv +wildargs tlib cm -setargv +wildargs tlib cl -setargv +wildargs tlib ch -setargv +wildargs Компиляция с использованием ключа -p (Соглашение по вызову языка Паскаль). Если вы компилируете вашу программу, используя соглашение по вызову языка Паскаль (детально описано в главе 9 "Interfacing with assembly languige", "Programmer"s Guide"), вы должны помнить, что функция main должна быть явно объявлена как функция С. Это можно сделать с помощью ключевого слова cdecl примерно так: cdecl main(int argc, char *argv, char *env) Значение, возвращаемое функцией main. Функция main возвращает значение, которое является кодом завершения программы: это целое. Однако, если ваша программа для завершения использует функцию exit (или _exit), то возвращаемым значением будет аргумент этой функции. Например, если ваша программа содержит вызов: exit(1) то код завершения будет равен 1. Если для запуска программы вы используете интегрированное окружение Borland C++ (BC.EXE), то посмотреть возвращаемое значение функции main вы можете, выбрав "File | Get Info".

Страница 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-файла.