Сборник задач и упражнений по языку Си. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Сборник задач и упражнений по языку Си.



Руденко Т.В.

 

 

Сборник задач и упражнений по языку Си.

 

 

(учебное пособие для студентов II курса)

 

Москва

1999

УДК 519.682

 

 

Представлены задачи и упражнения по языку Си и программированию на нем. Рассматриваемая версия Си соответствует международному и ANSI-стандарту этого языка.

 

Сборник составлен как дополнение к учебнику Б. Кернигана, Д. Ритчи «Язык программирования Си» (М., «Финансы и статистика», 1992) и с учетом опыта преподавания программирования на факультете вычислительной математики и кибернетики МГУ.

 

Для студентов факультета ВМК в поддержку основного лекционного курса “Системное программное обеспечение” и для преподавателей, ведущих практические занятия по этому курсу.

 

Автор выражает благодарность сотрудникам кафедры алгоритмических языков за помощь и поддержку при создании этого сборника.

 

Рецензенты:

доц. Машечкин И.В.

доц. Терехин А.Н.

 

 

Руденко Т.В. “Сборник задач и упражнений по языку Си (учебное пособие для студентов II курса)”.

 

Издательский отдел факультета ВМиК МГУ

(лицензия ЛР №040777 от 23.07.96), 1999.-80 с.

 

Печатается по решению Редакционно-издательского Совета факультета вычислительной математики и кибернетики МГУ им. М.В. Ломоносова

 

ISBN 5-89407-048-1

 

Ó Издательский отдел факультета вычислительной математики и кибернетики МГУ им. М.В.Ломоносова, 1999


ПРЕДИСЛОВИЕ

 

Сборник задач составлен как дополнение к учебнику Б. Кернигана и Д. Ритчи «Язык программирования Си» [1], поэтому в нем сохранен такой же порядок разделов. Однако предполагается, что некоторое минимальное представление о структуре программы на Си и простейшем вводе-выводе у читателя имеется (в объеме разделов 1.7 и 1.8 первой главы учебника по Си [1]). Сборник может быть использован и независимо от учебника Б. Кернигана и Д. Ритчи; рассматриваемая версия Си соответствует стандарту ANSI (X3.159 - 1989) [2].

Кроме того, в сборнике приведено краткое описание заданий практикума, которые рекомендуется выполнить для закрепления пройденного материала и получения навыков в написании законченных программ.

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

 

ТИПЫ, ОПЕРАЦИИ, ВЫРАЖЕНИЯ

 

2.1. Верно ли записаны константы, представляющие целочисленные значения? Для верно записанных констант определить их значение, тип.

123 1E6 123456789LU -5 0XFUL

‘0’ 058 ‘\x7’ 0X-1AD ‘\122’

00123 0xffffffL 01A -‘x’ ²x²

‘a’U 0731UL ‘\n’ +0xaf 0X0

 

2.2. Верно ли записаны константы с плавающей точкой? Для верно записанных констант определить их значение, тип.

1.71 1E-6 0.314159E1F.005 0051E-04

5.E+2 0e0 0x1A1.5 05.5 0

0X1E6 0F 1234.56789L 1.0E-10D 3.1415U

1e-2f -12.3E-6 +10e6 123456L E-6

 

2.3. Верно ли записаны выражения? Для верно записанных выражений вычислить их значения (операции + - * / % =):

int a, b, c, d, e;

a = 2; b = 13; c = 7; d = 19; e = -4;

b / a / c d / a % c c % d-e -e % a + b / a *-5+5

b % e 7-d%+(3-a) b % - e * c 9 / c - - 20 / d

 

2.4. Верно ли решена задача: «значение целочисленной переменной с увеличить на 1; целочисленной переменной а присвоить значение, равное удвоенному значению переменной с».

int a, c; c = 5;

a). c ++; b). a = 2 * c++; c). c += 1; d). a = c++ + c;

a = 2 * c; a = c + c;

 

e). ++c; f). a = ++ c + c; g). a = c += 1 + c; h). a = (c+=1)+c;

a = c + c;

 

2.5. Верно ли решена задача: «значение целочисленной переменной с уменьшить на 1; целочисленной переменной а присвоить значение, равное частному от деления переменной с на 2».

int a, c; c = 5;

a). -- c; b). a = -- c / 2; c). c -= 1; d). a = c -- / 2;

a = c / 2; a = c % 2;

 

e). a = c -= 1/2; f). a = (c = c - 1)/2; g). a = (c -= 1)/2; h). a=(c-= 1)/2.0;

 

2.6. Эквивалентны ли выражения?

a) E1 op= E2 и E1 = E1 op E2

b) E1 op= E2 и E1 = E1 op (E2)

Замечание: здесь E1, E2 - выражения допустимого в этом случае типа; op - операция (одна из + - * / % >> << & ^ |).

 

2.7. Верно ли записаны выражения? Для верно записанных выражений вычислить их значения (операции + - * / ++ - - операции присваивания):

int a, b, c; a = 2; b = 6; c = 3;

- - - a -- - a b-- - a a += a ++ ++ b / a ++ * --c

a --- b - a-- -b a ++ = b a = a ++ b++ / ++a * c --

- --a a- --c a ++ = a ++ a = b a = (b + 1) ++

 

2.8. Верно ли записаны выражения? Для верно записанных выражений вычислить их значения, определить тип результата (операции + - * / % ++ операции отношения, операции присваивания):

