КаталогИндекс раздела
НазадОглавлениеВперед


Лабораторная работа ╧11

Указатели и массивы

1. Цель работы

     Целью лабораторной работы является получение практических навыков в работе с указателями и с адресной арифметикой в языке C.

2. Теми для предварительной проработки

3. Задания для выполнения

     Выполнить задание лабораторной работы ╧8 с такими дополнительными условиями:

4. Варианты индивидуальных заданий

 1        2        3        4        5        6        7        8        9       10      
11       12       13       14       15       16       17       18       19       20      
21       22       23       24       25       26       27       28       29       30      

5. Пример решения задачи (вариант 30)

     Описание решения задачи приводится со ссылками на методические указания к работе ╧8. Описываются только решения, отличные от тех, что принимались в работе ╧8.

5.1. Разработка алгоритма решения.

     Алгоритм решения задачи в основном - тот же, что и в работе ╧8, поэтому его схему ми тут не приводимо. Разница состоит в том, что в начале выполнения, после инициализации датчика случайных чисел, нужно получить случайное число в диапазоне 50 - 200 (назовем его size) и выделить память для массива целых чисел размером size. (На схеме алгоритма для работы ╧8 эти действия должны быть вставлены сразу же после блока 2). Перед самым выходом из программы мы должны освободить выделенную память (На схеме алгоритма для работы ╧8 - после блока 19).

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

    Ar[i]  *(Ar+i)
Это соответствовало бы букве задания, но не духу языка C. Если мы переходим от индексации к адресации, у нас устраняется необходимость в индексах и даже в переменных, которые их представляют. Это приводит к другому способу реализации всех циклов. Если имя массива Ar является указателем на его начало, то вместо цикла, в котором индекс i меняется от 0 до size, мы можем организовать цикл, в котором некоторый текущий указатель Cr меняется от Ar до Ar+size. Также, когда нам нужно запомнить начало отрицательной последовательности, мы можем запоминать не индекс соответствующего элемента, а его адрес - указатель на него.

5.2. Определение переменных программы

     Переменные программы мы также описываем в сравнении с работой ╧8. Память для массива целых чисел в нашей работе не выделяется на этапе компиляции, так что нам достаточно объявить в программе только переменную - указатель на начало массива:

    int *Ar; 

     Размерность массива определяется при выполнении программы, так что для ее сохранения нужна отдельная переменная:

    int size;

     Вместо переменных, которые в работе ╧8 являются индексами элементов массива, мы будем применять указатели:

    int *Cr; 
это будет указатель на текущий элемент массива при его полном переборе, и:
    int *Ir; 
в этом указателе будет сохраняться адрес начала отрицательной последовательности, а потом - при обработке последовательности - адрес текущего ее элемента.

     Переменные для сохранения суммы элементов и среднего значения и количества элементов в последовательности остаются те же самые:

    int av; 
    int nn; 

5.3. Разработка текста программы

     Кроме тех файлов, которые были включены в текст программы работы ╧8:

    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
включаем также файл alloc.h, в котором содержатся описания функций динамического выделения/освобождения памяти:
    #include <alloc.h>

     Начинаем главную функцию и объявляем в ней переменные программы по п.5.2. Кодовая часть программы начинается с инициализации датчика случайных чисел и получения случайного числа для размера массива:

    randomize();
    size=random(151)+50;

     Функция rand возвращает нам число в диапазоне 0 - 150, прибавлением к нему 50 мы переводим его в диапазон 50 - 200. Полученный размер массива сразу выводим на экран:

    printf("size=%d\n",size);

     Обращаемся к функции выделения памяти:

    Ar=(int far *)malloc(size*sizeof(int));
