Язык Си в примерах/Таблица умножения: различия между версиями
Содержимое удалено Содержимое добавлено
DannyS712 (обсуждение | вклад) м <source> -> <syntaxhighlight> (phab:T237267) |
|||
Строка 12:
{{Якорь |multable.c}}
<
#include <assert.h>
#include <limits.h>
Строка 46:
return 0;
}
</syntaxhighlight>
Примета работы программы (построение таблицы умножения для <var >n</var> = 5):
Строка 82:
Телом ''цикла строк'' должна стать, очевидно, некая процедура вывода заданной строки, которую мы вновь оформляем как цикл — использующий уже новую переменную <var >j</var>:
<
long j;
for (j = 1; j <= n; j++) {
Строка 88:
}
putchar ('\n');
</syntaxhighlight>
{{Якорь |%*}}
Строка 111:
{{Якорь |ceil |log}}
В итоговом выражении — <
Ясно, что данное выражение теряет смысл при <var >n</var> < 0. Кроме того, при <var >n</var> = 0, реализованные нами циклы вычисления—вывода сформируют ''пустой'' результат, который также <em >можно</em> считать ошибочным. Чтобы этого избежать, перед вычислением искомого выражения мы ''требуем'' (макроподстановкой <code >assert</code><ref name="assert" />) выполнения условия <
Здесь же мы требуем, чтобы значение <var >n</var> не превышало квадратного корня из максимального допустимого значения для используемого нами типа <code >long</code> (макроподстановка <var >LONG_MAX</var> — ''объявлена'' в ''заголовке'' <code >limits.h</code> ''стандартной библиотеки''.) В противном случае, один или более из результатов умножения может ''переполнить'' разрядность данного типа. (Отметим, впрочем, что формирование таблицы умножения теряет практический смысл уже при много меньших значениях <var >n</var>.)
Строка 121:
Наконец, рассмотрим получение в программе переданного как аргумент командной строки значения <var >n</var>.
<
assert (argc - 1 == 1);
long n;
Строка 130:
assert (*tail == '\0');
}
</syntaxhighlight>
Данный фрагмент кода начинается ''требованием'' (макроподстановкой <code >assert</code><ref name="assert" />) наличия ''единственного'' аргумента командной строки. Здесь следует отметить, что переменная <var >argc</var> отражает общую длину массива <var >argv</var>, в который входит — нулевым элементом — имя самой программы: <code ><var >argv</var>[0]</code>. Тем самым, условие наличия и единственности аргумента может быть записано как <code ><var >argc</var> == 2</code> — или же как приведено в коде.
В свою очередь, переменные <var >argc</var> и <var >argv</var> являются аргументами главной функции <code >main</code>, при ''объявлении'' ее следующим образом:<ref name="startup" />
<
int
main (int argc, char *argv[])
</syntaxhighlight>
{{Якорь |strtol}}
Строка 158:
''Областью видимости'' (англ. {{lang |en|scope}}) переменной (или ''идентификатора'' в общем) как правило оказывается часть содержащего переменную блока — от точки определения и до закрытия этого блока. Однако, вложенные блоки могут ''скрывать'' переменные вышестоящих блоков, объявляя свои собственные переменные с теми же именами. Так, например, функция <code >foo</code> в следующем примере выведет на стандартный вывод код перевода строки (из переменной <var >a</var> внутреннего блока) и ''вернет'' значение 1 (из одноименной переменной внешнего):
<
static int
foo (void)
Строка 170:
return a;
}
</syntaxhighlight>
Хорошей практикой представляется определение переменных так, чтобы область их видимости была <em >не большей</em>, чем строго необходимо. (Но не в ущерб ясности кода.) В этом случае, при перемещении (копировании) кода, случайное использование переменной там, где она не имеет смысла, с большей вероятностью будет диагностировано непосредственно реализацией языка.
Строка 179:
{{Якорь |multablex.c}}
<
#include <assert.h>
#include <ctype.h>
Строка 230:
return 0;
}
</syntaxhighlight>
Пример работы программы (построение таблицы умножения для <var >n</var> = 5 в шестнадцатиричном представлении):
Строка 242:
По сравнению с [[#multable.c |исходным вариантом]], пример дополнился следующим фрагментом кода:
<
char *p = strchr (argv[1], '0');
if (p == 0
Строка 255:
fmt = " %*lo";
}
</syntaxhighlight>
Кроме того, две из исходных ''констант'' (<code >10</code> при [[#Вычисление предельной разрядности |вычислении предельной разрядности]] и <code >" %*ld"</code> в качестве ''строки формата'' функции <code >printf</code>) заменены в данном варианте ''переменными'' <var >base</var> и <var >fmt</var>, соответственно.
Строка 262:
Во фрагменте выше, мы используем функцию <code >strchr</code> (''объявленную'' в ''заголовке'' <code >string.h</code>) поиска первого вхождения символа (кода) в строку<ref name="strchr" /> — в данном случае, поиска символа <code >0</code> в аргументе командной строки.
Функция возвращает ''нулевой указатель'' (0 или <code >NULL</code>) если символ не найден.<ref name="strchr" /> Поскольку это означает, что аргумент командной строки не содержит символа <code >0</code> <em >вовсе</em>, очевидно, что он не может содержать его и как часть префикса системы счисления (<code >0x</code> или <code >0</code>), а значит следует использовать десятичную систему счисления при [[#Вычисление предельной разрядности |вычислении предельной разрядности]] и ''указатель представления'' <code >d</code> — «десятичное число»: <
{{Якорь |isdigit}}
Точно так же обрабатывается случай, когда найденному символу <code >0</code> <em >предшествует</em> любая десятичная цифра — <
Следующим мы проверяем условие <
Наконец, если условия выше (наличие цифры перед <code >0</code> ''или'' <code >x</code>, <code >X</code> — после) — не выполнены, мы присваиваем <var >base</var> значение 8, <var >fmt</var> — <code >" %*lo"</code>.
|