int i, j, k, m; char c, d; i = 1; j = 2; k = -7; m = 0; c = ‘w’;

d = ’a’+1 < c m = - i - 5 * j >= k+1 i + j++ + k = = -2*j

m = 3 < j < 5 m = 3 = = j < 5 m = = c = ’w’

m = c!= 87 m = c =! 87 m =! c = 87

m =!c+87! m = =c + 87 m! = c + 87

k = = j - 9 = = i k *= 3 + j i + j =!k

i += ++ j + 3 k %= m = 1 + n / 2 1 + 3 * n += 7 / 5

1 + 3 * (n += 7) / 5 c + i < c - ‘x’+10 i - k = = ‘0’+9 < 10

 

2.9. В логике справедливы утверждения:

not (not x) = x

x and true = x

Верны ли соответствующие утверждения для операций! и && в Си? Ответ обосновать.

 

2.10. При любом вещественном y > 0 x < x + y математически верно. Верно ли подобное утверждение для выражения на Си?

 

2.11. Написать эквивалентное выражение, не содержащее операции!

! (a>b)! (2*a == b+4)! (a<b && c<d)

! (a<2 || a>5)! (a<1 || b<2 && c<3)

 

2.12. Пусть

char c; short s; int i; unsigned u; signed char sc;

float f; double d; long lng; unsigned short us; long double ld;

Определить тип выражений:

c - s / i u * 3 - 3.0 * u - i u - us * i (sc + d) * ld

(5 * lng - ‘a’) * (s + u / 2) (f + 3) / (2.5f - s * 3.14)

 

2.13. Допустимо ли в Си? Если "да" - опишите семантику этих действий; если "нет" - объясните почему.

а). ... b). ...

int i; int a, b, m, n, z;

i = (1 || 2) % (1 | 2); m = n = 5;

printf (² i = %d\n², i); z = a = b = 0;

z--, (a = b) = z + (m!= n);

printf (²%d %d %d %d %d\n²,

a, b, m, n, z);

с). ... d). ...

int i = 1; double x = 1.9; int a;

i = i << i | i; double b = 3.7;

printf (² i = %d\n², i); a = b += (1 && 2 || 3)!= (int)x;

printf (²%f %d %f\n², x, a, b);

e). ... f).. ..

int x; int i, x, y; x = 5; y = 10; i = 15;

x = 5; ++ x =10; x = (y = 0, i = 1);

printf ("%d\n", x); printf("%d %d %d\n", i, x,y);

(x = y == 0), i=1;

printf("%d %d %d\n", i, x, y);

g). ... h). ...

int x, y; int x = 2, y, z;

x = 5; y = x && ++ x; x *= 3+2; x *= y = z = 4;

printf("%d %d\n", x, y); printf ("%d %d %d\n", x, y, z);

x = y == z; x == (y = z);

printf ("%d %d %d\n", x, y, z);

i). ... j). ...

int x = 2, y = 1, z = 0; int x = 03, y = 02, z = 01;

y = x && y || z; printf("%d\n", x | y & -z);

x = x ||!y && z; printf("%d\n", x ^ y & -z);

z = x / ++x; printf("%d\n", x & y && z);

printf(" %d %d %d\n", x, y, z); printf("%d\n", x<<3);

k). ... l). ...

int x, y, z; x = y = z = 1; int x, y, z, i; x = y = z = 1;

x += y += z; i = ++x || ++y && ++z;

printf("%d\n", x < y? y++: x++); printf("%d%d%d%d\n", x,y,z,i);

printf("%d\n", z+=x<y? ++x: y--); i = x++ <= --y || ++z >= i;

printf("%d %d %d\n", x, y, z); printf("%d%d%d%d\n", x,y,z,i);

printf("%d\n", z>=y && y>=x);

 

2.14. Что будет напечатано в результате выполнения следующего фрагмента программы?

...

double d; float f; long lng; int i; short s;

s = i = lng = f = d = 100/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

d = f = lng = i = s =100/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

s = i = lng = f = d = 1000000/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

d = f = lng = i = s =1000000/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

lng = s = f = i = d =100/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

f = s = d = lng = i = (double)100/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

s = i = lng = f = d = 100/(double)3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

f = s = d = lng = i = (double)100/3;

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

i = s = lng = d = f = (double)(100/3);

printf("s = %hd i = %d lng = %ld f = %f d = %f\n", s, i, lng, f, d);

 

2.15. Что будет напечатано в результате выполнения следующего фрагмента программы?

double d = 3.2, x; int i = 2, y;

x = (y = d / i) * 2; printf ("x = %f;y = %d\n", x, y);

x = (y = d / i) * 2; printf ("x = %d;y = %f\n", x, y);

y = (x = d / i) * 2; printf ("x = %f;y = %d\n", x, y);

y = d * (x = 2.5 / d); printf ("x = %f; y = %d\n", x, y);

x = d * (y = ((int)2.9 + 1.1) / d; printf ("x = %d y = %f\n", x, y);

 

2.16. Дано вещественное число x. Не пользуясь никакими операциями, кроме умножения, сложения и вычитания, вычислить

2x4-3x3+4x2-5x+6.

Разрешается использовать не более четырех умножений и четырех сложений и вычитаний.

 

2.17. Целой переменной k присвоить значение, равное третьей от конца цифре в записи целого положительного числа x.

 

2.18. Целой переменной k присвоить значение, равное сумме цифр в записи целого положительного трехзначного числа x.

 

2.19. Целой переменной k присвоить значение, равное первой цифре дробной части в записи вещественного положительного числа x.

 

2.20. Определить число, полученное выписыванием в обратном порядке цифр заданного целого трехзначного числа.

 

2.21. Идет n-ая секунда суток. Определить, сколько полных часов и полных минут прошло к этому моменту.

 

2.22. Дано вещественное число x. Не пользуясь никакими операциями, кроме умножения, получить

a) x21 за шесть операций

