[Язык C] Операции, выражения и операторы (глава 5)

Пятая глава в книжке Стивена Прата “C Primer Plus”. В ней идет речь об операторах и цикле while. Любопытно, что в книге Прата while идет до if/else в плане изложения материала; в то время, как в программировании часто учат циклы уже посте условных операторов.

Помимо решений, буду постить свои варианты некоторых (наиболее любопытных) программ из листингов. Я делаю так – просматриваю листинг, потом закрываю книжку и пишу “своими словами”:

1) Создаем таблицу квадратов чисел
#include <stdio.h>
int main (void)
{
int n=1;
int sqrt;
while (n<10)
{
sqrt=n*n;
printf("Square root for %d is %d\n",n,sqrt);
n=n+1;
}
getchar();
return 0;
}

2) Программа про зернышки на шахматной доске ← ссылка; выложил в виде отдельной статьи на сайте.

3) Перевод секунды в минуты и секунды (деление по модулю: %)

#include <stdio.h>
int main(void)
#define SEC_TO_MIN 60
{
int sec, min, sec_left;
printf("Enter second to transfer them to minites:\n");
scanf("%d",&sec);
min = sec / SEC_TO_MIN;
sec_left = sec % SEC_TO_MIN;
printf("%d seconds in minutes: %d minites %d seconds", sec, min, sec_left);
getchar();getchar();
return 0;
}

Это первый вариант программы. Теперь сделаем так, чтобы она периодически запрашивала ввод новых значений:

#include <stdio.h>
int main(void)
#define SEC_TO_MIN 60
{
int sec, min, sec_left;
printf("Enter second to transfer them to minites:\n(to finish enter 0)\n");
while (sec>0)
{
scanf("%d",&sec);
min = sec / SEC_TO_MIN;
sec_left = sec % SEC_TO_MIN;
printf("%d seconds in minutes: %d minites %d seconds\n", sec, min, sec_left);
}
getchar();
return 0;
}

4) Проблема с программой из параграфа “Операция уменьшения”
(Листинг 5 .12. Программа bottles.с)

#include <stdio.h>
#define MAX 100
int main(void)
{
int count = MAX + 1;
while (--count > 0)
{
printf("%d bottles in box, "
"%d bottles in box\n", count,count);
printf("Drink one... and now there are %d bottles in the box\n\n", count - 1);
}
getchar();
return 0;
}

Тут забавная штука. Вывод показывает начало с “Drink one… and now there are 99 bottles in the box”. Оказалось дело в том, что длины консоли виндовой не хватает, чтобы поместить все значения, когда запускаешь программу из компилятора. Если делать вывод в файл (батник с содержимым: project1.exe >> a.txt), то первые строчки влезают и вывод получается как в книге.

И еще забавная штука – в моей книжке 2000 года там такие фразы:

100 бутылок пива на полке, 100 бутылок пива!
Сними одну и пусти ее по кругу,
99 бутылок пива на полке, 99 бутылок пива!..

Ну а в книжке 2014 года пиво поменяли на родниковую воду.. Куда катится мир?! 🙂


Правило использование операторов приращения ++ и уменьшения —

  • Не применяйте операцию инкремента или декремента к переменной, которая является частью более чем одного аргумента функции.
  • Не используйте операцию инкремента или декремента с переменной, которая
    появляется в выражении более одного раза.

Задание из “Контрольные вопросы”:

Нужно переделать эту программу:

#include <stdio.h>
#define TEN 10
int main(void)
{
int n = 0;
while (n++ < TEN)
        printf("%5d", n);
printf("\n");
getchar(); getchar();
return 0;
}

… которая выводит:

    1    2    3    4    5    6    7    8    9   10

…чтобы она выводила символы от a до g.

Мой первый вариант:

/// a to g
#include <stdio.h>
#define G 103 // 103 is ANSI for g
int main (void)
{
int n = 96; // 96 is ANSI for ` (just before 'a')
while (n++ < G)
        printf("%5c", n);
printf("\n");
getchar(); getchar();
return 0;
}

Второй вариант:

