Попробуйте часть кода до слова main заменить на #include "stdafx.h" //1 #include <iostream> //2 using namespace std; //3 |
Работа с массивами
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 под динамические массивы, таким образом инициализировать нельзя.