Для начала разбор Д/З Вот прога, которую ты составил по уроку №2:
#include <stdio.h> void main(void){ int i[100]; int v; int c=100; for(v=1;v<100;v++){ i[v]=c; c--; } }
Оценка : Всё правильно !!!
Но все же предлагаю тебе посмотреть на мои варианты написания этой проги. От тебя требуется въехать, почему мои варианты делают тоже самое, что и твой и как они работают. Если сможешь - используй эти приёмы в дальнейшем.
Вариант №1 (небольшая модификация твоей проги)
#include <stdio.h>
void main(){ int i[100],v; for(v=100;v>0;v--){ i[100-v]=v; } }
Надеюсь, с пониманием этого варианта у тебя не возникнет проблем. Отличий от твоего немного: 1. в main я не передаю void. А что же тогда туда передается? Если тип опущен, то по умолчанию считается, что это int. Т.е. эта запись эквивалентна void main(int ). Ты резонно спросишь, а зачем нам в функцию передавать какой-то int ? на что я отвечу - этот int нам нафиг не нужен :-)) Его использовать я вовсе не собираюсь. Просто так короче писать - main() с пустыми скобками. Вот если еще опустить возвращаемый main'ом тип: "main()", что будет эквивалентно "int main(int)", то тут возникнут накладки. Раз мы заявили, что функция возвращает int, то будем обязаны в конце функции его вернуть, например командой "return 0;" 2. переменные одного типа я обявляю в одной команде через запятую, даже если одно из них массив, а другое просто переменная. 3. я использую на одну переменную меньше, чем ты. Действительно, зачем иметь 2 счетчика, один из которых пробегает от одного до 100, а другой от 100 до 1. Значение второго счетчика можно просто получить вычитая из 101 первый счетчик. 4. И последнее, мне было удобнее сделать цикл for убывающим. Впрочем, убывающий или возрастающий - один хрен.
Вариант №2 (хакерский :-)
void main(){ int i[100],v=100;
while(v) i[100-v]=v--; }
Этот вариант как раз в тему этого урока. Вернее темы две - это еще одна конструкция для построения цикла «while» и вычисление выражений. while использовать значительно проще for'а:
while(условие){ операторы }
«Операторы выполняются повторно, пока «условие» является истиной. Прежде чем понять, как работает вариант №2, рассмотрим его упрощенную для понимания версию:
(0)- как видишь, никакого include'а нет. Он же был нужен, чтобы использовать функцию printf из библиотеки stdio. Здесь мы ничего на экран не выводим - поэтому отпадает необходимость в подключении библиотеки. В (1) создаются переменные - массив на 100 элементов и переменная v, которая тут же инициализируется числом 100. Начинается исполнение цикла while. Сначала в (2) проверяется условие. Оно удовлетворяется (100>0) и мы входим в цикл (3). Если бы оно не выполнилось, то мы бы перешли на строчку, следующую за циклом, не входя в него. В данном случае это была бы (5) - выход из программы. Но пока что все ОК и мы переходим на (3), в которой в ячейку массива с номером 100-v заносится число из переменной v. На первом шаге v=100 и получаем, что в нулевую ячейку заносится число 100. Далее в(4) v уменьшается на единицу. (5) - конец тела цикла. Возвращаемся к проверке условия в (2). 99>0 - условие выполняется и мы опять входим в цикл. Теперь в ячейку №1 заносится число 99 и т.д. Так этот цикл будет крутиться пока после очередного (4) переменная v уменьшится до нуля. Тогда условие (2) не выполнится. Исполнение перейдет на (6) и программа завершится. Как видишь, while можно считать урезанным for'ом - без инициализации и без инкримента. Инициализацию (занесение 100 в v) здесь приходится делать перед циклом, а инкримент (v--) - в конце тела цикла. Если есть какие-либо вопросы по поводу цикла while, можешь их задавать сейчас. Вопросов не слышу - продолжаем дальше :-) Теперь окончательно разберемся с тем хакерским кодом. Что означает запись «while(v)». Это равносильно «while(v!=0)». «!=» - это «не равно», оператор сравнения. Есть еще «==» - это «равно» , оператор сравнения. Не надо путать с «=» - оператор присвоения. Операторы сравнения (больше, меньше , равно , не равно) используются при написании условий. так, почему же эти две записи равносильны. Для этого надо понять как происходит проверка условия (т.е. того, что записано в скобках).Условие , например «a>b», это такое же выражение, как «a+b», т.е. оно вычисляется и результат вычисления - это число. Только в отличие от арифметических операторов, где результатом может быть любое число - положительное, отрицательное или ноль, логические операторы дают только ноль (ложь) или один (истина). Пример: «int a; a=2>1;» - вполне нормальная запись. После выполнения в переменной «а» будет лежать 1. Естественно, условные операторы типа if или while ожидают, что им будет передан результат логического выражения, т.е. число 0 или 1. Но как можно заметить при исполнении строчки «while(v)» на первом шаге в v лежит число 100. В таком случае все, что не ноль является истиной. Именно поэтому цикл будет крутиться пока v не дойдет до нуля. Теперь рассмотрим строчку «i[100-v]=v--;». Как это надо понимать? Естественно, также, как это понимает компьютер :-) Вот тут начинается суровая часть. В данном выражении компьютер выделяет 4 оператора (операции): 1. вычитание (минус) 2. взятие элемента из массива (квадратные скобки) 3. присвоение (знак равно) 4. декремент (двойной минус)
Об операторах Каждый оператор как функция принимает на входе набор параметров и возвращает одно значение. Также у каждого оператора есть приоритет. Вообще последовательность выполнения операторов определяется вложенностью, а если операторы находятся на одном уровне вложенности - то приоритетом. Если приоритет одинаковый, то с права налево по очереди.
Примеры №1 «1-2*3+4» здесь 3 оператора с разными приоритетами. У умножения приоритет выше, чем у сложения и вычитания - оно выполняется первым. У вычитания и сложения приоритеты одинаковые и они выполняются справа налево. Действия компьютера: 2*3 -> 6 -6+4 -> -2 1-2 -> -1 само собой, что если вычислять без учета приоритета получится совсем другой результат №2 «((1-2)*3)+4» как я говорил, приоритеты операторов играют роль только, когда операторы находятся на одном уровне вложенности. Здесь видно, что на самом «внутреннем» уровне вложенности находится вычитание. За ним идет умножение и на последнем - сложение. В данном выражении приоритеты операторов никак не участвуют.
Предполагаю, ты скажешь «Я все это знал, мы еще в 3м классе проходили арифметику». Однако, это больше, чем арифметика. №3 «a=b+c» Я не сомневаюсь, что последовательность действий в этом примере ты тоже знаешь. Но важно еще понимать почему именно так происходит. Здесь 2 оператора на одно уровне вложенности, но с разными приоритетами. У сложения приоритет, естественно выше. Именно поэтому сначала b и c сложатся, а только потом результат сложения будет присвоен a. №4 «a=b=c» Если не знать теории, то можно подумать, что это какой-то новый оператор тройного равно в Си завелся. Однако, это обычное выражение из двух операторов равно. Как я уже говорил, оператор в Си как функция принимает параметры и возвращает значение. Так вот оператор равно принимает 2 параметра, заносит в левый параметр значение из правого и возвращает тоже значение. Теперь вооружившись теорией, мы увидим, что здесь 2 оператора с равным приоритетом. Следовательно, выполняются справа налево: 1. в b заносится значение из c b и оно же возвращается 2. в a заносится результат предыдущего действия, т.е. значение из с Таким образом, после выполнения этого выражения в a и b будет лежать тоже число, что и в с.
№5 «c=a+b++» операторы ++/-- принимают один параметр - переменную, которую надо увеличить/уменьшить. Они могут быть двух видов - постфиксные и префиксные. а++ - постфиксный - имеет самый низкий приоритет ++а - префиксный, имеет самый высокий приоритет таким образом, сначала складываются a и b, потом результат заносится в c, потом b увеличивается на 1.
Уффф! как же я утомился ! думаю, ты тоже :-)
Теперь должно быть ясно, что в «i[100-v]=v--;» в эл-т номер 100-v заносится число из v, потом v уменьшается на 1. и все это в одной строчке. И так повторяется пока v не уменьшится до нуля:
Я понимаю, что все это ты сразу не запомнишь и не сможешь использовать, но постарайся анализировать сёвые выражения исходя из этой теории.
Задание
1. заполнить массив на 100 элементов случайными целыми числами от 0 до 999 2. найти в этом массиве максимальное и минимальное число 3. вывести эти числа на экран. 4. найти сколько чисел в этом массиве меньше 500
Что бы получить случайное число, используй функцию rand() из библиотеки stdlib.h. Эта функция возвращает число от 0 до RAND_MAX. RAND_MAX -это определенная в библиотеке константа. Чтобы получить число из диапазона 0…999, используй: rand()*1000/ RAND_MAX. Чтобы найти макс. число, надо положить в переменную первое число в массиве, пройти в цикле по массиву и сравнивать это число с каждым. Если найдется большее - то запомнить его вместо текущего. Следует использовать переменные типа long, чтобы не произошло переполнения.