#include <stdio.h>
#define LIMIT 'h'
int main(void)
{
char n = 'a';
while (n < LIMIT)
        {
        printf("%5c", n);
        n++;
        }
getchar();
return 0;
}

В этом варианте приходится использовать h, т.к.  книжке пока до <= не дошли, и нужно справляться с задачами поставляемыми средствами 🙂 Посмотрев в книжке решение этой программы, вижу, что до вынесения инкремента в функцию printf я не догадался; вот оно:

#include <stdio.h>
int main(void)
{
char ch = 'a';
while (ch <= 'g')
        printf("%5c", ch++);
printf("\n");
getchar();
return 0;
}

Красиво, ничего не скажешь 🙂 Хотя <= это читерство на данном этапе книжки.

Итак, наконец-то мы дошли до упражнений по программированию в конце пятой главы:

1) Напишите программу, которая преобразует время в минутах в часы и минуты. Для значения 60 создайте символическую константу посредством #define или const. Используйте цикл while, чтобы обеспечить пользователю возможность повторного ввода значений и для прекращения цикла, если вводится значение времени, меньшее или равное нулю.

#include <stdio.h>
#define MIN_PER_HOUR 60
int main (void)
{
int min, hour, min_left;
printf("Enter time in minutes\n");
scanf("%d", &min);
while (min > 0)
        {
        hour = min / MIN_PER_HOUR;
        min_left = min % MIN_PER_HOUR;
        printf("%d minutes is: %d hours, %d minutes\n\n",
        min, hour, min_left);
        printf("Enter more minutes to convert or 0 to quit:\n");
        scanf("%d", &min);
        }
getchar();
return 0;
}

2) Напишите программу, которая запрашивает у пользователя ввод целого числа, а затем выводит все целые числа, начиная с этого числа (и включая его) и заканчивая числом, которое больше введенного значения на 10 (включая его). (То есть, если вводится число 5, то в выводе должны присутствовать числа от 5 до 15). Обеспечьте разделение выводимых значений друг от друга пробелами, символами табуляции или символами новой строки.

#include <stdio.h>
int main (void)
{
int n=0, z=0;
printf("Choose the number, Neo\n");
scanf("%d", &n);
z = n;
while (n <= z+10)
        {
        printf("%d\n", n++);
        }
getchar();getchar();
return 0;
}

И второй подход:

#include <stdio.h>
int main(void)
{
int n = 0, z = 0;
printf("Choose the number, Neo\n");
scanf("%d", &n);
while (z <= 10)
	{
	printf("%4d\n", n + z);
	z++;
	}
getchar();getchar();
return 0;
}

3) Напишите программу, которая запрашивает у пользователя ввод количества
дней и затем преобразует это значение в количество недель и дней. Например,
18 дней программа должна преобразовать в 2 недели и 4 дня. Отображайте результаты в следующем формате:
18 дней составляют 2 недели и 4 дня.
Чтобы пользователь мог многократно вводить количество дней, используйте
цикл while. Цикл должен завершаться при вводе пользователем неположительного значения, например, 0 или -20.

#include <stdio.h>
#define DAYS_PER_WEEK 7
int main(void)
{
int day, week, day_left;
printf("Enter happy days\n");
scanf("%d", &day);
while (day > 0)
        {
        week = day / DAYS_PER_WEEK;
        day_left = day % DAYS_PER_WEEK;
        printf("%d days is: %d weeks %d days\n",
        day, week, day_left);
        printf("Enter another value or 0 to exit\n");
        scanf("%d", &day);
        }
getchar();
return 0;
}

4) Напишите программу, которая запрашивает у пользователя ввод значения высоты в сантиметрах, после чего отображает высоту в сантиметрах, а также в футах и дюймах. Должны быть разрешены дробные части сантиметров и дюймов. Программа должна позволить пользователю продолжать ввод значений высоты до тех пор, пока не будет введено неположительное значение. Вывод этой программы должен иметь следующий вид:
Введите высоту в сантиметрах: 182
182.0 см = 5 футов, 11.7 дюймов
Введите высоту в сантиметрах (<=0 для выхода из программы): 168.7
168.0 см = 5 футов, 6.4 дюймов
Введите высоту в сантиметрах (<=0 для выхода из программы): 0
Работа завершена.

