Как исключить аргументы, переданные из командной строки argc argv в C?

Мне нужно добавить дроби, заданные пользователем через командную строку в формате

a/b b/c

Я думал, что могу сделать это следующим образом:

n1 = atoi(argv[1]);
d1 = atoi(argv[3]);
n2 = atoi(argv[4]);
d2 = atoi(argv[6]);

Тем самым пропуская косые черты, но это просто вылетает из программы. Есть ли способ пропустить определенные символы, переданные в качестве аргументов через командную строку? Заранее спасибо.


person supersaidso    schedule 12.11.2013    source источник


Ответы (2)


Если пользователь пишет:

add_fractions 1/2 2/3

то вашей программе дается всего 3 аргумента:

argv[0] = "add_fractions"
argv[1] = "1/2"
argv[2] = "2/3"
argv[3] = 0

и argc равно 3.

Вам нужно будет сделать что-то вроде этого (после проверки того, что вам были даны 2 аргумента):

char *ptr;
n1 = atoi(argv[1]);
if ((ptr = strchr(argv[1], '/') != 0)
    d1 = atoi(ptr+1);
else
    d1 = 1;
n2 = atoi(argv[2]);
if ((ptr = strchr(argv[2], '/') != 0)
    d2 = atoi(ptr+1);
else
    d2 = 1;

Или вы можете упаковать повторяющуюся последовательность операторов в функцию (с немного другим поворотом логики):

void read_fraction(char const *str, int *num, int *den)
{
    char *ptr;
    *num = atoi(str);
    if ((ptr = strchr(str, '/') == 0)
        ptr = "/1";
    *den = atoi(ptr+1);
}

и в main():

read_fraction(argv[1], &n1, &d1);
read_fraction(argv[2], &n2, &d2);

Возможно, вы захотите подумать о проверке; числитель становится равным 0, если в первой части строки нет числа, но знаменатель становится равным 0, если есть косая черта и после косой черты нет числа, что может быть не совсем то, что вы хотите. Одно исправление состоит в том, чтобы установить знаменатель на 1, если значение из atoi(ptr+1) равно 0. Это отговорка, но предотвращает безудержные сбои. Или вы можете использовать другую совершенно другую реализацию в теле функции:

int read_fraction(char const *str, int *num, int *den)
{
    if (sscanf(str, "%d/%d", num, den) != 2)
        return -1;
    return 0;
}

А затем проверьте main():

if (read_fraction(argv[1], &n1, &d1) == 0 &&
    read_fraction(argv[2], &n2, &d2) == 0)
    ...process valid fractions...
else
    ...make appropriate comments about how to use the program...

Использование функции «лучше» с нескольких точек зрения. В Программист-прагматик это называется СУХИМ принципом: не повторяй Самим собой.

Керниган и Плаугер аккуратно описали это в своей книге Элементы стиля программирования:

  • Вызов подпрограммы позволяет нам суммировать несоответствия в списке аргументов, где мы можем быстро увидеть, что происходит.
  • Сама подпрограмма суммирует закономерности кода, поэтому нет необходимости использовать повторяющиеся шаблоны.
person Jonathan Leffler    schedule 12.11.2013
comment
+1, но не могли бы вы объяснить, что вы подразумеваете под альтернативой упаковать последовательность в функцию. - person legends2k; 12.11.2013
comment
@legends2k: см. обновление. - person Jonathan Leffler; 12.11.2013
comment
Спасибо за обновления. Разве не следует распаковывать последовательность в функции? - person legends2k; 12.11.2013
comment
Я имею в виду «упаковать повторяющуюся последовательность операторов N в функцию», поэтому правильным глаголом будет «упаковать» (выписывание кода дважды, как в оригинале, будет его распаковкой). Если вы считаете, что это «распаковать строку аргумента в функции», то «распаковать» становится правильным глаголом. - person Jonathan Leffler; 12.11.2013
comment
Первый касается кода, а второй — данных; теперь понял, спасибо! :) - person legends2k; 12.11.2013
comment
Используйте %d/%d%c с sscanf и убедитесь, что результат равен 2; это гарантирует, что в значении нет следующего мусора… - person Donal Fellows; 17.11.2013

a/b b/c

Он просто создает 2 записи в списке аргументов, одна a/b, а другая b/c.

Итак, argv[0], argv[1] и argv[2] действительны, а argc равно 3.

Пробелы важны для разделения аргументов (если вы не заключаете запись в "")

person masoud    schedule 12.11.2013