b) x3 и x10 за четыре операции

c) x5 и x13 за пять операций

d) x2, x5 и x17 за шесть операций

e) x4, x12 и x28 за шесть операций

 

2.23. Выражения, соединенные операциями && и ||, по правилам Си вычисляются слева направо; вычисления прекращаются, как только становится известна истинность или ложность результата. В других языках программирования, например в Паскале, вычисляются все части выражения в любом случае. Приведите «за» и «против» каждого из этих решений.

 

2.24. Почему в Си не допускается, чтобы один и тот же литерал-перечислитель входил в два различных перечислимых типа? Могут ли совпадать имена литералов-перечислителей и имена обычных переменных в одной области видимости? Могут ли разные литералы-перечислители иметь одинаковые значения?

 

2.25. «Упаковать» четыре символа в беззнаковое целое. Длина беззнакового целого равна 4.

 

2.26. «Распаковать» беззнаковое целое число в четыре символа. Длина беззнакового целого равна 4.

 

2.27. Заменить в целочисленной переменной x n бит, начиная с позиции p, n старшими инвертированными битами целочисленной переменной y.

 

2.28. Циклически сдвинуть значение целочисленной величины на n позиций вправо.

 

2.29. Циклически сдвинуть значение целочисленной величины на n позиций влево.

 

2.30. Выясните некоторые свойства и особенности поведения доступного Вам транслятора Си:

a) выяснить, сколько байт отведено для хранения данных типа short, int, long, float, double и long double;

b) выяснить способ представления типа char (signed- или unsigned- вариант);

c) проконтролировать, все ли способы записи констант допустимы:

· целых (обычная форма записи, u/U, l/L, их комбинации; запись констант в восьмеричной и шестнадцатиричной системах счисления)

· вещественных (обычная форма записи, в экспоненциальном виде, f/F, l/L, e/E)

· символьных (обычная форма записи, с помощью эскейп-последовательности) и строковых (в частности, происходит ли конкатенация рядом расположенных строковых констант)

d) выяснить, как упорядочены коды символов '0' - '9', 'a' - 'z', 'A' - 'Z', пробел (между собой и относительно друг друга);

e) проконтролировать, происходит ли инициализация переменных по умолчанию;

f) проверить, реагирует ли транслятор на попытку изменить константу;

g) исследовать особенности выполнения операции % с отрицательными операндами;

h) проверьте, действительно ли операции отношения == и!= имеют более низкий приоритет, чем все другие операции отношения;

i) проверьте, действительно ли выполняется правило "ленивых вычислений" выражений в Си, т.е. прекращается ли вычисление выражений с логическими операциями, если возможно "досрочно" установить значение результата;

j) проверьте, все ли виды операнда операции sizeof (X), определяемые стандартом для арифметических типов, допускаются компилятором; действительно ли выражение X не вычисляется.

 

УПРАВЛЕНИЕ

Обработка числовых данных

 

Замечание: при решении некоторых задач этого раздела необходимы минимальные знания о «стандартном» вводе и выводе целых и вещественных чисел.

 

3.17. Для данных чисел a, b и c определить, сколько корней имеет уравнение ax2+bx+c = 0, и распечатать их. Если уравнение имеет комплексные корни, то распечатать их в виде v ± iw.

 

3.18. Подсчитать количество натуральных чисел n (111 £ n £ 999), в записи которых есть две одинаковые цифры.

 

3.19. Подсчитать количество натуральных чисел n (102 £ n £ 987), в которых все три цифры различны.

 

3.20. Подсчитать количество натуральных чисел n (11 £ n £ 999), являющихся палиндромами, и распечатать их.

 

3.21. Подсчитать количество цифр в десятичной записи целого неотрицательного числа n.

 

3.22. Определить, верно ли, что куб суммы цифр натурального числа n равен n2.

 

3.23. Определить, является ли натуральное число n степенью числа 3.

 

3.24. Для данного вещественного числа a среди чисел 1, 1 + (1/2), 1 + (1/2) + (1/3),... найти первое, большее a.

 

3.25. Для данного вещественного положительного числа a найти наименьшее целое положительное n такое, что 1 + 1/2 +1/3+... + 1/n > a.

 

3.26. Даны натуральное число n и вещественное число x. Среди чисел exp(cos(x2k))sin(x3k) (k = 1, 2,..., n) найти ближайшее к какому-нибудь целому.

 

3.27. Дано натуральное число n. Найти значение числа, полученного следующим образом: из записи числа n выбросить цифры 0 и 5, оставив прежним порядок остальных цифр.

 

3.28. Дано натуральное число n. Получить все такие натуральные q, что n делится на q2 и не делится на q3.

 

3.29. Дано натуральное число n. Получить все его натуральные делители.

 

3.30. Дано целое число m > 1.Получить наибольшее целое k, при котором 4k < m.

 

3.31. Дано натуральное число n. Получить наименьшее число вида 2r, превосходящее n.

 

3.32. Распечатать первые n простых чисел (p - простое число, если
p >= 2 и делится только на 1 и на себя).

 

