C Урок 33. Аргументы командной строки



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

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

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

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

До сих пор, когда нам не требовались входящие аргументы, наша функция mian() имела следующий заголовок

 

int main()

 

А чтобы функция main() увидела аргументы командной строки, то мы её объявлять должны уже с параметрами и её заголовок при этом будет выглядеть вот так

 

int main(int argc, char *argv[])

 

Также возможен ещё вот такой вариант

 

int main(int argc, char **argv)

 

В данном случае в первом аргументе будет содержаться количество переданных в командной строке параметров, а во втором — указатель на массив строк, в которых и содержатся данные параметры, а содержатся они там именно в символьном виде. Первый параметр, в котором содержится количество параметров, не может быть меньше 1, так как хотя бы один параметр всегда будет — это имя файла в том виде, в котором мы его вводим в командой строке. Следовательно, второй параметр также никогда не будет пустым.

Как именно пользоваться данными параметрами, мы лучше узнаем сразу в практической части, к которой сейчас и приступим.

Проект мы сделаем, как всегда, из проекта прошлого урока с именем MYPROG32 и присвоим ему имя MYPROG33.

Откроем наш проект в Eclipse, произведём его первоначальную настройку и удалим весь наш код из функции main() за исключением возврата. Функция main() приобретёт вот такой вид

 

int main()

{

   return 0; //Return an integer from a function

}

 

Соответственно, заголовок функции main() мы приведём к следующему виду, добавив в него аргументы

 

int main(int argc, char *argv[])

 

Удалим все глобальные структуры, в том числе и закомментированную.

Первым делом давайте выведем в консоль количество аргументов, переданных в нашу программу с помощью параметров командной строки

 

 

Соберём код и запустим нашу программу, не передавая ей пока никаких аргументов в командной строке

 

 

Как видим, параметров у нас 1, хотя мы ничего не передавали.

Далее с помощью цикла выведем в консоль содержимое наших параметров

 

 

Соберём код и посмотрим, что содержится в единственном аргументе командной строки

 

 

Мы видим, что у нас в аргументе находится не только имя исполняемого файла нашей программы вместе с расширением, а также и полный путь к нему. Это имеет место, когда мы программу запускаем из среды программирования. А если мы, как и раньше, зайдём в каталог с программой и запустим её с командной строки, введя её имя, то мы получим уже аргумент без пути к программе

 

 

Мы знаем также, что при вводе имени файла программы для запуска в командной строке, мы можем не писать расширение данного файла, а ввести только имя. При этом расширения также не будет и в параметре

 

 

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

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

 

 

Параметр Hello у нас теперь появился во второй строчке вывода в консоль и количество параметров у нас стало равным 2.

А давайте попробуем вот так

 

 

Так как у нас используется пробел, то всё, что после пробела, перешло в следующий параметр.

Это всё, конечно, пробные варианты, которые нам никакой пользы не приносят, точнее, нам-то они принесли, мы уже поняли, как вывести в консоль параметры командной строки, как их посчитать. А вот программе нашей это всё никакой пользы не принесло кроме лишней информации в консоли.

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

Для этого вернёмся к нашим студентам.

Создадим массив переменных структур наших студентов, добавим туда позиции и выведем их в консоль

 

 

Соберём наш код, а запускать мы его будем из консоли, причём пока без аргументов в строке запуска.

 

 

Не забываем, что для того, чтобы у нас отображалась кириллица (а кто смотрит урок из других неанглоязычных стран, то их кодовая страница), нам нужно сначала ввести в консоли вот такую вот команду

 

 

После этого мы смело можем запускать нашу программу, не боясь, что у нас будут отображаться непонятные символы

 

 

Что же мы будем использовать в качестве параметра для работы с нашими студентами?

А давайте мы будем в них искать определённую позицию. А поиск мы организуем по номеру позиции, по номеру курса и по возрасту студента.

Можно было бы также организовать поиск по части имени (ФИО) студента, но мы оставим это до лучших времён, когда будем плотно работать со строковыми функциями.

В первом параметре у нас будет информация о том, по какому критерию мы будем искать, а во втором — значение этого критерия.

Первым делом давайте организуем некую проверку на то, что пользователь ввёл параметры командной строки. Если это не так, то мы ему дадим подсказку, причём полную, какие нужны параметры и чего мы от них хотим добиться. Сделаем мы это даже перед тем, как будем объявлять и инициализировать массив студентов

 

 

Мы используем цифру 3 в условии, так как если будет количество аргументов 1, то это будет обозначать, что пользователь вообще ни вводил никаких параметров, если будет 2, то значит пользователь ввёл только один параметр. А нужно, чтобы пользователь ввёл именно 2 параметра, поэтому цифра должна быть равна не меньше 3. Если пользователь введёт лишние параметры, то это не страшно, они будут просто игнорироваться.

Теперь давайте соберём наш код и запустим нашу программу без аргументов

 

 

