Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы программирования на языке С. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
и месяца рождения человека равна 3, то основным его качеством будет ум, 4 – красота, 5 – доброта, 6 – энергичность, 7 – скромность, в противном случае трудно выделить основное качество.
6. Определить, каким является для человечества введенный год. Год
считается счастливым, если остаток от деления суммы его двух последних цифр на 7 равен 0, удачным – 1, неудачным – 2, несчастным – 3, обычным – в остальных случаях
.
7. Дано двузначное число. Подсчитать сумму цифр этого числа
и напечатать название числа этой суммы, если оно меньше 10. Например, при вводе числа 34 должно быть выдано сообщение: «сумма цифр числа равна семи», при вводе числа 91 – «сумма цифр числа больше девяти».
8. По введенному с клавиатуры символу (! ? : ; , . – ) напечатать
название знака препинания или выдать
сообщение, что введен не знак пре-
пинания.
9. Написать программу, выводящую на экран строку «switch» при вводе числа 1, строку «конструкции switch» – при вводе числа 2, «пример конструкции switch» – при вводе числа 3, «просто пример конструкции switch» – при вводе числа 4 и «Это просто пример конструкции switch» – при вводе числа 5. В противном случае вывести на экран сообщение «Вве­ден неверный
код строки».
10. Напишите программу, запрашивающую с клавиатуры номер ме-
сяца и выводящую на экран его название. Если введено число больше 12, то выдается соответствующее сообщение.
11. Напишите программу, запрашивающую ввод с клавиатуры любой десятичной цифры и выводящую на экран название ближайшей нечетной десятичной цифры не меньше заданной. Если была введена не
цифра, то
выдается сообщение об ошибке.
12. Введите с клавиатуры 7 слов. Затем по введенной цифре опреде­лите, существует ли слово с таким порядковым номером, и, если суще­ствует, выведите его на экран. Например, если набраны слова «один два три четыре пять шесть семь», то при нажатии клавиши 5 на экран должно быть
выведено слово «пять».
31
6. КОНСТРУКЦИИ ЦИКЛА
И ПЕРЕДАЧИ УПРАВЛЕНИЯ
Операторы цикла задают многократное исполнение операторов тела
цикла. Определены три разных оператора цикла:
цикл с предусловием
while (выражение_условие) тело_цикла;
цикл с постусловием
do тело_цикла while (выражение_условие)
цикл for
for (инициализация_цикла; выражение_условие; спи-
сок_выражений) тело_цикла
Тело_цикла не может быть описанием, это либо один (может быть и пустой) оператор, который всегда завершается точкой с запятой, либо блок операторов, заключенных в скобки {}. Выражение_условие – это выражение, определяющее условие продолжения итераций. Операторы те­ла цикла выполняются, пока условие истинно (не равно нулю). Инициали-
зация_цикла в цикле for – это
последовательность определений и выра-
жений, разделяемых запятыми. Даже если она пустая, точка с запятой должна присутствовать. Чаще всего здесь устанавливаются начальные зна­чения счетчиков и параметров цикла. Выражения из списка_выражений выполняются после выполнения операторов тела цикла и до следующей проверки выражения_условия.
Приведем примеры, иллюстрирующие разные решения задачи нахождения
for (int i=1,s=0;i<=k; i++) s+=i*i;
for (int i=0,s=0;i<=k; s+=++i*i);// тело цикла – пустой оператор;
for (int i=0,s=0;i<=k) s+=++i*i; //отсутствует список выражений;
for (int i=0,s=0;i<=k ) {int j; j=++i; s+=j*j;}
суммы s квадратов первых k членов натурального ряда.
Конструкцию for чаще применяют для организации детерминиро­ванных циклов, то есть циклов, число повторений которых заранее опреде­лено. А конструкции do и while чаще применяют для итерационных цик­лов, то есть циклов, число повторений которых зависит от выполнения условий, изменяющихся в теле цикла, и заранее не определено. Хотя такое функциональное разделение довольно условно.
Каждый
цикл может содержать вложенные циклы. Для принуди­тельного выхода из цикла используется оператор break. Необходимость в его использовании возникает, когда условия продолжения итераций надо проверять не только в начале или конце итерации, но и в середине тела цикла. Например, если начальные значения переменных i,j таковы, что i<j, то следующий цикл определяет наименьшее
целое, не меньшее их средне-
го арифметического.
32
while (i<j) { i++; if (i==j) break; j––; }
Для i=0, j=3 результат i=j=2 достигается при выходе из цикла с по­мощью оператора break, а для i=0, j=2 результат i=j=1 достигается при естественном завершении цикла.
Циклические конструкции чаще всего применяют для ввода значе­ний элементов массива. Массив – это именованная совокупность элемен­тов одного типа, расположенных в памяти компьютера последовательно. Описание массива имеет два формата:
тип идентификатор[размерность];
или
тип идентификатор [размерность]={элемент1, элемент2,…};
Размерность – это константное выражение целого типа, обозначаю­щее количество элементов в массиве. Если в первом случая описания раз­мерность необходимо указывать, то во втором его указание не обязатель­но. Когда массив объявлен без указания размерности, но при этом инициа­лизирован списком, его размерность вычисляется путем подсчета числа элементов этого списка. Явная
инициализация массива разрешена только при его определении и возможна двумя способами: либо с указанием раз­мера массива в квадратных скобках, либо без его явного указания, напри­мер,
int а[6]={1,2,3,4};//массив из 6 целых чисел с инициализа-
цией
//первых четырех char str[]={‘a’, ‘b’, ‘c’};// массив из 3 элементов типа
char
Рекомендуется задавать размерность массива не как числовую, а как именованную константу. Например, запись const int n=5; int a[n]; предпо­чтительнее записи int a[5];.
Одним из способов доступа к элементам массива является использо­вание индексов. То есть, чтобы обратится к i-му элементу массива а, ис­пользуют запись а[i], при этом первый элемент массива имеет индекс 0. Например, ввод элементов массива
с клавиатуры можно реализовать сле-
дующим образом:
const int n=10;
int a[n];
for (int i=0;i<n;i++)
{
printf("\nЕnter a[%d%s",i, "] ");
scanf ("%d",&a[i]);
}
33
Если требуется сгенерировать элементы случайным образом, то используют функцию rand() из библиотеки stdlib.h. Данная функция воз­вращает случайное целое число в диапазоне от 0 до 255. Для того чтобы изменить этот диапазон на диапозон [0,k], можно взять остаток от деления результата функции rand() на k+1. Чтобы получить число в диапазоне от­рицательных чисел, можно использовать обычную операцию вычитания Например, сгенерировать элементы массива в диапазоне [0,40] можно сле­дующим образом:
const int n=10;
int a[n];
const int k=40;//граница диапазона [0,40]
for (int i=0;i<n;i++)
a[i]= rand()%(k+1) //генерируем массив случайных чи- сел
//в диапазоне [0..k]
Если в задаче указано, что размерность массива не превышает, например N=20, то можно задать эту размерность константой, а реальное количество обрабатываемых элементов n (n[0,N]) запросить у пользова­теля:
const int N=20; int a[N],n; do { printf("\nEnter n (1-%d%s",N,"): "); scanf("%d",&n); } while (n<=0 || n>N); // проверка корректности ввода
n[0,N]
К элементам массива можно обращаться также с помощью указате-
лей. Указатель – это переменная, значением которой является адрес участ­ка памяти, выделенной для объекта конкретного типа. В простейшем слу­чае описание указателя-переменной на некоторый объект имеет вид:
тип *имя_указателя инициализатор;
Например,
int *T; // неинициализированный указатель на объект типа
int,
//то есть в переменной T может храниться адрес объ-
екта типа int;
В качестве инициализирующего выражения указателя может исполь-
зоваться константное выражение, частными случаями которого являются явно заданный адрес участка памяти, указатель, уже имеющий значение, выражение, позволяющее получить адрес объекта с помощью операции ‘&’. Например,
char c1 = ‘a’; char* p = &c1;// в p хранится адрес переменной c1
.
34
Переменная, на которую указывает p – это c1, а значение, которое хранится в c1, это символ ‘a’. Основная операция над указателем – разы­менование, унарная операция ‘*’ (получение значения через указатель). Эта операция также называется косвенным обращением или обращением по адресу. Например, при выполнении оператора printf(“%c”, *p); на экран выведется значение того участка памяти, с которым связан указатель p, то есть
символ ‘a’.
Имя массива является указателем-константой на его первый элемент. То есть, если описан массив int a [n], то для обращения к его i-му элементу наряду с записью a[i], можно использовать запись *(a+i).
Например, пусть описан и инициализирован массив a.
const int n=5;
int a[n]={1,2,3,4,5};
Выведем его элементы на экран столбиком тремя способами:
a) int *p=a; for (int i=0;i<n;i++ ) printf("%d%s",*p++, "\n");
b) for (int i=0;i<n;i++ ) printf("%d%s",*(a+i), "\n");
c) for (int i=0;i<n;i++ ) printf("%d%s", a[i], "\n");
Чтобы связать указатель с новым участком памяти, еще не занятым никаким объектом программы, используют функцию malloc (n) из библио­теки stdlib.h, где n – количество выделяемых байт. Функция malloc воз­вращает указатель на void, потому при присваивании ее результат необхо­димо преобразовать в указатель на нужный тип данных. Например,
char *p= (char*)malloc(sizeof(char)); //выделили память для перемененной типа
// char и связали указатель p с эти участком памяти;
Объекты, созданные таким образом (динамические объекты), требу­ют явного уничтожения с помощью функции free(t) из библиотеки stdlib.h (), где t – имя указателя из-под которого освобождается память, например
free(p);
Функция malloc позволяет определять массив еще одним способом:
int k;
scanf(“%d”,&k);
int *a=(int *)malloc(k*sizeof(int));
Этот способ целесообразно использовать, если размерность массива не может быть описана как константа. Однако в данном случае необходи­мо удалить описанный динамический массив после использования с по­мощью функции free(а), иначе память, выделенная под него, останется за­нятой до перезагрузки операционной системы (так называемая проблема «динамического мусора»). Обращаться к элементам
динамического масси-
ва можно всеми перечисленными выше способами.
Специальным образом в языке С обрабатываются массивы, называе­мые С-строками. С-строка – это массив символов, последний из которых
35
символ ‘\0’. Дело в том, что в С нет специального типа данных для описа­ния строк, но есть библиотека функций языка С для работы С-строками (описанная в заголовочном файле string.h, см. задание 18), которые обеспе­чивают различные операции для манипулирования строками. В этой главе мы рассмотрим работу, используя обычный принцип обработки символов как элементов массива.
При инициализации массив символов может задаваться как последо­вательность символов, заключенная в двойные кавычки: “...”. Компилятор располагает в конце каждой строки нулевой (пустой) байт, обозначаемый esc-последовательностью ‘\0’, с тем, чтобы сканирующая строку програм­ма могла найти ее конец. Например:
char str1[]= “abcd”; // действительная длина этой строки равна 5
char * str2= “abcd”; // действительная длина этой строки равна 5
Кроме того, инициализация строк может быть выполнена следую­щим образом:
char str3[]={‘a’, ‘b’, ‘c’, ‘d’, ‘\0’};
При такой инициализации списком, а также при посимвольном за­полнении неинициализированного массива в цикле в конце символьного массива следует явным образом задать символ конца строки ‘\0’. Только при этом массив получает свойства С-строки, которые можно использо­вать, например, в библиотечных функциях для работы со строками или при вводе и выводе строки
. Например, С-строку str3 в отличие от любого не символьного массива можно вывести на экран не в цикле, а с помощью с помощью одного оператора printf(“%s”,str2). А неинициализированный массив char str4[20], в отличие от любого не символьного можно заполнить одним оператором scanf(“%s”, str3). Однако, как отмечено в главе 2, при применении функции scanf клавиатуры считаются в массив str3 все
симво­лы только до первого пробела. Чтобы считать строку целиком, можно ис­пользовать функцию
gets (указатель_на_строку),
описанную в заголовочном файле stdio.h. Например:
char s1[10]; gets(s1); char * s2 = (char *)malloc(m); scanf(“%s”, str3);
Строка s1 – это массив с константой размерностью 10, элементы ко-
торого считываются с клавиатуры с помощью функции gets. Строка
s2 – это динамический массив из m элементов, в который считается только m–4 символов (m–3-й элемент будет равен ‘\0’). Причем второй способ
считывания строки предпочтительнее, чем первый, так как функция gets не накладывает ограничения на число считываемых с клавиатуры символов
,
а это значит, что массив s1 может переполниться.
Пример. Определить длину строки, введенной с клавиатуры, не ис-
пользуя библиотечных функций.
36
# include <stdio.h> void main() { const int n=255; char stroka [n]; gets(stroka);//считали строку int len = 0; // будем использовать переменную len //как индекс массива while (stroka[len]) len++; // условие окончание цикла
stroka[len]= ‘\0’
printf(“%d”,len); }
Многомерные массивы описываются как массивы массивов, например,
int a2[3][2]; // массив из 3 массивов, содержащих по 2 це-
лых элемента.
Для обращения к элементу двумерного массива используется два ин­декса, например, a2[i][j]. Рассмотрим, как используется конструкция вло­женных циклов для работы с двумерными массивами и как возможен вы­ход из вложенных циклов.
Для принудительного выхода из вложенных циклов используют опе­ратор безусловного перехода goto, который имеет формат:
goto идентификатор;
где идентификатор – имя метки оператора, расположенного в той же функции, где используется оператор безусловного перехода. Метка – это обычный идентификатор, после которого ставится двоеточие и следует некоторый оператор. Использование оператора goto принято считать пло­хим стилем, однако в некоторых случаях его применение может быть дей­ствительно обосновано. Например, при решении задачи поиска
в матрице размерности (n,m) поиска в матрице хотя бы одного элемента с заданным значением x.
for (int i=0;i<n; i++) for (int j=0; j<m;j++) if (a[i][j]==x) goto success; … … success: prinf(“Элемент найден. Строка i= %d”,i); prinf(“Столбец j= %d”,j);
Также в циклах применяется оператор continue. С его помощь завер­шается текущая итерация и начинается проверка условий дальнейшего про­должения цикла. Типичный пример использования continue – подсчитать среднее значение только положительных элементов одномерного массива.
for (s=0,k=0,i=0;i<n;i++)
{
if (x[i]<=0) continue;
k++;
s+=x[i];
37
} if (k>0) s=s/k;
Каждому студенту рекомендуется выполнить одно из упражнений 1-12 каждого задания 1-6 и все упражнения задания 7. Тестовый пример для данной задачи подготовить в книге MS Excel.
Задание 9. Детерминированные циклы. Простейшие задачи
Пример. Даны натуральные числа N, x. Вычислить
N
k
1
S
#include <stdio.h>
#include <conio.h>
void main()
{
int x,N,ed=1,fact=1,stepX=1;
float S=0;
printf("Enter x,N ");
scanf("%d%d", &x,&N);
for (int k=1; k<=N; k++)
{
ed= -ed; // меняем знак единицы при каждой итерации
stepX*=x; // вычисляем
fact*=k; // вычисляем (k+1)!
S+=ed*stepX/float(fact);
}
printf("S= %f",S);
getch();
}
k
x
k
)1(
.
k
)!1(
Для проверки данной программы, например, при x = 2, N = 6 целесо­образно составить таблицу MS Excel, представленную на рис. 1.
Рис. 1. Тестовая таблица MS Excel
Данные в этой таблице представлены на рис. 2.
1. Дано натуральное число N. Вычислить
2. Дано натуральное число N. Вычислить
38
N
K
i
N
aS
1
i
1(
1
2
, где
i
1
i
)
*
i
N
1
 
.
1
i1!
лить
лить
p
лить
a
i
a
i
кратномiприi
кратномнеiприii
;3,3/
.3,)3/(
Рис. 2. Данные тестовой таблицы MS Excel
N
3. Даны натуральные числа N и M (N>M). Вычислить
k
)1(
kk
4. Дано натуральное число N. Вычислить
N
S
k
1
1
.
)1(
2
kkS )!ln(
Mk
5. Дано натуральное число N и вещественное число x. Вычис-
N
1
1
i
xS
i
)(sin ,
N
2
i
i
xS
sin . Функцию pow() не использовать.
1
6. Дано натуральное число N и вещественное число x. Вычис-
N
S
1
i
,
i
x
1
N
i
ixp
)( . Функцию pow() не использовать.
0
7. Дано натуральное число N и вещественное число x. Вычислить,
N
 
1
i
1
8. Дано натуральное число N>2. Вычислить
i
x
. Функцию pow() не использовать.
i
12
N
k
k
2
2
kS
)1ln()1( .
9. Дано натуральное число N и вещественное число x. Вычис-
N
i
x
.
iN
1
)!(
N
1
i
кратномiприi
кратномнеiприii
;2,3*
.2,)2(*
k
N
S
S
k
1
N
i
1
2
x
k
1
)1(
i
!
.
k
!
.
iN
)!(
iaS
)( , где
i
2
S
10. Дано натуральное число N. Вычислить
  
11. Дано натуральное число N. Вычислить
12. Дано натуральное число N. Вычислить
.
39
Задание 10. Итерационные циклы. Простейшие задачи
Пример. Дано натуральное число N. Определить его первую и по- следнюю цифры.
#include <stdio.h>
#include <conio.h>
void main()
{
long n,m;
int last;
printf("Enter n: ");
scanf("%d",&n);
m=n; // Сохранили значение исходного числа
last=m%10;
while (m>9) m/=10;
printf("\n In number: %d%s%d",n," first digit: ",m);
printf(", last digit: %d",last);
getch();
}
1. Подсчитать количество цифр в записи заданного десятичного
натурального числа и вывести их на экран в обратном порядке.
2. Дано натуральное число n. Подсчитать сумму цифр этого числа, находящихся на нечетных позициях (нумерация позиций идет слева направо).
3. Дано натуральное число n. Найти сумму цифр числа, находящихся на четных позициях (старшая цифра
числа находится на первой позиции).
4. Даны натуральные числа n и k. Определить k-ю слева цифру числа n.
5. Даны натуральные числа n и k. Вычислить сумму k старших раз­рядов (находящихся слева) цифр числа.
6. Даны натуральные числа n и k. Вычислить произведение k стар­ших разрядов (находящихся слева) цифр числа.
7. Дано натуральное число n.
Вычислить сумму его цифр.
8. Дано натуральное число n. Вычислить произведение его цифр.
9. Дано натуральное число n. Найти разность между первой цифрой этого числа и суммой всех остальных.
10. Выбросить из записи введенного натурального числа n цифры 0 и 5, оставив прежним порядок остальных цифр. Распечатать это число.
11. Целое положительное десятичное число m
записать в восьмерич-
ной системе счисления и распечатать число, состоящие из разрядов этой записи, выписанных в обратном порядке. Например, m = 477, результат
n = 537.
12. Целое положительное число m записать в двоичной системе
счисления и распечатать число, состоящие из разрядов этой записи, выпи­санных в обратном порядке. Например, m = 37, результат n = 101001.
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]