3.33. Даны вещественные числа x и y (x > 0, y > 1). Получить целое число k (положительное, отрицательное или равное нулю), удовлетворяющее условию yk-1 £ x < yk.

 

3.34. Распечатать первые n чисел Фибоначчи (f0 = 1; f1 = 1; fk+1 = fk-1+ fk;
k = 1, 2, 3,...)

 

3.35. Вычислить с точностью eps > 0 значение «золотого сечения» - 0.5*(1+Ö5) - предел последовательности { qi }при i ® ¥

qi = fi / fi-1, i = 2, 3,...где fi - числа Фибоначчи (см. предыдущую задачу).

Считать, что требуемая точность достигнута, если | qi-qi+1| < eps.

3.36. Распечатать числа Фибоначчи (см. задачу 3.34), являющиеся простыми числами со значениями меньше n.

 

3.37. Вычислить с точностью eps > 0 значение числа e - предел последовательности { xi }при i ® ¥

xi = (1+1/i)i, i = 1, 2,...

Считать, что требуемая точность достигнута, если | xi-xi+1| < eps.

 

3.38. Вычислить значение å i! для i, изменяющихся от 1 до n. Воспользоваться соотношением å i! = 1 + 1*2 + 1*2*3 +...+ 1*2*3*...*n = 1+2*(1+3*(1+ +n*(1)...)).

 

3.39. Пусть a0 и b0 - положительные вещественные числа. Соотношениями an+1 = Ö(anbn); bn+1 = (an+bn) / 2 при n = 0, 1, 2,... задаются две бесконечные числовые последовательности {an}и {bn}, которые сходятся к общему пределу M(a0,b0), называемому арифметико-геометрическим средним чисел a0 и b0. Найти приближенное значение M(a0,b0) с точностью eps > 0. Поскольку при
a0 < b0 ai < bi и, более того, a0 < a1 <... < ai <... bi <... < b1 < b0, то в качестве подходящего критерия прекращения вычислений можно использовать соотношение | ai - bi | < eps.

 

3.40. Вычислить квадратные корни вещественных чисел x = 2.0, 3.0,..., 100.0. Распечатать значения x, Öx, количество итераций, необходимых для вычисления корня с точностью eps > 0.

Для a > 0 величина Öa вычисляется следующим образом:

a0 = 1; ai+1 = 0.5*(ai+a/ai ) i = 0, 1, 2,...

Считать, что требуемая точность достигнута, если | ai-ai+1| < eps.

 

3.41. Найти приближенное значение числа p с точностью eps > 0. Для этого можно использовать представление числа 2/p в виде произведения корней Ö(1/2) *Ö(1/2+1/2Ö(1/2))*Ö(1/2+ 1/2Ö(1/2+1/2Ö(1/2)))*.... Вычисления прекращаются, когда два следующих друг за другом приближения для числа p будут отличаться меньше, чем на eps.

 

3.42. Для данного вещественного числа x и натурального n вычислить:

a) sin x + sin2x +... + sinnx

b) sin x + sinx2 +... + sinxn

c) sin x + sin(sin x) +... + sin (sin (... sin(sin x)...))

 

3.43. Алгоритм Евклида нахождения наибольшего общего делителя (НОД) неотрицательных целых чисел основан на следующих свойствах этой величины: пусть m и n - одновременно не равные нулю целые неотрицательные числа и m ³ n. Тогда, если n = 0, то НОД(n, m) = m, а если n ¹ 0, то для чисел m, n, и r, где r - остаток от деления m на n, выполняется равенство НОД(m, n) = НОД(n, r). Используя алгоритм Евклида, определить наибольший общий делитель неотрицательных целых чисел a и b.

 

3.44. Вычислить 1 - 1/2 + 1/3 - 1/4 +...+1/9999 - 1/10000 следующими способами:

a). последовательно слева направо;

b). последовательно справа налево;

c). последовательно слева направо вычисляются 1 +1/3 + 1/5 +... + 1/9999 и 1/2 + 1/4 +... + 1/10000, затем второе значение вычитается из первого;

d). последовательно справа налево вычисляются 1 +1/3 + 1/5 +... + 1/9999 и 1/2 + 1/4 +... + 1/10000, затем второе значение вычитается из первого.

Сравнить и объяснить полученные результаты.

 

3.45. Натуральное число называется совершенным, если оно равно сумме всех своих делителей, за исключением самого себя. Дано натуральное чис-
ло n. Получить все совершенные числа, меньшие n.

 

3.46. Определить, является ли число простых чисел, меньших 10000, простым числом.

 

3.47. Если p и q - простые числа и q = p+2, то они называются простыми сдвоенными числами или “близнецами” (twin primes). Например, 3 и 5 - такие простые числа. Распечатать все простые сдвоенные числа, меньшие N.

 

Обработка символьных данных

 

Замечание: при решении некоторых задач этого раздела необходимы минимальные знания о «стандартном» вводе и выводе литер.

 

3.48. Пусть во входном потоке находится последовательность литер, заканчивающаяся точкой (кодировка ASCII):

a) определить, сколько раз в этой последовательности встречается символ ‘a’;

b) определить, сколько символов ‘e’ предшествует первому вхождению символа ‘u’ (либо сколько всего символов ‘e’ в этой последовательности, если она не содержит символа ‘u’);

