На основании аргументов запуска, выполняет арифметические операции и выводит результат.
Пример выполнения:
./calc 10 x 5 result: 10 x 5 = 50 ./calc 10 / 5 result: 10 / 5 = 2 ./calc 10 + 5 result: 10 + 5 = 15 ./calc 10 - 5 result: 10 - 5 = 5
- Процесс обработки аргументов, которые передаем для запуска.
- Возвращение кода выхода в зависимости от успеха / неудачи.
- Арифметические операции с аргументами.
- Вывод результата.
calc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>stdio.h- необходимый для работы стандартного ввода/вывода, в нашем случае для функцииprintf(), которая нужна для вывода текста в терминале.stdlib.h- основной заголовок стандартной библиотеки языка C, в нашем случае используем от туда функциюatoi()для перевода строк в целые числа.string.h- заголовок для работы со строками, в нашем случае используем функциюstrcmp()для сравнения двух строк.
Когда мы вызываем программу то ей передаются следующие аргументы:
[0] -> имя_программы[1] -> аргумент #1 ?[2] -> аргумент #2 ?[n] -> аргумент #n ...
Аргумент #0 обязателен, он передается автоматически. Если мы вызываем программу так:
./calc 10то набор аргументов будет таким:
[0] -> ./calc[1] -> 10
итого всего 2 аргумента.
Передача аргументов происходит в функции main - входная точка в программу. Где происходит начальный запуск.
int main(int argc, char* argv[])Аргументы функции main:
int argc- количество переданных аргументов (1, 2, 3 и так далее)char* argv[]- значения аргументов, в виде списка строк.
Зная количество аргументов мы можем находить в списке нужный аргумент, не выходя за пределы.
Для программы нужно 4 аргумента, которые будут передаваться при запуске так:
./calc 10 x 5[0] -> обязательный, передается по умолчанию (calc)[1] -> левая цифра (10)[2] -> символ операции ( x, :, +, -)[3] -> правая цифра (5)
Поэтому нам нужно проверить, что аргументов именно 4, не больше ни меньше:
if(argc != 4)
{
printf("arguments fail, example:\n$ ./calc.out 10 * 10\n");
return 1;
}Если количество аргументов не равно 4, то мы пишем понятную ошибку для пользователя с помощью функции printf() , это сообщение поможет нам понять как правильно вызывать функцию с примером. Так как это ошибка при выполнении программы, мы делаем return 1 для выхода из программы, с кодом 1, который означает ошибку выполнения.
Когда мы запускаем программу нужно понимать как она завершилась, успешно или неудачно. Принято возвращать коды из функции main:
- при успехе делается
return 0 - при неудаче делается
return 1
Отслеживание кода возврата в терминале Отследить последний код возврата программы в терминале можно с помощью команды:
echo $?Эта команда покажет код выполнения последней вызванной программы.
Если с количеством аргументов все хорошо, то дальше сохраняем аргументы в переменные:
int result = -1;
int left = atoi(argv[1]);
int right = atoi(argv[3]);
char* operator = argv[2];Пояснения:
int result- переменная для хранения результата вычислений.int left- левая цифра, преобразуем строку в int с помощью функцииatoi().int right- правая цифра.char* operator- арифметический оператор, который располагается между цифрами, ожидается что он будет иметь одно из значений:x,:,+,-.
Далее проверяем что за оператор был введен, с помощью функции сравнения строк strcmp(), и, если найдено совпадение, делаем соответствующую операцию:
x- умножение.:- деление.+- сложение.-- вычитание.
Пример:
if(strcmp(operator, "x") == 0)
{
result = left * right;
}Если совпадения не найдено, то результат остается со значением -1 и выводим ошибку о неизвестном операторе и делаем выход из программы с ошибкой с помощью return 1:
if(result == -1)
{
printf("arguments fail, invalid operator '%s' , expected: [ x , : , +, - ]\n", operator);
return 1;
}В конце программы выводим результат вычислений и делаем успешный выход из программы return 0:
printf("result: %d %s %d = %d\n", left, operator, right, result);
return 0;hello_args
На основании аргументов запуска, выводим определенное сообщение.
Пример выполнения
./hello_args -h intfloatbool hello intfloatbool !!! ./hello_args -g intfloatbool greetings intfloatbool !!! ./hello_args -m intfloatbool mashala intfloatbool !!!
- проверка аргументов, с помощью функции
getopt() - вывод сообщения, в зависимости от аргументов.
hello_args.c
#include <stdio.h>
#include <unistd.h>- stdio.h - уже встречали, для вывода, функция
printf(). - unistd.h - предоставляет функции для работы с ОС, в нашем случае для функции
getopt()
В примере с калькулятором мы сравнивали аргументы, как обычные строки, с помощью функции strcmp(). Это не совсем удобно, тем-более что существует стандарт передачи аргументов, с помощью дефиса ``-arg```.
Обычно, программы в Unix, принимают аргументы в таком формате и на то есть причины. Существует набор функций стандартной библиотеки, которые упрощают нам обработку аргументов, переданных таким образом.
Одна из таких функций - getopt().
Функция принимает три параметра:
- количесвто аргументов (
int argc) - массив значений (
char* argv[]) - шаблон возможных аргументов, в виде строки (
abc)
Ключевое здесь - третий параметр функции, шаблон, по которому происходит поиск аргументов.
Если поиск по шаблону удался (есть такой аргумент) то мы можем обработать его.
То есть эта функция проводит поиск наличия аргументов за нас, нам лишь остается обработать случай, для каждого возможного аргумента.
while( ( opt = getopt( argc, argv, "hgm" ) ) != -1 )здесь происходит вся магия. Мы передали шаблон в виде строки "hgm", который можно описать так: проверить наличие аргумента -h или -g или -m.
Нетрудно заметить, что шаблон состоит как раз из этих трех символов, которые нас интересуют, в качестве аргументов. То есть наша программа работает с одним из аргументов: -h , -g или -m.
В зависимости от аргумента мы выводим сообщение и успешный код завершения return 0 , а в случае несовпадения (default) пишем ошибку и возвращаем код выполнения с неудачным результатом return 1 :
case 'h':
{
printf("hello %s !!!\n", name);
return 0;
}
case 'g':
{
printf("greetings %s !!!\n", name);
return 0;
}
case 'm':
{
printf("mashala %s !!!\n", name);
return 0;
}
default:
{
printf("invalid argument! Consider using: -h, -g, -m.\n");
return 1;
}handle_user_input
Принимает текст от пользователя и выводит определенный ответ, на основании входящего текста.
Пример выполнения
./handle_user_input hey # наш ввод, потом жмем enter your message: hey number representation: 104 101 121 yeh # наш ввод, потом жмем enter your message: yeh number representation: 121 101 104 intfloatbool # наш ввод, потом жмем enter Wow! You know the secret word! Congrats!
- считывание текста пользователя в программе.
- обработка специального слова
intfloatbool. - показ числового представления каждого символа.
- использование функции
exit().
handle_user_input.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>- stdio.h - обработка ввода/вывода , функциями
fgets()для ввода иprintf()для вывода. - string.h - работа со строками, сравнение функцией
strcmp()и поиск количества символов функциейstrcspn(). - stdlib.h - стандартная библиотека, выход из программы функцией
exit().
#define BUFF_SIZE 256Определив макрос BUFF_SIZE, мы можем его подставлять в коде, где нужно. Чтобы часто не писать магическое число 256, будем писать просто BUFF_SIZE. Компилятор подставит вместо BUFF_SIZE значение 256 сам.
Это довольно распространенная практика в системном программировании.
В нашем случае макрос BUFF_SIZE означает размер массива символов, в который будет записываться пользовательский ввод.
А что будет если сделать ввод в программу больше чем 256 символов ?
Ничего, просто ограничение на количество. Программа обрежет ваш ввод до 256 символов.
В системном программировании на C, мы должны знать пределы заранее!
int main(void)Обратим внимание, что у нас тут нет параметров argc и argv, так как они нам не нужны (программа работает без аргументов). Вместо этого просто указываем void, который означает что функция работает без параметров.
char secret_word[] = "intfloatbool";
char user_input[BUFF_SIZE];secret_wordэто наше секретное слово, мой никнейм -intfloatbool, введя которое, вы получите особое сообщение от программы.user_inputэто буфер, куда будет помещаться пользовательский ввод. Что пользователь ввел до256символов (макросBUFF_SIZE), то и попадет в этот буфер.
while( fgets( user_input, sizeof(user_input), stdin ) != NULL )Здесь мы вызываем функцию fgets(), которая считывает ввод пользователя, до нажатия enter .
Цикл while здесь для того, чтобы после первого ввода программа продолжала работать и принимать ввод. Пока мы явно ее не завершим, нажатием ctrl + D или ctrl + C.
user_input[ strcspn( user_input , "\n") ] = '\0';Когда пользовательский ввод помещается в строку user_input, в ней дополнительно будет символ переноса строки "\n" (что очевидно, мы ведь нажали enter !) , чтобы он не мешал нашим дальнейшим расчетам, заменяем его на символ конца строки - '\0'.
if( strcmp(user_input, secret_word) == 0 )
{
printf("Wow! You know the secret word! Congrats! \n");
exit(0);
}Сравниваем строку ввода со строкой secret_word с помощью функции strcmp(). Если совпадение найдено, то пишем сообщение с поздравлением и выходим из программы с помощью функции exit(), передав ей 0 как успешное завершение!
for(int i = 0; i < sizeof(user_input); i++)
{
char c = user_input[i];
if(c == '\0')
{
break;
}
printf("%d ", user_input[i]);
}Строка состоит из символов, поэтому строка это массив символов char str[]. Символ это всего-лишь число от -128 до 127 что дает нам в сумме 255 уникальных символов.
С помощью цикла for выводим цифровое значение кажого символа из ввода пользователя, проверяя символ на конец строки '\0', чтобы успешно завершить цикл (ведь строка закончилась) оператором break.