Практикум для изучения дисциплины «Основы программирования»



Pdf көрінісі
бет56/81
Дата08.07.2020
өлшемі1,55 Mb.
#74978
түріПрактикум
1   ...   52   53   54   55   56   57   58   59   ...   81
Байланысты:
А.А. Тюгашев

Файл test.txt
 
(пример): "абитуриент сможет перейти через барьер, и 
наконец стать настоящим человеком, который поступит в вуз и будет 
переходить с курса на курс, так что абитуриент в конце концов станет 
настоящим специалистом — инженером!" 
Обратите внимание на использование в этой программе функций rename 
и  remove  из  стандартной  библиотеки,  описываемой  заголовочным 
файлом  stdio.h,  для  переименования  и  удаления  файлов.  В  программе 
сначала  создается  промежуточный  файл  test.bak,  в  который  из 
исходного  файла  копируется  вся  информация,  но  слова  «абитуриент» 


106 
 
заменяются  словами  «студент»,  потом  исходный  файл  удаляется,  а 
промежуточный получает имя исходного файла — test.txt. 
Контрольные вопросы 
1. 
Что  такое  файловый  дескриптор  в  программе  на  языке  Си?  В  чем 
отличие дескриптора от имени файла? 
2. 
Как открыть файл в программе на языке Си? Как задать режим доступа 
к файлу? 
3. 
Как используется NULL при открытии файла в программах на Си? 
4. 
В чем заключается применение функций remove() и rename()? 
5. 
Нужно  ли  закрывать  файл  после  использования?  C  помощью  какой 
функции это можно сделать? 
Сумма нечетных на языке Си 
Итак,  мы  уже  располагаем  некоторыми  знаниями  о  языке 
программирования Си. Вернемся к примеру, рассмотренному во введении 
книги.  Напишем  программу  суммирования  нечетных  членов  числовой 
последовательности. 
Предположим, что числа вводятся пользователем с клавиатуры — столько, 
сколько необходимо, пока не будет введен ноль, служащий ограничителем 
последовательности. 
/* 
Сумма нечетных */ 
#include  
 