c) выяснить, есть ли в данной последовательности хотя бы одна пара символов-соседей ‘n’ и ‘o’, т.е. образующих сочетание ‘n’ ‘o’ либо ‘o’ ‘n’;

d) выяснить, чередуются ли в данной последовательности символы ‘+’ и ‘-‘, и сколько раз каждый из этих символов входит в эту последовательность;

e) выяснить, сколько раз в данную последовательность входит группа подряд идущих символов, образующих слово С++;

f) выяснить, есть ли среди символов этой последовательности символы, образующие слово char;

g) выяснить, есть ли в данной последовательности фрагмент из подряд идущих литер, образующий начало латинского алфавита (строчные буквы), и какова его длина. Если таких фрагментов несколько, найти длину наибольшего из них. Если такого фрагмента нет, то считать длину равной нулю;

h) выяснить, есть ли в данной последовательности фрагменты из подряд идущих цифр, изображающие целые числа без знака. Найти значение наибольшего из этих чисел. Если в этой последовательности нет ни одной цифры, то считать, что это значение равно нулю;

i) определить, имеет ли данная последовательность символов структуру, которая может быть описана с помощью следующих правил:

последовательность::= слагаемое + последовательность | слагаемое

слагаемое::= идентификатор | целое

идентификатор::= буква | идентификатор буква | идентификатор цифра

буква::= A | B | C | D | E | F | G | H | I | J | K

цифра::= 0 | 1 | 2 | 3 | 4 | 5

целое::= цифра | целое цифра

 

3.49. Пусть во входном потоке находится последовательность литер, заканчивающаяся точкой (кодировка ASCII). Вывести в выходной поток последовательность литер, измененную следующим образом:

a) заменить все символы ‘?’ на’!’;

b) удалить все символы ‘-‘ и удвоить все символы ‘&’;

c) удалить все символы, не являющиеся строчными латинскими буквами;

d) заменить все прописные латинские буквы строчными (другие символы копировать в выходной поток без изменения);

e) заменить все строчные латинские буквы прописными (другие символы копировать в выходной поток без изменения);

f) каждую группу рядом стоящих символов ‘+’ заменить одним таким символом;

g) каждую группу из n рядом стоящих символов ‘*’ заменить группой из n/2 рядом стоящих символов ‘+’ (n >= 2); одиночные ‘*’ копировать в выходной поток без изменения;

h) удалить из каждой группы подряд идущих цифр все начальные незначащие нули (если группа состоит только из нулей, то заменить эту группу одним нулем);

i) удалить все комбинации символов the;

j) оставить только те группы цифр, которые составлены из подряд идущих цифр с возрастающими значениями; все остальные цифры и группы цифр удалить (другие символы копировать в выходной поток без изменения);

k) заменить все комбинации символов child комбинациями символов children;

l) удалить группы символов, расположенные между фигурными скобками { и }. Скобки тоже должны быть удалены. Предполагается, что скобки сбалансированы, и внутри каждой пары скобок других фигурных скобок нет.

 

3.50. Пусть во входном потоке находится последовательность литер, заканчивающаяся маркером конца $ (кодировка ASCII). Вывести в выходной поток последовательность литер, измененную следующим образом:

a) удалить из каждой группы подряд идущих цифр, в которой более двух цифр и которой предшествует точка, все цифры, начиная с третьей (например, a+12.3456-b-0.456789+1.3-45678 преобразуется в a+12.34-b-0.45+1.3-45678);

b) удалить из каждой группы цифр, которой не предшествует точка, все начальные нули (кроме последнего, если за ним идет точка либо в этой группе нет других цифр, кроме нулей; например, a-000123+bc+0000.0008-0000+0001.07 преобразуется в a-123+bc+0.0008-0+1.07).

 

 

УКАЗАТЕЛИ И МАССИВЫ

 

5.1. Допустимо ли в Си? Если "да" - опишите семантику каждого правильного действия (не принимая во внимание ошибочные); если "нет" - объясните почему.

a). ...

int i,* p, j, *q;

p = &i; q = &p;

j = *p = 1; q = p-1; *p += 1;

i = *++q + *p; q -= 1; i = *q ++ + *q;

printf("i=%d, j=%d, *p=%d, *q=%d \n", i, j, *p, *q);

b) ...

int x = 1, y; char c = ‘a’;

int *pi, *qi; char *pc;

pi = &x; *pi = 3; y = *pi; *pi = c; qi = pi;

pc = qi; *qi+=1; pi++; *(- - pi) = 5; y = *qi+1;

pc = &c; ++*pc; (*pc)++; *pc++; *pc+=1;

x = (int)pi; pi=(int*)pc; pi=(int*)x; x = 1+ *pi; pc=(char*)pi;

c = *pc; pc = &y; x = qi – pi; qi = 0; qi+=pi;

y = &pi; y = (int)&pi; pi = pi +5; *(pi+1)=0; pi=&(x+0);

 

5.2. К любому ли объекту в Си можно применять операцию взятия адреса &?

5. 3. Допустимо ли в Си? Если "да" - опишите семантику этих действий; если "нет" - объясните почему.

a) int i = 2; const int j = 5;

int *pi;

const int *pci;

int *const cpi;

const int * const cpci;

pi = &i; pci = &j; cpi = &i; cpci = &j; pci = &i;

pi = (int*)&j; i = *pci + *pi; *pci = 3;

*pi = 3; i=*pci++; *(cpi++)=5; *cpi++;

b) int f(const int i, int j) { j++; return i+j; }

main()

{ int a, b; const int c = 5;

scanf("%d", &a);

b = f(c,a); printf("a=%d, b=%d, c=%d \n", a, b, c);

b = f(c,c); printf("a=%d, b=%d, c=%d \n", a, b, c);

b = f(a,a); printf("a=%d, b=%d, c=%d \n", a, b, c);

b = f(a,c); printf("a=%d, b=%d, c=%d \n", a, b, c);

}

 

5.4. Пусть целочисленный массив a соддержит 100 элементов. Верно ли решена задача: "написать фрагмент программы, выполняющий суммирование всех элементов массива a".

a) int a[100], sum, i;

sum = 0;

for (i = 0; i < 100; ++i) sum += a[i];

b) int a[100], *p, sum;

sum = 0;

for (p = a; p < &a[100]; ++p) sum = sum + *p;

c) int a[100], *p, sum;

sum = 0;

for (p = &a[0]; p < &a[100]; p++) sum += *p;

d) int a[100], sum, i;

sum = 0;

for (i = 0; i < 100; ++i) sum += *(a+i);

e) int a[100], sum, i;

sum = 0;

for (i = 0; i < 100; ++a, ++i) sum += *a;

f) int a[100], *p, sum, i;

sum = 0;

for (i = 0, p = a; i < 100; ++i) sum += p[i];

g) int a[100], *p, sum, i;

sum = 0;

for (i = 0, p = a; i < 100; ++i) sum += *(p+i);

 

5.5. Допустимо ли в Си? Если "да" - опишите семантику каждого правильного действия (не принимая во внимание ошибочные); если "нет" - объясните почему.

a) ...

int a[5] = { 1, 2, 3, 4, 5 };

int *p, x, *q, i;

p = a + 2; * (p+2) = 7;

*a += 3; q=*&p-1;

x = ++ p - q ++; x += ++ *p; x=*p-- + *p++;

for (i = 0; i < 5; i++) printf("a [%d]=%d", i, a[ i ]); printf("\n");

printf("x=%d, *p=%d, *q=%d \n", x, *p, *q);

b) ...

char *str = "abcdef";

char *p, *q, *r; int k;

p = str; q = 0; p++;

k = p - str; r = p+k;

if (k && p || q) q = str + 6;

p = q? r: q; *(p-1) = ‘a’; *r = ‘x’;

printf("str: %s\n", str);

c) ...

char s[ ] = "0123456";

int *pi; char *pc1, *pc2;

pc2 = s;

pc1 = s + *(s+strlen(s) - 1) - ‘0’;

pi = (int*) pc2; *pc1-- = ‘8’;

if (pc1 - pc2 < 3) pc1 = pc2 = pi; else pc1 = (pc1+pc2)/2;

if (s == pc2) *pc1 = *pc2 + 1; else *pc1 = ‘9’;

printf("s: %s\n", s);

d) ...

int i; char *c; int *pi;

i = ‘a’;

pi = &i; c = (char*)pi + 3; printf("c1=%c", *c);

i <<= 8; c--; printf("c2=%c\n", *c);

e) ...

char c1, c2; short i;

char *pc; short *ps;

c1 = ‘1’; c2 = ‘2’; ps =&i;

pc = (char*)ps; *pc = c1; pc++; *pc = c2;

printf("i = %hd\n", i);

 

5.6. Эквивалентны ли следующие фрагменты программы на Си?

a[ i ] /= k+m и a[ i ] = a[ i ]/k+m

a[ i ] /= k+m и a[ i ] = a[ i ]/(k+m)

a[ i++]+=3 и a[i++] = a[ i++]+3

a[ i++]+=3 и a[ i ] = a[ i++]+3

a[ i++]+=3 и a[ i++ ] = a[ i ]+3

a[ i++]+=3 и a[ i ] = a[ i ]+3; i++;

 

5.7. Что напечатает следующая программа?

#include <stdio.h>

char str[ ] = "SSSWILTECH1\1\11W\1WALLMP1";

main()

{ int i, c;

for (i = 2; (c = str [ i ])!= ‘\0’; i++) {

switch (c) {

case ‘a’: putchar(‘i’); continue;

case ‘1’: break;

case 1: while ((c = str [++ i ])!= ‘\1’ && c!= ‘\0’);

case 9: putchar(‘S’);

case ‘E’: case ‘L’: continue;

default: putchar(c); continue; }

putchar(‘ ’); }

putchar(‘\n’);

}

5.8. Что напечатает следующая программа?

#include <stdio.h>

int a[ ] = { 0, 1, 2, 3, 4 };

main()

{ int i, *p;

for (i = 0; i <= 4; i++) printf("a[ i ]=%d ", a[ i ]); printf("\n");

for (p = &a[0]; p <= &a[4]; p++) printf("*p=%d ", *p); printf("\n");

for (p = &a[0], i = 0; i <= 4; i++) printf("p[ i ]=%d ", p[ i ]); printf("\n");

for (p = a, i = 0; p+i <= a+4; i++) printf("* (p+i)=%d ", * (p+i));

printf("\n");

for (p = a+4; p >= a; p--) printf("*p=%d ", *p); printf("\n");

for (p = a+4, i=0; i <= 4; i++) printf("p[ -i ]=%d ", p[ -i ]);

printf("\n");

for (p = a+4; p >= a; p --) printf("a[ p - a ]=%d ", a[ p - a ]);

printf("\n");

}

 

5.9. Что напечатает следующая программа?

#include <stdio.h>

int a[ ] = { 8, 7, 6, 5, 4 };

int *p[ ] = { a, a+1, a+2, a+3, a+4 };

int **pp = p;

main()

{ printf("*a=%d **p=%d **pp=%d\n", *a, **p, **pp);

pp++;

printf("pp-p=%d *pp-a=%d **pp=%d\n", pp-p, *pp-a, **pp);

++*pp;

printf("pp-p=%d *pp-a=%d **pp=%d\n", pp-p, *pp-a, **pp);

pp = p;

++**pp;

printf("pp-p=%d *pp-a=%d **pp=%d\n", pp-p, *pp-a, **pp);

}

 

5.10. Что напечатает следующая программа?

#include <stdio.h>

int a[ 3 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

int *pa[ 3 ] = { a[ 0 ], a[ 1 ], a[ 2 ] };

int *p = a[ 0 ];

main()

{ int i;

for (i = 0; i < 3; i ++)

printf(" a[ i ][ 2 – i ]=%d *a[ i ]=%d *(*(a+i)+i)=%d\n",

a[ i ][ 2 – i ], *a[ i ], *(*(a+i)+i));

for (i = 0; i < 3; i ++)

printf("*pa[ i ]=%d p[ i ]=%d \n", *pa[ i ], p[ i ]);

}

 

5.11. Что напечатает следующая программа?

#include <stdio.h>

char *c[ ] = { "ENTER", "NEW", "POINT", "FIRST" };

char ** cp[ ] = { c+3, c+2, c+1, c };

char ***cpp=cp;

main()

{ printf("%s", **++cpp);

printf("%s ", * -- *++cpp+3);

printf("%s", *cpp[ -2 ]+3);

printf("%s\n", cpp[ -1 ][ -1 ]+1);

}

 

5.12. Какие соглашения о конце строки существуют в Си и Паскале? Укажите все «за» и «против» явного указания концов строк с помощью null-литеры ‘\0’.

 

5.13. В чем заключается проблема «висящей» ссылки? Приведите примеры.

5.14. Нужна ли в Си «сборка мусора»? Почему возникает такая проблема и как она решается в Си?

 

5.15. Прочитайте следующие описания и определения:

int *ip, f(), *fip(), (*pfi)(); char *str[10]; char * (*cp)[5];

int (*r) (); double (*k)(double,int*);

float * (* (*x) [6])(); double (* (* (y())[ ])();

int * (*const *name[9])(void); char * const p;

 

5.16. Определите переменную x как массив указателей на функцию, имеющую два параметра типа int и возвращающую результат типа указатель на double.

5.17. Определите переменную y как указатель на массив указателей на функцию без параметров, возвращающую результат типа указатель на функцию с одним параметром типа int и результатом типа float.

 

5.18. Что будет напечатано? Объяснить, почему результат будет таким.

a) #include <stdio.h> b) #include <stdio.h>

int try_to_change_it(int); void compare (int, int *);

main() main()

{ int i = 4, j; { int i = 4, j = 5;

j = try_to_change_it(i); compare(i, &j);

printf("i=%d, j=%d\n", i, j); printf("i=%d, j=%d\n", i, j);

} }

int try_to_change_it(int k) void compare (int k, int *m)

{ printf("k1=%d\n", k); { printf("k1=%d,*m1=%d\n",k, *m);

k+=33; k++; (*m)++;

printf("k2=%d\n", k); printf("k2=%d,*m2=%d\n", k, *m);

return k; }

}

5.19. Верно ли решена задача: «Описать функцию, меняющую местами значения двух переменных символьного типа. Использовать эту функцию для изменения значений символьных переменных a и b.»

a) void swap (char x, char y) b) void swap (char *x, char *y)

{ char t; t = x; x = y; y = t;} { char *t; t = x; x = y; y = t;}

main() main()

{ char a,b; { char a,b;

scanf("%c%c", &a, &b); scanf("%c%c", &a, &b);

swap(a,b); swap(&a, &b);

printf("a=%c,b=%c\n",a,b); printf("a=%c,b=%c\n",a,b);

} }

c) void swap (char *x, char *y) d) void swap (char *x, char *y)

{ char t; t = *x; *x = *y; *y = t;} { char t; t = *x; *x = *y; *y = t;}

main() main()

{ char a,b; { char a,b;

scanf("%c%c", &a, &b); scanf("%c%c", &a, &b);

swap(a,b); swap(&a, &b);

printf("a=%c,b=%c\n",a,b); printf("a=%c,b=%c\n",a,b);

} }

e) void swap (char x, char y) f) void swap (char &x, char &y)

{ char *t; t = &x; &x = &y; &y = t;} { char t; t = x; x = y; y = t;}

main() main()

{ char a,b; { char a,b;

scanf("%c%c", &a, &b); scanf("%c%c", &a, &b);

swap(&a, &b); swap(a, b);

printf("a=%c,b=%c\n",a,b); printf("a=%c,b=%c\n",a,b);

} }

 

5.20. Допустимо ли в Си? Если "да" - опишите семантику этих действий; если "нет" - объясните почему.

int ques (char *s1, char *s2)

{ while (*s1 && *s2 && *s1++ == *s2++);

return *--s1 - *--s2;

}

 

5.21. Допустимо ли в Си? Если "да" - опишите семантику этих действий; если "нет" - объясните почему.

void ques (char *s1, char *s2, int n)

{ while (*s1 && *s2 && n-- && (*s1 ++ = *s2 ++)); }

 

5.22. Описать функцию, определяющую упорядочены ли строго по возрастанию элементы целочисленного массива из n элементов.

 

5.23. Описать функцию, определяющую индекс первого элемента целочисленного массива из n элементов, значение которого равно заданному числу x. Если такого элемента в массиве нет, то считать номер равным –1.

 

5.24. Описать функцию, вычисляющую значение x0 + x0*x1 + x0*x1*x2 + …+ x0*x1*x2 *… *xm, где xi - элементы вещественного массива x из n элементов, m - индекс первого отрицательного элемента этого массива либо число n-1, если такого элемента в массиве нет.

 

5.25. Описать функцию, вычисляющую значение max(x0 + xn-1, x1 + xn-2, x2 + xn-3,…, x(n-1)/2 + xn/2), где xi - элементы вещественного массива x из n элементов.

 

5.26. Описать функцию, вычисляющую значение min(x0 * x1, x1 * x2,
x2 * x3,…, xn-3 * xn-2, xn-2 * xn-1), где xi - элементы вещественного массива x из n элементов.

 

5.27. Описать функцию, вычисляющую значение x0*y0+x1*y1+ …+ xk*yk, где xi – отрицательные элементы вещественного массива a из n элементов, взятые в порядке их следования; yi – положительные элементы этого массива, взятые в обратном порядке; k = min(p,q), где p – количество положительных элементов массива a, q – количество отрицательных элементов этого массива.

 

5.28. Описать функцию, которая упорядочивает элементы целочисленного массива по неубыванию, используя следующий алгоритм сортировки:

a) сортировка выбором: находится максимальный элемент массива и переносится в его конец; затем этот метод применяется ко всем элементам массива, кроме последнего (т.к. он уже находится на своем месте), и т.д.

b) сортировка обменом (метод пузырька): последовательно сравни-ваются пары соседних элементов xk и x k+1 (k = 0, 1, …,n-2) и, если xk > x k+1, то они переставляются; в результате наибольший элемент окажется на своем месте в конце массива; затем этот метод применяется ко всем элементам, кроме последнего, и т.д.

c) сортировка вставками: пусть первые k элементов массива (от 0 до
k-1) уже упорядочены по неубыванию; тогда берется xk и рaзмещается среди первых k элементов так, чтобы упорядоченными оказались уже k+1 первых элементов; этот метод повторяется при k от 1 до n-1.

 

5.29. Описать функцию, определяющую индекс первого элемента целочисленного массива из n элементов, значение которого равно заданному числу x. Если такого элемента в массиве нет, то считать номер равным –1. Элементы массива упорядочены по возрастанию; использовать метод двоичного (бинарного) поиска.

 

5.30. Программа. Описать функцию f(a, n, p), определяющую, чередуются ли положительные и отрицательные элементы в целочисленном массиве a из n элементов и вычисляющую целочисленное значение p. Если элементы чередуются, то p - это сумма положительных элементов, иначе p - это произведение отрицательных элементов. С помощью этой функции провести анализ целочисленного массива x [50].

 

5.31. Программа. Описать функцию f(a, n, p), определяющую, упорядочены ли строго по возрастанию элементы в целочисленном массиве a из n элементов, и вычисляющую целочисленное значение p. Если элементы упорядочены, то p - это произведение разностей рядом стоящих элементов, иначе p - это количество нарушений порядка в массиве a. С помощью этой функции провести анализ целочисленного массива b [60].

 

5.32. Программа. Описать функцию f (s, n, x), определяющую, какой символ чаще других встречается в строке s и сколько раз он в нее входит. Если таких символов несколько, то взять первый из них по алфавиту. С помощью этой функции провести анализ строки str.

 

5.33. Программа. Описать функцию f(s, n, x), определяющую, какой символ реже других (но не нуль раз) встречается в строке s и сколько раз он в нее входит. Если таких символов несколько, то взять первый из них по алфавиту. С помощью этой функции провести анализ строки str.

 

5.34. Программа. Для целочисленного массива а, содержащего n элементов, описать функцию f(a, n, last, k, nlast), определяющую last - значение последнего из элементов массива а, значение которого принадлежит диапазону
[-k, k], и nlast - индекс этого элемента. С помощью этой функции вычислить соответствующие значения last и nlast для целочисленных массивов x[20] и y[30].

 

5.35. Программа. Для вещественного массива а, содержащего n элементов, описать функцию G, определяющую значения максимального и минимального элементов этого массива. С помощью этой функции для вещественных массивов x[25] и y[40] вычислить соответствующие значения.

 

5.36. Описать функцию, которая изменяет заданную строку следующим образом: сначала записывает все элементы с четными индексами, а затем все элементы с нечетными индексами (с сохранением их относительного порядка в каждой группе).

Например, abcdefgh => acegbdfh, vwxyz => vxzwy.

 

5.37. Описать функцию, которая в заданной строке меняет местами ее первую и вторую половины.

Например, abcdefgh => efghabcd, vwxyz => yzxvw.

 

5.38. Описать функцию, осуществляющую циклический сдвиг на n позиций вправо элементов целочисленного массива, содержащего m элементов (n<m).

5.39. Описать функцию, осуществляющую циклический сдвиг на n позиций влево элементов целочисленного массива, содержащего m элементов (n<m).

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

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



Поделиться:


Последнее изменение этой страницы: 2017-02-05; просмотров: 1341; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.142.197.198 (0.445 с.)