Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 25.11.2008 | Доступ: свободный | Студентов: 9593 / 1296 | Оценка: 4.06 / 3.66 | Длительность: 21:16:00
Лекция 9:

Работа с массивами

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >

8.6. Слияние отсортированных массивов

Довольно много методов сортировки построено на сортировке фрагментов массивов с последующим объединением (слиянием) двух или более фрагментов в общий массив. Ниже приведена одна из реализаций объединения двух отсортированных массивов a и b, содержащих, соответственно, по ka и kb упорядоченных по возрастанию целых чисел. Чего-то особенного в алгоритме слияния нет – надо поочередно просматривать претендентов из обоих массивов и вставлять нужный из них в результирующий массив. Единственное, за чем приходится следить – не исчерпался ли тот или иной поставщик данных. Несмотря на использование в функции merge трех операторов goto, приведенный вариант представляет собой наиболее эффективную программу слияния.

#include <stdio.h>
#include <conio.h>
void merge(int *a,int ka,int *b, int kb, int *c)
{ int ja=0,jb=0,jc;
  for(jc=0; jc<ka+kb; jc++)
    { if(ja==ka) goto mb;
      if(jb==kb) goto ma;
      if(a[ja]<b[jb]) goto ma;
mb:   c[jc]=b[jb]; jb++; continue;
ma:   c[jc]=a[ja]; ja++;
    }
}
#define na 3
#define nb 4
void main()
{ int j,a[na]={0,2,4},b[nb]={1,3,5,7};
  int c[na+nb];
  for(j=0; j<na; j++) printf("%4d",a[j]);
  printf("\n");
  for(j=0; j<nb; j++) printf("%4d",b[j]);
  printf("\n");
  merge(a,na,b,nb,c);
  for(j=0; j<na+nb; j++) printf("%4d",c[j]);
  getch();
}
//=== Результат работы ===
   0   2   4
   1   3   5   7
   0   1   2   3   4   5   7

8.7. Динамические массивы.

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

Пусть qуказатель на одномерный массив с элементами типа type_q. Тогда запрос на выделение памяти без ее предварительной очистки выполняется с помощью функции malloc:

q=(type_q *)malloc(n_byte);

Приведение к типу данных потребовалось потому, что функция malloc возвращает указатель типа void. Аргументом функции malloc является запрашиваемое количество байт. Необходимо иметь в виду, что данные типа int в 16-битной системе программирования (например, BC 3.1 под управлением MS-DOS) занимают по 2 байта, а в 32-битной среде типа BCB – по 4 байта.

Аналогичный запрос на выделении памяти с ее предварительной очисткой выполняется с помощью функции calloc:

q=(type_q *)calloc(n_el,sizeof(type_q));

В отличие от предыдущей функции здесь уже два аргумента – количество элементов массива ( n_el ) и длина каждого элемента в байтах sizeof(type_q).

Прототипы обеих функций находятся в заголовочных файлах alloc.h и stdlib.h. Если по каким-то причинам память выделить не удалось, каждая из функций возвращает нулевой указатель ( q==NULL ).

После выделения блока памяти по malloc или calloc его можно перераспределить, изменив ранее объявленную длину:

q=(type_q *)realloc(q,new_len);

Если новая длина больше предыдущей, то содержимое массива q копируется в начало нового блока памяти. Если новая длина меньше предыдущей, то в новом блоке сохраняются значения только начала старого массива. Если new_len=0, то это эквивалентно освобождению занимаемого блока памяти.

После того, как массив q будет использован и больше не понадобится, выделенную память надо возвратить с помощью функции free:

free(q);

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

q=NULL;    //или q=0;

Некоторое представление о работе описанных функций дает следующий пример:

#include <alloc.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
void main()
{ int j,*p,s;
  char *str="abcdefghijk",*s1;
  p=(int *)malloc(4000);        //запрос "грязной" памяти
  for(s=0,j=0; j<1000; j++) s += p[j];
  printf("s=%d",s);             //улика - память "грязная"
  for(j=0; j<1000; j++) p[j]=j; //роспись выделенной памяти
  printf("\np[500]=%d",p[500]); //выборочная проверка
  free(p);                      //освобождение памяти
  p=(int *)calloc(1000,sizeof(int)); //запрос чистой памяти
  for(s=0,j=0; j<1000; j++) s += p[j];
  printf("\ns=%d",s);           //алиби - память чистая
  free(p);                      //освобождение памяти
  s1=(char *)calloc(20,1);      //запрос памяти под строку
  strcpy(s1,str);               //копирование данных
  printf("\ns1=%s",s1);         //вывод старой строки
  s1=(char*)realloc(s1,8);      //перераспределение памяти
  s1[5]=0x0;                    //признак конца новой строки
  printf("\ns1=%s",s1);         //вывод новой строки
  getch();
}
//=== Результат работы ===
s=-2138551277
p[500]=500
s=0
s1=abcdefghijk
s1=abcde

В языке C++ появились дополнительные средства для запроса и освобождения памяти:

q = new type_q;		//запрос памяти под скалярную переменную
  q = new type_q[n_el];	//запрос памяти под массив из n_el элементов
  delete q;			//освобождение памяти из-под скаляра
  delete []q;			//освобождение памяти из-под массива

Динамическое выделение памяти под скалярную переменную можно совместить с ее инициализацией:

int v=new int(5);	//после выделения памяти v=5

Память, выделяемую с помощью оператора new под динамические массивы, таким образом инициализировать нельзя.

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >
Alexey Ku
Alexey Ku

Попробуйте часть кода до слова main заменить на 

#include "stdafx.h" //1

#include <iostream> //2
#include <conio.h>

using namespace std; //3

Александр Талеев
Александр Талеев

#include <iostream.h>
#include <conio.h>
int main(void)
{
int a,b,max;
cout << "a=5";
cin >> a;
cout <<"b=3";
cin >> b;
if(a>b) max=a;
else max=b;
cout <<" max="<<max;
getch();
return 0;
}

при запуске в visual express выдает ошибки 

Ошибка    1    error C1083: Не удается открыть файл включение: iostream.h: No such file or directory    c:\users\саня\documents\visual studio 2012\projects\проект3\проект3\исходный код.cpp    1    1    Проект3

    2    IntelliSense: не удается открыть источник файл "iostream.h"    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    1    1    Проект3

    3    IntelliSense: идентификатор "cout" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    6    1    Проект3

    4    IntelliSense: идентификатор "cin" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    7    1    Проект3

при создании файла я выбрал пустой проект. Может нужно было выбрать консольное приложение?