в. 7
г. 7
д. 5
е. 3
ж. 28
4. а. 255
б. 1 (“не ложно” — это “истинно”)
в. 0
г. 1 (“истинно” И “истинно” — это “истинно”)
д. 6
е. 1 (“истинно” ИЛИ “истинно” — это “истинно”)
ж. 40
5. В двоичной форме маска имеет вид 1111111, в десятичной — 12 7, в восьмеричной 0177, а в шестнадцатеричной — 0x7F.
6. Оба выражения bitval *= 2 и bitval << 1 удваивают текущее значение переменной bitval, поэтому они эквивалентны. Однако выражения mask += bitval и mask |= bitval оказывают одинаковое влияние, только если переменные bitval и mask не имеют ни одного общего установленного бита. Например, 2 | 4 равно 6, но этому же значению равен результат выражения 3 | 6.
7. a. struct tb_drives {
nsigned int diskdrives : 2; unsigned int : 1;
unsigned int cdromdrives : 2; unsigned int : 1;
unsigned int harddrives : 2;
6. struct kb_drives {
unsigned int harddrives : 2; unsigned int : 1;
unsigned int cdromdrives : 2; unsigned int : 1;
. unsigned int diskdrives : 2;
824 Приложение А
Ответы на вопросы для самоконтроля из главы 16
1. а. Результирующий код dist = 5280 * miles; является допустимым.
б. Результирующий код plort = 4*4 + 4; является допустимым, но если в действительности пользователю необходимо 4 * (4 + 4), то должно использоваться #define POD (FEET + FEET),
в. Результирующий код пех = = 6;; является недопустимым. (Если между двумя знаками равенства пробелы отсутствуют, код будет допустимым, но бесполезным.) Очевидно, пользователь забыл, что пишет макрос для препроцессора, а не код на С.
г. Результирующий код у = у + 5 является допустимым. Код berg = berg + 5 * lob; также допустим, но, скорее всего, представляет собой не тот результат, который хотел получить пользователь. Код est = berg + 5/у + 5; допустим, но, вероятно, представляет собой не тот результат, который хотел получить пользователь. Код nilp = lob *-berg + 5; является допустимым, но, скорее всего, представляет не тот результат, к которому стремился пользователь.
2. #define NEW (X) ( (X) +5)
3. #define MIN (X,Y) ( (X) < (Y) ? (X) : (Y) )
4. #define EVEN_GT (X, Y) ( (X) > (Y) && (X) % 2 == 0 ? 1 : 0 )
5. #def ine PR(X,Y) printf (#X " = %d и " #Y " = %d\n", X,Y)
Поскольку в этом макросе X и Y не появляются в каких-то других операциях (таких как умножение), круглые скобки можно не применять.
6. a. #define QUARTERCENTURY 2 5
б. #define SPACE ' '
в. #define PS() putchar (' ') или
#define PS() putchar(SPACE) r. #define BIG(X) ( (X) + 3)
д. #define SUMSQ(X,Y) ( (X) * (X) + (Y) * (Y) )
7. Попробуйте воспользоваться следующим определением:
#define Р(X) printf("имя: "#Х"; значение: %d; адрес: %p\n", X, &Х)
Если используемая вами реализация не распознает спецификатор адреса %р, применяйте %u или %lu.
8. Используйте директивы условной компиляции. Один из возможных способов предусматривает применение директивы #ifdef:
#define _SKIP_ /* удалите эту строку, если не хотите пропускать код */ #ifndef _SKIP_
/* код, который нужно пропустить */
#endif
9. #ifdef PR_DATE
printf("Дата = %s\n", ____ DATE );
#endi f
Ответы на вопросы для самоконтроля 825
10. Первая версия возвращает значение х*х. При этом просто возвращается значение типа double квадратах. Например, square (1.3) возвратит 1.69. Вторая версия возвращает (int) (х*х). Здесь результат усекается до типа int. Из-за того, что возвращаемым типом является double, значение int затем повышается до double. Таким образом, 1.69 сначала преобразуется в 1, после чего — в 1.00. Третья версия возвращает (int) (х*х+0.5). Добавление 0.5 приводит к округлению до ближайшего целого числа вместо его усечения. Следовательно, 1.69 становится 2.19, которое усекается до 2 и затем преобразуется в 2.00. Но 1.44 становится 1.94, что усекается до 1 и после этого преобразуется в 1.00.
11. Вот одна из возможных версий:
#define BOOL(X) _Generic((X) , _Bool : "boolean", default : "not boolean")
12. Аргумент argv должен быть объявлен с типом char *argv[]. Аргументы командной строки хранятся в виде строк, поэтому сначала программа должна преобразовать строку, хранящуюся в элементе массива argv[l], в значение типа double — например, с помощью функции atof() из библиотеки stdlib.h. Чтобы можно было использовать функцию sqrt(), в программу потребуется включить заголовочный файл math.h. Прежде чем извлекать квадратный корень, программа должна выполнить проверку на предмет передачи отрицательных значений.
13. а. Вызов функции должен выглядеть следующим образом:
qsort( (void *)scores, (size t) 1000, sizeof (double), comp);
б. Ниже показано подходящее определение функции сравнения:
int comp(const void * p1, const void * p2)
{
/* Для получения доступа к значениям необходимо */
/* использовать указатели на константу int */
/* Приведения типов не обязательны в С, */
/* но обязательны в C++ */
const int * al = (const int *) p1; const int * a2 = (const int *) p2;
if (*al > * a 2) return -1;
else if (*al = *a2) return 0; else
return 1;
}
14. а. Вызов функции должен выглядеть примерно так:
memcpy(datal, data2, 100 * sizeof(double));
Читать дальше