int main() 

  int a,s=0; /*s — 
сумма, обнуляем*/  
   
  
printf("Программа нахождения суммы нечетных членов числового 
ряда\n"); 
  
printf("Вводите целые числа или ноль для завершения\n"); 
  do  
  { 
    printf(">");scanf("%d",&a); 
    if (a%2) s+=a; /* 
экивалентно if (a%2!=0) s=s+a;*/ 
  
} while (a!=0); /* можно просто while(a); но это менее понятно*/ 
  
printf("сумма нечетных среди введенных =%d\n",s); 
  return 0; 

Обратите  внимание  на  некоторые  особенности  программы.  В  ней 


107 
 
соблюдены  правила  хорошего  тона:  после  запуска  до  пользователя 
доводится  краткая  информация  о  ее  предназначении  и  делается 
приглашение  к  вводу  чисел.  При  этом  для  каждого  очередного  числа 
выдается >. Вывод приглашения с помощью printf() и ввод с помощью 
scanf()
 
сгруппированы в одной строке, что вполне логично. 
Используется цикл do (ДО) для ввода чисел и подсчета суммы нечетных. 
Для  определения  четности/нечетности  введенного  числа  используется 
встроенная в язык операция % взятия остатка от деления. Если остаток от 
деления на 2 ненулевой — число нечетное, в противном случае — четное. 
Поскольку  в  языке  программирования  Си  нет  выделенного  логического 
типа и любое ненулевое число воспринимается как логическая ИСТИНА, 
можно  записать  if  (a%2)  вместо  if  (a%2!=0).  Этим,  как  и 
сокращенной записью s+=a вместо s=s+a, соблюден дух Си. Однако это 
несколько  ухудшает  прозрачность  программы,  и  при  проверке 
ограничителя цикла подобный трюк не применяется. 
Напишем  теперь  второй  вариант  программы.  В  нем  сначала  будем 
запрашивать  пользователя  о  количестве  подлежащих  обработке  чисел. 
Кроме  того,  вместо  условного  оператора  if  применим  условное 
выражение ?: 
/* Сумма нечетных вторым способом */ 
#include  
#define MAXN 1000 /* максимальная длина последовательности чисел */ 
 
int main() 

  int a,i,n,s=0; /*s — 
сумма, обнуляем*/  
   
  
printf("Программа нахождения суммы нечетных членов числового 
ряда\n"); 
  
printf("Введите количество чисел (<%d):",MAXN);scanf("%d",&n); 
  for (i=0;i  { 
    
printf("введите очередное число>");scanf("%d",&a); 
    
s+=((a%2)?a:0); /* прибавляем или само число a, или ноль */ 
  }   
  pri
ntf("сумма нечетных среди введенных =%d\n",s); 
  return 0; 

В этом варианте следует обратить внимание на ввод ограничения сверху на 
длину  обрабатываемой  числовой  последовательности  с  помощью 
директивы #define. Затем у пользователя запрашивается действительное 


108 
 
количество  чисел,  подлежащих  обработке,  n.  Для  ввода  и  обработки 
используется единый цикл for, в котором переменная цикла i меняется от 
0 до n – 1 путем записи for (i=0;iСи, поскольку в нем с помощью for часто обрабатываются массивы, а в 
них нумерация начинается с нуля. Всего получится n повторений, что нам 
и  надо.  После  ввода  числа  к  s  добавляется  результат  вычисления 
условного  выражения.  Сначала  вычисляется  остаток  от  деления  a  на  2. 
Этот результат по правилам языка программирования Си воспринимается 
как логическая ИСТИНА, если остаток ненулевой, иными словами, число 
нечетное, и как логическая ЛОЖЬ, если нулевой, то есть число четное. В 
первом случае все условное выражение принимает значение, указанное до 
двоеточия,  а  именно  само  число  a,  во  втором  случае —  ноль,  указанный 
после двоеточия. Полученное число прибавляется к s, давая возможность 
получить нужный результат. 
Контрольные вопросы 
1. 
Как  работает  оператор  if  (a%2)?  Какая  особенность  работы  с 
логическими  значениями  языка  программирования  Си  используется  в 
данной программе? 
2. 
С какими целями используется директива препроцессора #define? 
3. 
Поясните,  как  работает  оператор  s+=((a%2)?a:0).  Могли  бы  вы 
предложить  альтернативные  варианты  подсчета  суммы  нечетных  на 
языке программирования Си? 
Сортировка массивов 
Весьма  важную  роль  в  программировании  имеют  задачи  поиска  и 
сортировки.  Неудивительно,  что  один  из  томов  свого  знаменитого  труда 
«Искусство  программирования»  Дональд  Кнут  так  и  назвал — 
«Сортировка и поиск» [10]. 
Мы  не  будем  сейчас  углубляться  в  теорию,  а  интересующихся  вопросом 
отсылаем  к  упомянутой  книге.  Заметим  лишь,  что  решать  эти  задачи 
можно  различными  способами,  причем  существенно  различающимися 
между  собой  по  эффективности —  времени  выполнения  алгоритма  и 
требуемому объему памяти. 
Приведем здесь лишь один из примеров реализации сортировки на языке 
программирования  Си —  не  самого  эффективный,  но  прозрачный 
алгоритм  (сортировка  выбором),  в  котором  сначала  на  первое  место  в 
массиве  ставится  наименьший  элемент  путем  перебора  всех  элементов, 
сравнения  их  с  первым  и  перестановки  в  случае  необходимости,  а  затем 
процедура повторяется для второго и оставшихся элементов. 


109 
 
/* сортировка перестановками на Си */ 
#define N 10 /* размер обрабатываемого массива */ 
 
int main() 

  int a[N]; 
  int i,j,buf; 
   
  
printf("Программа сортировки массива\n"); 
  
printf("Введите %d чисел:",N); 
  for (i=0;i   
  for (i=0;i    for (j=i+1;j      if (a[i]>a[j]) 
      { 
        buf=a[i]; 
        a[i]=a[j]; 
        a[j]=buf; 
      } 
   
  printf("
После сортировки:\n"); 
  for (i=0;i  printf("\n"); 
   
  return 0; 

В  программе  используется  #define  для  задания  размера  массива. 
Поскольку обработка с помощью директив препроцессора происходит до 
компиляции,  запись  int  a[N]  допустима,  несмотря  на  поддержку  лишь 
статических  массивов  в  Си —  к  моменту  выделения  памяти  N  будет 
заменено в программе конкретным числом. 
Для  сортировки  используются  два  цикла,  один  из  которых  вложен  в 
другой.  Внешний  цикл  использует  переменную  i  для  выбора  сначала 
первой позиции, куда помещается наименьший в массиве, затем — второй 
и  так  до  позиции  N – 2  (именно  это  значит  запись  iцикле,  использующем  переменную  j,  ее  значение  изменяется  от  i + 1  до 
N – 1 (j),  производятся  перебор  всех  оставшихся  элементов  массива  и 
их сравнение с находящимся на выбранном месте, в случае необходимости 
выполняется  перестановка.  Поскольку  в  языке  программирования  Си  нет 
операции  обмена  значений  переменных,  для  перестановки  используется 


110 
 
буфер buf и «трехходовка» через него (в отличие от ассемблера x8086). 
Контрольные вопросы 
1. 
Как  работает  оператор  if  (a%2)?  Какая  особенность  работы  с 
логическими  значениями  языка  программирования  Си  используется  в 
данной программе? 
2. 
Какие  методы  сортировки  вам  известны?  Какие  свои  идеи  вы  бы 
использовали для этого? 
Система управления базой данных о студентах 
Рассмотрим  более  сложную,  нежели  приведенные  ранее,  программу  на 
языке  Си,  а  именно —  систему  управления  базой  данных  (СУБД)  о 
студентах. Как правило, в современной практике для создания программ, 
основными  функциями  которых  являются  хранение,  поиск  и  выдача  по 
запросу  пользователя  информации, —  информационных  систем 
используются специализированные средства. 
Однако  с  учебными  целями  мы  проиллюстрируем,  как  реализовать 
простую  базу  данных  непосредственно  на  универсальном  языке 
программирования,  каковым  является  Си.  Хранить  информацию  будем  в 
формируемом  программой  на  диске  компьютера  файле,  например 
Students.dat

Какую  информацию  нужно  хранить  о  студенте?  Очевидно,  что  нужно 
запоминать фамилию, имя и отчество, вероятно, год рождения (это может 
представлять  интерес  для  военкомата).  Логично  для  студента  сохранять 
группу  и  успеваемость,  которую  можно  выразить  средним  баллом, 
полученным  в  ходе  сдачи  предыдущей  сессии.  Добавим —  чтобы  внести 
положительных эмоций — еще размер стипендии и этим в нашем учебном 
примере  ограничимся  (читателю  не  возбраняется  создать  свою  версию 
данной  программы  с  расширенным  перечнем  характеристик  студента, 
например, указанием пола, длины волос, любимой рок-группы и т. д.). 
Соответствующая структура данных может выглядеть так: 
/* Описание структуры данных "Студент" */ 
struct 

  char Family[50]; // 
Фамилия 
  char Imy[50];  // 
Имя 
  char Otcestvo[50];  // 
Отчество 
  char NGr[7]; // 
Номер группы 
  int GodR
; // Год рождения 
  float SrBall
; // Средний балл 


111 
 
  float Stip
; // Размер стипендии 
} Stud; 
Для удобства дальнейшей обработки фамилия, имя и отчество хранятся в 
виде  отдельных  строк.  Обозначение  группы  во  многих  вузах  может 
включать  как  цифры,  так  и  буквы,  поэтому  номер  группы  тоже 
представлен  строкой  NGr.  Год  рождения  вполне  может  представляться 
целым  числом.  Средний  балл  и  размер  стипендии —числа  с  плавающей 
точкой. 
Предположим,  что  после  запуска  программа  будет  выдавать  на  экран 
«меню» — перечень возможных действий с базой данных. 
Реализуем следующие основные операции с базой: 
1. 
Добавление записи о студенте в базу. 
2. 
Поиск студента по фамилии. 
3. 
Поиск по группе — вывод всех учащихся заданной группы. 
4. 
Поиск  по  возрасту —  с  указанием  диапазона  годов  рождения  «от»  и 
«до». 
5. 
Поиск по успеваемости с заданием диапазона среднего балла. 
6. 
Удаление данных. 
7. 
Выход из СУБД. 
Логично  соответствующим  образом  структурировать  программу —  для 
каждого  основного  режима  работы  реализовать  отдельную  функцию. 
Главная  программа  при  этом  содержит  цикл,  в  котором  производятся 
запрос выбираемого режима, обработка и т. д., пока не будет выбран пункт 
«Выход». 
Уместным  в  данной  ситуации  представляется  использование  так 
называемого  нисходящего  проектирования  программ  при  разработке 
системы.  Оно  заключается  в  том,  что  сначала  пишется  функция  main  с 
меню, из которой вызываются функции Dobavl(), Udal() и т. д. Затем 
создаются  «заглушки»  этих  функций —  заголовки  с  пустыми  телами, 
имеющими лишь return. Далее разрабатывается и отлаживается одна из 
подлежащих  реализации  функций,  затем —  другая  (остальные  остаются 
заглушками) и т. д. При этом на каждом этапе мы имеем работоспособную 
программу,  которую  можно  запустить  на  выполнение,  хотя  и  с 
ограниченной функциональностью! 


Достарыңызбен бөлісу:
1   ...   52   53   54   55   56   57   58   59   ...   81




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет