Передача аргументов в программу. Параметры функции main языка C
Бывает, что данные в программу передаются из командной строки при ее вызове. Такие данные называются аргументами командной строки. Выглядит это так, например:
./a.out test.txt ls -lt /home/peter/
Здесь вызываются программы a.out (из текущего каталога) и ls (из одного каталога, указанного в переменной окружения PATH
). Первая программа из командной строки получает одно слово — test.txt, вторая — два: -lt и /home/peter/.
Если программа написана на языке C, то при ее запуске управление сразу передается в функцию main
, следовательно, именно она получает аргументы командной строки, которые присваиваются ее переменным-параметрам.
До этого мы определяли функцию main
так, как-будто она не принимает никакие аргументы, далее будет показано, как определить заголовок функции иначе.
При вызове программы из командной строки в нее всегда передается пара данных:
- целое число, обозначающее количество слов (элементов, разделенных пробелами) в командной строке при вызове,
- указатель на массив строк, где каждая строка — это отдельное слово из командной строки.
Само имя программы также считается. Например, если вызов выглядит так:
./a.out 12 theme 2
, то первый аргумент программы имеет значение 4, а массив строк определяется как {"./a.out", "12", "theme", "2"}.
Обратите внимание на терминологию, есть всего два аргумента программы (число и массив), но сколько угодно аргументов командной строки. Аргументы командной строки "преобразуются" в аргументы программы (в аргументы функции main()
).
Эти данные (число и указатель) передаются в программу даже тогда, когда она просто вызывается по имени без передачи в нее чего-либо: ./a.out
. В таком случае первый аргумент имеет значение 1, а второй указывает на массив, состоящий всего из одной строки {"./a.out"}.
То, что в программу передаются данные, вовсе не означает, что функция main()
должна их принимать. Если она определена без параметров, то получить доступ к аргументам командной строки невозможно. Хотя ничего вам не мешает их передавать. Ошибки не возникнет.
Чтобы получить доступ к переданным в программу данным, их необходимо присвоить переменным. Поскольку аргументы сразу передаются в main()
, то ее заголовок должен выглядеть примерно так:
int main(int n, char *arr[])
В первой переменной содержится количество слов, а во второй ‒ указатель на массив строк. Часто второй параметр записывают в виде **arr
. Однако это то же самое. Вспомним, что сам массив строк, содержит в качестве своих элементов указатели на строки. В функцию мы передаем указатель на первый элемент массива. Получается, что передаем указатель на указатель, то есть **arr
.
Программа ниже выводит количество слов в командной строке при вызове, а также каждое слово с новой строки.
#include <stdio.h> int main(int argc, char **argv) { printf("%d\n", argc); for (int i = 0; i < argc; i++) puts(argv[i]); }
Примеры вызовов:
pl@desk:~$ ./a.out 1 ./a.out pl@desk:~$ ./a.out -u 120 "hello" 4 ./a.out -u 120 hello
В программе мы использовали переменные-параметры argc и argv. Принято использовать именно такие имена, но на самом деле они могут быть любыми. Лучше придерживаться этого стандарта, чтобы ваши программы были более понятны не только вам, но и другим программистам.
Практическое значение передачи данных в программу
Если у вас есть опыт работы в командной строке GNU/Linux, вы знаете, что у большинства команд есть ключи и аргументы. Например, при просмотре содержимого каталогов, копировании, перемещении в качестве аргументов указываются объекты файловой системы, над которыми выполняется команда. Особенности ее выполнения определяются с помощью ключей. Например, в команде
cp -r ../les_1 ../les_101
cp
— это имя команды, -r
— ключ, а ../les_1 и ../les_101 — аргументы команды.
Нередко в программы при их запуске передаются адреса файлов и "модификаторы" (это ключи) процесса выполнения программы.
Напишем программу, которая открывает указанные пользователем в командной строке файлы на запись или добавление и записывает (добавляет) туда одну и туже информацию, которую пользователь вводит с клавиатуры в процессе выполнения программы:
#include <stdio.h> #include <string.h> int main(int argc, char **argv) { int i, ch; FILE *f[5]; if (argc < 3 || argc > 7) { puts("Неверное количество параметров"); return 1; } if (strcmp(argv[1], "-w") != 0 && strcmp(argv[1], "-a") != 0) { puts("Первый параметр -w или -a"); return 2; } for (i = 0; i < argc-2; i++){ f[i] = fopen(argv[i+2], argv[1]+1); if (f[i] == NULL) { printf("Файл %s нельзя открыть\n", argv[i+2]); return 3; } } while ((ch = getchar()) != EOF) for (i = 0; i < argc-2; i++) putc(ch, f[i]); for (i = 0; i < argc-2; i++) fclose(f[i]); return 0; }
Пояснения к коду:
- Создается массив из пяти файловых указателей. Следовательно можно одновременно открыть не более пяти файлов. Файловый указатель первого файла будет хранится в элементе массива
f[0]
, второго — вf[1]
и т.д. - Проверяется количество аргументов командной строки. Их должно быть не меньше трех, т. к. первый — это имя программы, второй — режим открытия файла, третий — первый или единственный файл, в который будет производится запись. Поскольку программа позволяет открыть только пять файлов, то общее число аргументов командной строки не может быть больше семи. Поэтому если количество аргументов меньше 3 или больше 7, то программа завершается, т. к. оператор
return
приводит к выходу из функции, даже если после него есть еще код. Возвращаемое из функции значение неравное 0, может быть интерпретировано родительским процессом, как сообщение о том, что программа завершилась с ошибкой. - Проверяется корректность второго аргумента командной строки. Если он не равен ни "-w", ни "-a", то условное выражение во втором
if
возвращает 1 (true). Функцияstrcmp()
позволяет сравнивать строки и возвращает 0 в случае их равенства. - В цикле
for
открываются файлы по указанным адресам, которые начинаются с третьего элемента массива argv. Именно поэтому к i прибавляется 2, чтобы получать элементы массива argv, начиная с третьего. Выражениеargc-2
указывает на количество переданных имен файлов; т.к. в argc хранится общее число аргументов командной строки, первые два из которых не являются именами файлов. - Выражение
argv[1]+1
позволяет "вырезать" из строки "-w" (или "-a") подстроку "w" (или "a"), т. к.argv[1]
по сути указатель на первый элемент строки. Прибавляя к указателю единицу, мы смещаем его к следующему элементу массива. - Если файл отрыть не удается, то функция
fopen()
возвращаетNULL
. В таком случае программа завершается. - Каждый символ, введенный пользователем с клавиатуры, записывается во все открытые файлы.
- В конце файлы закрываются.
Курс с решением задач:
pdf-версия