Мы получим только подсказку.

Такая же участь нас ждёт, если мы запустим программу только с одним аргументом

 

 

А вот если мы введём два параметра, то программа нас уже не выбросит

 

 

Немного усложним нашу проверку. Нам, кроме того, что мы должны проверить, вводил ли пользователь параметры вообще и сколько он их ввёл, надо проверить его на корректность ввода параметров.

Во первых, в первом аргументе вместе с дефисом должен быть только один символ, то есть общее количество символов должно быть 2. Поэтому добавим в условие проверки ещё одно условие, объединив его с пока единственным

 

if((argc<3) || (strlen(argv[1])>2))

 

Мы используем операцию ИЛИ потому, что программа должна не сработать, если будет выполнено хотя бы одно из этих условий.

Проверим, как это сработает, добавив ещё одну букву к первому вводимому аргументу

 

Всё сработало, мы дали пользователю подсказку.

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

 

if((argc<3) || (strlen(argv[1])>2) ||\

   ((argv[1][1] != 'p') && (argv[1][1] != 'c') && (argv[1][1] != 'a')))

 

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

Наши три условия мы уже объединяем с помощью операции И, так как программа должна нас не пустить дальше, если данные условия выполнятся все.

 

 

Проверим, введя неправильный символ, то есть не существующий в подсказке

 

 

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

 

if((argc<3) || (strlen(argv[1])>2) ||\

   ((argv[1][1] != 'p') && (argv[1][1] != 'c') && (argv[1][1] != 'a')) ||\

   (atoi(argv[2])==0))

 

Проверим, введя в качестве третьего параметра ноль и вообще не число

 

 

Всё срабатывает.

Теперь мы будем уверены в том, что пользователь не введёт чего-то такого, что наша программа потом не сможет обработать.

Теперь займёмся поиском позиции.

Первым делом выведем в консоль число, полученное во втором аргументе

 

 

Проверим

 

 

Всё выводится.

Обработаем пока самый простой вариант поиска — по номеру позиции

 

 

Ну тут всё просто, мы проверяем второй символ в первом параметре и если он p, то попадаем в условие, в котором проверяем, что позиция существует, сравнивая введённое значение с количеством позиций в массиве студентов. Если больше или равно, то выдаём соответствующее сообщение и выходим из программы, а если нет, то выводим найденную позицию в консоль.

Проверим, введя сначала число заведомо большее количеству позиций. Максимальный номер позиции у нас 7, так как они начинаются с нуля

 

 

Ограничение отлично сработало.

Введём существующий номер в аргументе

 

 

 

Позиция нашлась и благополучно вывелась в консоль.

Я думаю, у многих возникает вопрос, что в консоли работать нам сейчас при разработке программы не совсем удобно, так как постоянно требуется скакать то туда, то в среду. Хотя, в принципе, оно не так уж и сложно. Но вполне закономерный вопрос: а нельзя ли вводить параметры командной строки прямо в IDE?

Ответ положительный — конечно же можно!

Зайдём по контекстному меню в свойства проекта, в левой панели выберем пункт Run/Debug Settings, зайдём в редактирование нашей конфигурации, выделив её и нажав кнопку Edit, потом в открывшемся диалоге перейдём в закладку Arguments и введём там нужные параметры

 

 

Применим изменения и запустим нашу программу уже в IDE Eclipse

 

 

Всё отлично работает.

Теперь обработаем следующий вид аргумента — поиск по номеру курса. Здесь может быть отфильтровано несколько позиций, поэтому применяем цикл. Но зато здесь нам не надо проверять, сколько вообще у нас позиций

 

 

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

 

 

Введём существующий — -c 2

 

 

Мы получили список второкурсников.

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

 

 

Обработаем последний — третий вид аргумента командной строки — поиск по возрасту. Обработка аналогична предыдущей

 

 

Проверим, сначала введя возраст, с которым нет никого в нашем списке, например -a 19

 

 

Соответственно, в нашем списке ничего не нашлось, теперь исправим на -a 18

 

 

Фильтр отлично сработал.

Раз уж у нас последние два условия в нашей конструкции — поиск по курсу и по возрасту имеют очень похожий текст, то мы их можем объединить в одно, при этом код станет проще и читабельность его тоже особо не пострадает. И в данном случае вместо else if мы уже используем обычный else

 

 

Можно, конечно, объединить с этой веткой и первое условие, но тогда внутри него будет большее ветвление, так как в первом условии похожий код, но не настолько. В таком случае код наш, хоть и станет несколько меньше, но он потеряет читабельность. А это не есть хорошо.

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

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование на C Следующий урок

 

Исходный код

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

C Аргументы командной строки

2 комментария на “C Урок 33. Аргументы командной строки
  1. Александр:

    Мне кажется было бы здорово несколько уроков о Raspberry и С на нем.

  2. Дмитрий:

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*