Тип переменных для хранения БУКВ называется
Char
(от слова character).
Буквы изображаются в одиночных кавычках 'a' 'b' '+'.
Пример: char letter;
letter = 'a'; putchar(letter); letter = 'b'; putchar(letter); letter = '\n'; putchar(letter);
Символ '\n' обозначает "невидимую букву" - переход на новую строку, new line. Есть несколько таких специальных букв, о них - позже.
Зато сразу сделаем оговорку. Чтобы изобразить саму букву \ следует использовать '\\'
putchar('\'); или printf ("\"); ошибочны.
Надо: putchar('\\'); printf("\\");
Дело в том, что символ \ начинает последовательность из ДВУХ букв, изображающих ОДНУ букву, иногда вызывающую специальные действия на экране или на принтере. */
/* Число делится на n, если ОСТАТОК от деления его на n равен 0, то есть если
(x % n) == 0
В частности, так можно проверять числа на четность/нечетность, беря x%2.
Остатки от деления числа x на n это 0 1 2... n-1. В случае деления на 2 остаток 0 соответствует четному x 1 соответствует нечетному x
*/
/* Задача: Нарисовать треугольник из звездочек в нечетных строках из плюсиков в четных строках *--------------------------------------------------------*
Решение: используем прежнюю программу, добавив в функцию drawOneLine еще один аргумент - symbol - каким символом рисовать строку.
Далее в основном цикле используем условный оператор и проверку номера строки на четность.
*/
#include
void drawOneLine(int nspaces, int nsymbols, char symbol){ int i; /* счетчик */
for(i=0; i < nspaces; i++) putchar(' '); for(i=0; i < nsymbols; i++) putchar(symbol); putchar('\n'); }
/* Мы вынесем объявление этой переменной из функции, сделав ее "глобальной", то есть видимой во ВСЕХ функциях. */ int LINES = 25; /* всего строк. */
void main(){ /* ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ */ int nline; /* номер строки */
/* ВЫПОЛНЯЕМЫЕ ОПЕРАТОРЫ (ДЕЙСТВИЯ) */ for(nline=0; nline < LINES; nline++){
if((nline % 2) == 0) /* четное? */ drawOneLine(LINES - nline - 1, nline*2 + 1, '+'); else drawOneLine(LINES - nline - 1, nline*2 + 1, '*'); } } 08.c
/* То же самое, но теперь нужно еще и печатать номер строки. */
#include
/* Вообще-то глобальные переменные принято объявлять в самом начале файла с программой. */
int LINES = 25; /* всего строк. */
/* Добавим к функции еще один аргумент, указатель - печатать ли номер строки. Назовем его drawLineNumber. Не впадите в заблуждение по аналогии с именем ФУНКЦИИ drawOneLine()! В данном случае - это имя ПЕРЕМЕННОЙ - АРГУМЕНТА ФУНКЦИИ.
Оператор if(x).....; РАБОТАЕТ ТАКИМ ОБРАЗОМ (так он устроен): в качестве условия он принимает целое число (типа int). Условие истинно, если x!= 0, и ложно, если x == 0.
Второй добавленный аргумент - собственно номер строки. */ void drawOneLine(int nspaces, int nsymbols, char symbol, /* а это мы добавили */ int drawLineNumber, int linenum ){ int i; /* счетчик */
if(drawLineNumber) printf("%d\t", linenum); /* без перевода строки */
/* На самом деле это условие более полно надо записывать как
if(drawLineNumber!= 0)
но в языке Си это то же самое. */
/* Тут мы снова видим новый специальный символ \t - ТАБУЛЯЦИЯ. Весь экран (или лист бумаги) условно поделен на колонки шириной по 8 позиций. Примерно так: | | | | | | | | |... Символ табуляции вызывает переход из текущей позиции в начало следующей колонки. Например | | | | | | | | |... ^ отсюда
| | | | | | | | |... ^ в это место
*/ for(i=0; i < nspaces; i++) putchar(' '); for(i=0; i < nsymbols; i++) putchar(symbol); putchar('\n'); }
void main(){ /* ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ */ int nline; /* номер строки */
/* ВЫПОЛНЯЕМЫЕ ОПЕРАТОРЫ (ДЕЙСТВИЯ) */ for(nline=0; nline < LINES; nline++){
if((nline % 2) == 0) /* четное? */ drawOneLine(LINES - nline - 1, nline*2 + 1, '+', 1, nline); else drawOneLine(LINES - nline - 1, nline*2 + 1, '*', 9, nline); }
/* А почему именно 1 или именно 9? * А все что попало, лишь бы не 0. * Можно 3, 333, 666, -13445, итп * * Вопрос: что будет, если тут написать 0? */ } 09.c
/* Следующая задача будет касаться того, чтобы каждая строка треугольника печаталась в виде: *+*+*+*.....*+*
Тут нам уже придется модифицировать функцию рисования строки. */
#include
int LINES = 25; /* всего строк. */
void drawOneLine(int nspaces, int nsymbols){ int i;
for(i=0; i < nspaces; i++) putchar(' ');
/* в цикле мы будем проверять на четность НОМЕР печатаемого символа. */ for(i=0; i < nsymbols; i++){ if((i % 2) == 0) putchar('*'); else putchar('+'); } putchar('\n'); }
void main(){ int nline; /* номер строки */
for(nline=0; nline < LINES; nline++) { drawOneLine(LINES - nline - 1, nline*2 + 1); } } 10.c
/* Задача нарисовать РОМБ: * *** ***** *** * */
#include
int LINES = 10; /* всего строк в половине ромба. */
void drawOneLine(int nspaces, int nsymbols){ int i;
for(i=0; i < nspaces; i++) putchar(' ');
for(i=0; i < nsymbols; i++) putchar('+'); putchar('\n'); }
void main(){ int nline; /* номер строки */
for(nline=0; nline < LINES; nline++) drawOneLine(LINES - nline - 1, nline*2 + 1);
/* Мы нарисовали треугольник. Теперь нам нужен перевернутый треугольник. Пишем цикл по убыванию индекса. С данного места номера строк отсчитываются в обратном порядке: от LINES-2 до 0 */
for(nline=LINES-2; nline >= 0; nline--) drawOneLine(LINES - nline - 1, nline*2 + 1); } 11.c
/* А теперь рисуем ромб, используя математические формулы. */
#include
void draw(int nspaces, int nstars, char symbol){ int i;
for(i=0; i < nspaces; i++) putchar(' '); for(i=0; i < nstars; i++) putchar(symbol); putchar('\n'); }
void main(){ int LINES = 21; int MIDDLELINE = LINES/2 + 1; /* середина ромба */ int nline;
for(nline=0; nline < MIDDLELINE; nline++) draw(MIDDLELINE - nline -1, nline*2+1, 'A');
/* У следующего цикла for() нет инициализации начального значения индекса. Начальное nline наследуется из предыдущего цикла, таким, каким оно осталось после его окончания, то есть равным MIDDLELINE. */
for(; nline < LINES; nline++) draw(nline - MIDDLELINE + 1, (LINES - 1 - nline) * 2 + 1, 'V'); } * 12_ARRAYS.txt *
МАССИВЫ
Массив - это несколько пронумерованных переменных, объединенных общим именем. Все переменные имеют ОДИН И ТОТ ЖЕ ТИП.
Рассмотрим ПОЛКУ с N ящиками, пусть имя полки - var. Тогда кажждый ящик-ячейка имеет имя var[0] var[1] ... var[N-1]
Нумерация идет с НУЛЯ.
-------- / var / / / ------------------------------------------- ------------------ | | | | | | | | | |....... | | | | | | | | ------------------------------------------- ------------------ / var[0] / / var[1] / / var[2] / / var[N-1] / --------- --------- --------- -----------
Массив объявляется так:
int var[N];
здесь N - его размер, число ячеек.
Это описание как бы объявляет N переменных типа int с именами var[0]... var[N-1];
В операторах для обращения к n-ому ящичку (где 0 <= n < N) используется имя ящика
var[n]
где n - целое значение (или значение целой переменной, или целочисленного выражения), "индекс в массиве". Эта операция [] называется "индексация массива". Индексация - есть ВЫБОР одного из N ящиков при помощи указания целого номера. var - массив (N ячеек) n - выражение (формула), выдающая целое значение в интервале 0..N-1 var[n] - взят один из элементов массива. Один из всех. n - номер ящика - называется еще и "индексом" этой переменной в массиве.
Пример:
int var[5]; /* 1 */
var[0] = 2; /* 2 */ var[1] = 3 + var[0]; /* 3 */ var[2] = var[0] * var[1]; /* 4 */ var[3] = (var[0] + 4) * var[1]; /* 5 */
printf("var третье есть %d\n", var[3]);
В ходе этой программы элементы массива меняются таким образом:
var[0] var[1] var[2] var[3] var[4] ------------------------------------------------ /* 1 */ мусор мусор мусор мусор мусор /* 2 */ 2 мусор мусор мусор мусор /* 3 */ 2 5 мусор мусор мусор /* 4 */ 2 5 10 мусор мусор /* 5 */ 2 5 10 30 мусор
Как видим, каждый оператор изменяет лишь ОДНУ ячейку массива за раз.
Массив - набор переменных, которые не ИМЕНОВАНЫ разными именами, вроде var0, var1, var2,... а ПРОНУМЕРОВАНЫ под одним именем: var[0], var[1], var[2],...
Индекс - часть ИМЕНИ ПЕРЕМЕННОЙ.
На самом деле индексация - это 1) выбор элемента в массиве 2) справа от присваиваний и в выражениях - еще и разыменование, то есть взятие вместо имени переменной - значения, в ней хранящегося. ---------------------------------------------------------------------------
Если в переменную не было занесено значение, а мы используем эту переменную, то в ней лежит МУСОР (любое, непредсказуемое значение).
printf("var4 есть %d\n", var[4]);
напечатает все что угодно.
Поэтому переменные надо всегда инициализировать (давать им начальное значение).
Глобальные переменные автоматически инициализируются нулем, если мы не задали иначе.
Локальные переменные не инициализируются автоматически, и содержат МУСОР. ---------------------------------------------------------------------------
Массивы НЕЛЬЗЯ присваивать целиком, язык Си этого не умеет.
int a[5]; int b[5];
a = b; /* ошибка */
Также нельзя присвоить значение сразу всем элементам (ячейкам) массива:
a = 0; /* ошибка */
не делает того, что нами ожидалось, а является ошибкой. Для обнуления всех ячеек следует использовать цикл:
int i;
for(i=0; i < 5; i++) /* для каждого i присвоить a[i] = 0; */ a[i] = 0;
---------------------------------------------------------------------------
|