Функция malloc() требует параметр - размер запрошенной памяти в байтах. Переменная size - это количество элементов в массиве; для задания размера памяти в байтах умножаем ее на размер одного элемента. Функция malloc()возвращает нетипизированный указатель, мы преобразуем его в указатель на int и записываем в переменную Ar.

     Далее организуем цикл перебора массива. В отличие от работы ╧8 мы тут в одном цикле и получаем случайные числа, и выводим начальный массив на экран. Заголовок этого цикла существенно отличается от работы ╧8:

    for (Cr=Ar; Cr<Ar+size; Cr++) {

     В начальных установках цикла мы записываем в переменную Cr адрес начала массива, т.е. Cr показывает на элемент с индексом 0. В конце каждой итерации Cr увеличивается на 1, т.е. показывает на следующий элемент массива. Последняя итерация происходит при значении Cr=Ar+size-1, т.е. Cr будет показывать на последний элемент. В каждой итерации мы обращаемся к текущему элементу массива как *Cr, т.е. обращаемся к тому, на что показывает указатель Cr.

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

     Тело цикла в основном подобно тому, что есть в лабораторной работе ╧8 за исключением того, что к текущему элементу массива мы обращаемся через указатель на него: *Cr. Там, где нам требуется запомнить начало отрицательной последовательности, мы просто сохраняем текущее значение указателя Cr в переменной-указателе Ir.

     Внутренний цикл, в котором обрабатывается отрицательная последовательность, существенно отличается от работы ╧8:

    for (av/=nn; Ir<Cr; Ir++)
      if (*Ir<av) *Ir=av;

     Начальные установки этого цикла - только усреднение значения в av, переменная Ir уже содержит в себе указатель на первый элемент отрицательной последовательности. В конце каждой итерации Ir увеличивается на 1, т.е. показывает на следующий элемент последовательности (обращение к этому элементу - *Ir). Последняя итерация происходит при значении Ir=Cr-1, поскольку Cr показывает на первый положительный элемент за отрицательной последовательностью.

     Остаток программы повторяет предыдущие фрагменты.

     Предпоследний оператор - обращение к функции free() для освобождения памяти, которая была выделена функцией malloc(): free(Ar);

     Полный текст программы приведен ниже.

/****************************************************/
/*             Лабораторная работа ╧11              */
/*              Указатели и массивы                 */
/*          Пример выполнения. Вариант ╧30.         */
/****************************************************/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <alloc.h>
int main(void) {
 int size;                   /* размер массива */
 int *Ar;       /* указатель на начало массива */
 int *Cr, *Ir;            /* текущие указатели */
 int av, nn;            /* среднее значение и
    количество элементов в последовательности  */
  randomize();  /* инициализация rand */
  size=random(151)+50;
  printf("size=%d\n",size);
  /* выделения памяти */
  Ar=(int far *)malloc(size*sizeof(int));
  /* заполнение массива случайными числами и
     вывод начального массива */
  printf("Начальный массив:\n");
  for (Cr=Ar; Cr<Ar+size; Cr++) {
    *Cr=random(101)-50;
    printf("%3d ",*Cr);
    }
  putchar('\n');

  /* перебор массива */
  for (nn=0, Cr=Ar; Cr<Ar+size; Cr++) { 
    if (*Cr<0)
      /* обработка отрицательного элемента */
      if (!nn) {
          /* начало последовательности: запомнить адрес 
             начала в Ir, установить начальное значение 
               накопителя суммы и счетчике элементов */
         Ir=Cr; av=*Cr; nn=1;
         }
      else {
      /* подсчет суммы и количества элементов */
        av+=*Cr; nn++;
        }
    /* конец обработки отрицательного элемента */
    else /* обработка положительного элемента */
      if (nn) {
          /* если есть необработанная отрицательная последовательность: 
             усреднение и перебор с ограничением */
        for (av/=nn; Ir<Cr; Ir++)
          if (*Ir<av) *Ir=av;
        nn=0; /* последовательность обработана */
        }  /* конец если есть необработанная... */
    }  /* конец перебора массива */
  if (nn) /* если не обработана последняя 
             отрицательная последовательность */
    for (av/=nn; Ir<Cr; Ir++)
      if (*Ir<av) *Ir=av;
  /* вывод результатов */
  printf("Массив-результат:\n");
  for (Cr=Ar; Cr<Ar+size; printf("%3d ",*Cr++));
  putchar('\n');
  /* освобождение памяти */
  free(Ar);
  return 0;
}

5.4. Отладка программы

     Отладку программы следует вести по тому же плану, что и в работе ╧8. Следует, однако, отметить, что отслеживать значения в пошаговом режиме тут несколько труднее, ибо если в работе ╧8 мы могли видеть достаточно понятные значения индексов, то тут вместо них мы увидим значения указателей, более сложные для понимания. Поэтому мы рекомендуем больше полагаться на выявление ошибок путем анализа результатов программы.

5.5. Результаты работы программы

Образец результатов программы приведен ниже
size=69
Начальный массив:
-50   8  13 -16  11 -45  21 -12  -6 -45  17  21  41  36 -12 -42  24 -14  -9 -14  
 50 -31 -37 -49  48 -37  50 -20 -43  46 -30  33  21  24 -36  12 -20 -48 -27  -8  
 -6 -36 -21 -24 -31   8 -23  24 -33  13 -15  -6  -8 -43 -48  22 -49  49  19  12  
 18 -17  31  47  45  -2  28  42 -49 
Массив-результат:
-50   8  13 -16  11 -45  21 -12  -6 -21  17  21  41  36 -12 -27  24 -12  -9 -12
 50 -31 -37 -39  48 -37  50 -20 -31  46 -30  33  21  24 -36  12 -20 -24 -24  -8
 -6 -24 -21 -24 -24   8 -23  24 -33  13 -15  -6  -8 -24 -24  22 -49  49  19  12
 18 -17  31  47  45  -2  28  42 -49 

5.6. Выводы

     При выполнении лабораторной работы изучены вопросы:


КаталогИндекс раздела
НазадОглавлениеВперед