Столкнулся с проблемой – невозможно привести к модулю дробные величины. Как в таком случае найти дюймы с необходимой точностью? Пришлось потанцевать с бубном:

#include <stdio.h>
#define CM_PER_INCH 2.54
#define INCH_PER_FEET 12.0
int main(void)
{
float cm, feet, inches, iches_left, inches_float;
printf("Enter you height in centimeters:\n");
scanf("%f",&cm);
while (cm > 0)
{
inches = cm / CM_PER_INCH;
iches_left = (int)inches % (int)INCH_PER_FEET; // modulus operator fail to work with floating values
feet = (inches - iches_left) / INCH_PER_FEET;
inches_float = inches - ((int)feet * INCH_PER_FEET);
printf("%.1f cm is %.0f feets %.1f inches\n",cm,feet,inches_float);
printf("Enter another one or 0 to exit\n");
scanf("%f",&cm);
}
getchar();
return 0;
}

Есть более элегантное решение, если забыть про модуль и грамотно использовать приведение типов (см. комментарии):

#include <stdio.h> #include <stdio.h>
#define CM_PER_INCH 2.54
#define INCH_PER_FEET 12.0
int main(void)
{
float cm, inches, inches_left;
int feet;
printf("Enter you height in centimeters:\n");
scanf("%f",&cm);
while (cm > 0)
{
inches = cm / CM_PER_INCH;
feet = inches / INCH_PER_FEET; // floating-point value got truncated because 'int feet'
inches_left = inches - (feet * INCH_PER_FEET); // as operation involves two types - 'float inches' and 'int feet' - both values 'promoted' to higher ranking and become floating-point
printf("%.1f cm is %d feets %.1f inches\n",cm,feet,inches_left);
printf("Enter another one or 0 to exit\n");
scanf("%f",&cm);
}
getchar();
return 0;
}

5) Внесите изменения в программу addemup.с (листинг 5.13), которая вычисляет
сумму первых 20 целых чисел. (Если хотите, можете считать addemup.с программой, которая вычисляет сумму, которую вы будете иметь спустя 20 дней, если в первый день вы получаете $1, во второй день — $2, в третий день — $3 и т.д.). Модифицируйте программу так, чтобы можно было интерактивно указать, насколько далеко должно распространяться вычисление. Другими словами, замените число 20 переменной, значение которой вводится пользователем.

// summ of first n values
#include <stdio.h>
int main(void)
{
int n=0, z=0, x;
printf("Enter number of integers to sum\n");
scanf("%d", &x);
while (n++<x)
z=n+z;
printf("%d\n", z);
getchar();getchar();
return 0;
}

6) Теперь модифицируйте программу из упражнения 5, чтобы она вычисляла сумму квадратов целых чисел. (Или, если вам гак больше нравится, программа должна вычислять сумму, которую вы получите, если в первый день вам заплатят $1, во второй день — $4, в третий день — $9 и т.д.) В языке С отсутствует функция возведения в квадрат, но, как вы знаете, квадрат числа n равен n*n.

// summ of squares
#include <stdio.h>
int main(void)
{
int n=0, z=0, x;
printf("Enter number of squares to sum\n");
scanf("%d", &x);
while (n++<x)
         z=(n*n+z);
printf("%d\n", z);
getchar();getchar();
return 0;
}

7) Напишите программу, которая запрашивает ввод числа типа double и выводит значение куба этого числа. Для этого используйте собственную функцию, которая возводит значение в куб и выводит полученный результат. Программа main () должна передавать этой функции вводимое значение.

В этом примере я уткнулся в затык – программы выдавала нули. Оказалось, это из-за передачи значения scanf(“%f”,…), в том время, как вычисления идут с точностью double.

Так происходит потому, что функция не знает какие типы у переданных к ней параметров, т.к. передаются не сами параметры, а указатели (pointer). Поэтому функции необходимо точно знать на какой тип указывает полученный указатель – на float (32 бита) или на double (64 бита).

