Доброго времени суток! Сегодня я приведу решения домашних заданий с четвертого по
восьмой выпуск рассылки.
Я получил от вас огромное количество писем с вопросами. Вопросы были разные.
Но главный вопрос меня добил. Вот он: "Скажите пожалуйста, где можно взять
предыдущие выпуски рассылки?"
Ну нельзя же так! Давайте установим правило: сперва вы пытаетесь решить вопрос сами,
а уж потом просите о помощи. Ну подумайте: рассылка распространяется через
Subscribe.Ru, так зайдите на него и хорошенько осмотритесь вокруг. И вы сразу
найдете лежащий там
архив рассылки. Только хочу вам порекомендовать выпуски с 1-го по 4-й читать
в текстовом варианте - когда я их писал, я еще не разобрался с конвертацией
в HTML, в результате чего HTML-версия оказалось несколько подпорченной. Особенно
это видно в 4-м выпуске.
Еще один вопрос был такой: как подписаться, не имея полноценного доступа к Интернету,
а только к e-mail? Отвечаю: напишите письмо по адресу
subscribe@subscribe.ru, содержащее
единственную строку HELP, и ждите ответа.
И еще просьба не присылать мне сообщений не по теме, как то "как подписаться на
рассылку", "где взять архив рассылки", "где скачать C++", и т.д.
Я просто физически не могу отвечать на все письма такого содержания. Еще просьба
указывать в поле "Subject" тему письма, а не "вопрос", "помогите"
, "?????", и т.д. Этим вы сильно упростите процедуру разбора
корреспонденции, следовательно, быстрее получите ответ. Да, не пугайтесь, если я вам
не ответил: быть может, я решил ответить в рассылке, а для этого необходимо дождаться
ее очередного выпуска.
Итак, решения домашних заданий (если у кого нет условий - ищите в
архивах).
Тем, кто их сделал, все же рекомендую посмотреть, как их сделал я. Тем, кто не
сделал: посмотрите на них, поймите, а после этого закройте и, больше не смотря
на них, сделайте все сами! Тогда все поймете. Да, я решил изменить нумерацию.
Теперь номера задач будут состоять из номера выпуска рассылки и номера задачи
в выпуске, разделенных точкой. Этого обозначения я буду придерживаться и здесь.
4.2.a = 2, f = 10, i = 1. Остальные
переменные - без изменений.
Если с первым присваиванием все еще кое-как ясно (обратите внимание: a
меняется!), то со вторым у многих возникли вопросы. Что ж, разбираем детально.
Для начала расставим скобки, чтобы обозначить порядок операций: i = ((3 < 2)
< 1);. 3 больше чем 2, следовательно 3 < 2 - ложно, т.е. равно
нулю (напомню, что в С ложь - это 0, истина - все остальное). А теперь этот
нуль сравнивается с единицей. Т.к. 0 < 1, то (0 < 1) = 1. Эта единица
и присваивается переменной i.
4.3. Привожу полностью исходный текст программы:
#include <stdio.h>
#include <math.h>
int main (void)
{
float a, b, c, d, x1, x2;
a = 1;
b = -1;
c = -6;
d = b * b - 4 * a * c;
x1 = (-b + sqrt (d)) / (2 * a);
x2 = (-b - sqrt (d)) / (2 * a);
printf ("%f\n%f\n", x1, x2);
return 0;
}
В комментариях, я думаю, не нуждается. Единственное замечание - это строка
"%f" в параметрах функции printf. Если
на место %d подставляется целое число, то на место
%f будет подставлено дробное
(float или double).
5.1. Опять текст программы:
#include <stdio.h>
#include <math.h>
int main (void)
{
float a, b, c, d, x1, x2;
a = 0;
b = 0;
c = 2;
if (!a)
if (!b)
if (!c)
printf ("x - любое число\n");
else
printf ("Решений нет.\n");
else
{
x1 = -c / b;
printf ("%f\n", x1);
}
else
{
d = b * b - 4 * a * c;
if (d < 0)
printf ("Действительных решений нет.\n");
else
{
x1 = (-b + sqrt (d)) / (2 * a);
if (!d)
printf ("x = %f\n", x1);
else
{
x2 = (-b - sqrt (d)) / (2 * a);
printf ("x1 = %f\nx2 = %f\n", x1, x2);
}
}
}
return 0;
}
Опять, я думаю, все понятно. Единственное, на что стоит обратить внимание - это на
конструкции типа if (!d). Как я уже говорил,
в С истина - все, что не нуль, поэтому эта конструкция эквивалентна конструкции
if (d == 0).
5.2. Снова текст (на этот раз только функции):
int triangle (int a, int b, int c)
{
int t;
/* Поменяем стороны местами так, чтобы c была наибольшей */
if (a > c)
{
t = a;
a = c;
c = t;
}
if (b > c)
{
t = b;
b = c;
c = t;
}
if (c >= a + b)
return 0;
if (c*c < a*a + b*b)
return 1;
return 2;
}
Думаю, в пояснениях не нуждается (конечно, если вы еще не забыли геометрию).
6.1. И снова текст:
#include <stdio.h>
int main (void)
{
double c = 1, s = 1;
int i = 0;
do
s += 1 / (c *= ++i);
while (c < 10000);
printf ("%f\n", s);
return 0;
}
Я надеюсь, что вы уже оценили краткость всей программы. Все же приведу некоторые
пояснения по части выделенного красным цветом выражения. Итак, в переменной c
у нас находится факториал числа i, в переменной s - сумма ряда.
На каждом шаге переменная i увеличивается на 1 (++i), вычисляется
ее факториал (с *= ++i, напомню, что n! = n * (n-1)!), и величина, обратная
этому факториалу, добавляется к переменной s. Так делается, пока 1/c
> 0.0001, то есть пока c < 10000.
6.2. Я думаю, все уже ее запустили и посмотрели :-)
И все же:
36
18
9
4
2
1
Что делает эта программа? Она печатает серию чисел, первое из которых - 36, а каждое
последующее вдвое меньше предыдущего (с точностью до округления). После того, как
напечатается единица, i примет значение, равное 0 (0.5, округленное до целого),
и цикл прекратится (напомню, что 0 - это ложь).
6.3. Вообще-то я тут ошибся с условием. Но
ничего не поделаешь, придется решать то, что написал :-)
#include <stdio.h>
int main (void)
{
int i, j;
for (i = 0; i < 6; i++)
{
for (j = 0; j < (((i < 2) ? 7 : 6) - i); j++)
printf ("$");
printf ("\n");
}
return 0;
}
Внимательно присмотритесь к выделенному красным цветом выражению. Если вы еще раз
прочтете условие, то заметите, что во второй строчке должно быть шесть
знаков, а в третьей - уже четыре. Поэтому в условие введен добавочный
оператор (i < 2) ? 7 : 6, который, как вы помните, возвратит 7, если
i < 2, и 6 в противном случае. Этим достигнется указанный эффект - из треугольника
как бы выбросится одна строка.
7.1. Текст функции:
void exchange (int *a, int *b)
{
int *t, c, d;
if (*a < *b)
{
t = a;
a = b;
b = t;
}
c = *a;
d = *b;
*a = (c + d) / 2;
*b = (c - d) / 2;
return;
}
А вот тут придется разбираться. Сперва обратите внимание на условие и блок за ним.
В нем мы переставляем переменные так, чтобы a содержало большее из
двух переменных. Но обратите внимание: мы меняем на значения, а адреса.
Значения переменных a и b в вызывающей функции пока что остались
без изменений, но a теперь указывает на большую переменную, а
b - на меньшую. А после этого мы с чистой совестью производим требуемую
замену, не забыв сохранить начальные значения переменных - иначе мы перезапишем
a новым значением и не сможем вычислить правильное значение b.
7.2. Снова текст:
void PrintFunc (int (*f)(int x))
{
int i;
for (i = 0; i <= 20; i++)
printf ("%d %d\n", i, (*f)(i));
return;
}
По-моему, тут все понятно.
8.1. Текст функции:
int Search4max (int d[], int Count)
{
int i, m = d [0];
for (i = 1; i < Count; i++)
if (m < d [i])
m = d [i];
return m;
}
8.2. Текст функции:
int Search4max (int d[4][4][4])
{
int i, j, k, m = d [0][0][0];
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 4; k++)
if (m < d [i][j][k])
m = d [i][j][k];
return m;
}