Это означает, что функция не понимает, в каком бите находится разделитель десятичного значения и поэтому возвращает дичь. В то время, как в С преобразует float в double для аргументов функций – ссылки (pointer) никак не преобразуются (надеюсь, понятно разжевал.. разжевывал в том числе для себя). Итак, программа:

#include <stdio.h>
void cube(double n);
int main(void)
{
double n;
printf("Enter number to cube it\n");
scanf("%lf", &n);
cube(n);
getchar();getchar();
return 0;
}
void cube(double n)
{
double x3 = n*n*n;
printf("Cube of %f is %f",n, x3);
}

8) Напишите программу, которая выводит результаты применения операции деления по модулю. Пользователь должен первым ввести целочисленное значение,
которое используется в качестве второго операнда и остается неизменным.
Затем пользователь должен вводить числа, для которых будет вычисляться результат деления по модулю. Процесс должен прерываться вводом значения, которое равно или меньше 0. Пример выполнения этой программы должен выглядеть следующим образом:
Эта программа вычисляет результаты деления по модулю.
Введите целое число, которое будет служить вторым операндом: 256
Теперь введите первый операнд: 438
438 % 256 равно 182
Введите следующее число для первого операнда (<= 0 для выхода из
программы): 1234567
1234567 % 256 равно 135
Введите следующее число для первого операнда (<= 0 для выхода из
программы): 0
Готово

#include <stdio.h>
int main(void)
{
int x, y;
printf("Enter second modulus operator\n");
scanf("%d",&y);
printf("Enter first modulus operator\n");
scanf("%d",&x);
while(x > 0)
  {
  printf("%d %% %d = %d\n", x, y, x%y);
  printf("Enter another first modulus operator or 0 for exit\n");
  scanf("%d",&x);
  }
getchar();
return 0;
}

9) Напишите программу, которая запрашивает у пользователя ввод значения температуры по Фаренгейту. Программа должна считывать значение температуры как число типа double и передавать его в виде аргумента пользовательской функции по имени Temperatures (). Эта функция должна вычислять эквивалентные значения температуры по Цельсию и по Кельвину и отображать на экране все три значения температуры с точностью до двух позиций справа от десятичной точки. Функция должна идентифицировать каждое значение символом соответствующей температурной шкалы. Вот формула перевода температуры по Фаренгейту в температуру по Цельсию:
Температура по Цельсию = 5.0 / 9.0 * (температура по Фаренгейту - 32.0)
В шкале Кельвина, которая обычно применяется в науке, 0 представляет абсолютный нуль, т.е. минимальный предел возможных температур. Формула перевода температуры по Цельсию в температуру по Фаренгейту имеет вид:
Температура по Кельвину = температура по Цельсию + 273.16
Функция Temperatures () должна использовать const для создания символических представлений трех констант, которые участвуют в преобразованиях. Чтобы
предоставить пользователю возможность многократного ввода значений температуры, в функции main () должен быть организован цикл который завершается при вводе символа q или другого нечислового значения. Воспользуйтесь тем фактом, что функция scanf () возвращает количество прочитанных ею элементов, поэтому она возвратит 1, если прочитает число, но не будет возвращать 1, когда пользователь введет q. Операция == выполняет проверку на равенство, так что ее можно применять для сравнения возвращаемого значения scanf () с 1.

// to check: 32 F is 0 C and 273.16 K
#include <stdio.h>
void temperatures (double f);
int main(void)
{
double fahrenheit;
printf("Enter temperature in F: ");
while (scanf("%lf", &fahrenheit) == 1)
{
temperatures(fahrenheit);
printf("Enter another F-value to calculate or any letter-symbol to exit\n");
}
getchar();getchar();
return 0;
}
void temperatures (double fahrenheit)
{
const double a = 5.0; // F to C
const double b = 9.0; // F to C
const double c = 32.0; // F to C
const double d = 273.16; // F to K
double celsium = a / b * (fahrenheit - c);
double kelvin = celsium + d;
printf("%.2f fahrenheit is %.2f C or %.2f K\n",fahrenheit, celsium, kelvin);
}

Буду рад вашим комментариям!

This entry was posted in С (Си). Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *