Массивы
Ранее мы ввели типы данных в языке С, которые называются иногда базовыми или встроенными. На основе этих типов данных язык С позволяет строить другие типы данных и структуры данных. Массив - одна из наиболее простых и известных структур данных.
Под массивом в языке С понимают набор данных одного и того же типа, собранных под одним именем Каждый элемент массива определяется именем массива и порядковым номером элемента, который называется индексом. Индекс в языке С всегда целое число.
Объявление массива в программе
Основная форма объявления массива размерности N такова:
тип <имя массива>[размер1][размер2]...[размерN]
Чаще всего используются одномерные массивы:
тип <имя массива>[размер],
тип - базовый тип элементов массива,
размер — количество элементов одномерного массива.
Размер массива в языке С может задаваться константой или константным выражением. Нельзя задать массив переменного размера. Для этого существует отдельный механизм, называемый динамическим выделением памяти.
Обсудим более подробно одномерные массивы.
В языке С индекс всегда начинается с нуля. Когда мы говорим о первом элементе массива, то имеем в виду элемент с индексом 0. Если мы объявили массив int a[100],
это значит, что массив содержит 100 элементов от а[0] до а[99]. Для одномерного массива легко подсчитать, сколько байт в памяти будет занимать этот массив:
колич. байт=<размер базового типа>*<колич. элементов>.
В языке С под массив всегда выделяется непрерывное место в оперативной памяти.
В языке С не проверяется выход индекса за пределы массива. Если массив а[100] описан как целочисленный массив, имеющий 100 элементов, а вы в программе укажете а[200], то сообщение об ошибке не будет выдано, а в качестве значения элемента а[200] будет выдано некоторое число, занимающее соответствующие 2 байта.
Можно определить массив любого определенного ранее типа, например
unsigned arr[40], long double al[1000], char ch[80].
Упорядочение в одномерных массивах
Задаче упорядочения или сортировке посвящены многочисленные работы математиков и программистов. Для демонстрации некоторых особенностей вложения циклов и работы с массивами рассмотрим простейшие алгоритмы сортировки. Необходимо, введя значение переменной 1 <n<= 100 и значения п первых элементов массива а[0],а[1],...,а[п-1], упорядочить эти первые элементы массива по возрастанию их значений. Текст первого варианта программы:
/* Упорядочение элементов массива */
#include <stdio.h>
main() {
int n, i, j;
double a[100], b;
while(1) {
printf("\n Введите количество элементов n=");
scanf("%d",&n);
if (n > 1 && n <= 100) break;
printf("Ошибка! Необходимо 1<n<=100!");
}
printf("\n Введите значения элементов массива:\n");
for(j=0; j<n; j++) {
printf("a[%d]=”, j+1);
scanf("%lf",&a[j]);
}
for(i=0; i<n-l; i++)
for(j=i+l; j<n; j++)...
if(a[i]>a[j])
{
b=a[i];
a[i]=a[j];.
a[j]=b;
}
printf("\n Упорядоченный массив: \n"); '
for(j=0; j<n; j++)
printf("a[%d]=%f\n",j +1,a[j]);
}
Результаты выполнения программы:
Введите количество элементов п=-15
Ошибка! Необходимо 1<п<=100!
Введите количество элементов п=3
Введите значения элементов массива:
а[1] = 88.8
а[2] = -3.3
а[3] = 0.11
Упорядоченный массив:
а[1] = -3.3
а[2] = 0.11
а[3] = 88.8
Обратите внимание, что при заполнении массива и при печати результатов его упорядочения индексация элементов выполнена от 1 до n, как это обычно принято в математике. В программе на Си это соответствует изменению индекса от 0 до (n-1).
В программе реализован алгоритм прямого упорядочения - каждый элемент a[i], начиная с а[0] и кончая а[n-2], сравнивается со всеми последующими, и на место a[i] выбирается минимальный. Таким образом, а[0] принимает минимальное значение, а[1] - минимальное из оставшихся и т.д. Недостаток этого алгоритма состоит в том, что в нем фиксированное число сравнений, не зависимое от исходного расположения значений элементов. Даже для уже упорядоченного массива придется выполнить то же самое количество итераций (n-1)*n/2, так как условия окончания циклов не связаны со свойствами, т.е. с размещением элементов массива.
Двумерные массивы
Как мы уже отмечали, язык С допускает многомерные массивы, простейшей формой которых является двумерный массив (two-dimentional array). Можно сказать, что двумерный массив - это массив одномерных массивов.
При описание двумерного массива объявление имеет следующий вид:
тип <имя массива>[размер1][размер2],
В соответствии с синтаксисом Си в языке существуют только одномерные массивы, однако элементами одномерного массива, в свою очередь, могут быть массивы. Поэтому двумерный массив определяется как массив массивов. Таким образом, в этом описании можно трактовать объявление двумерного массива массив размера [размер2], элементами которого являются одномерные массивы <имя массива>[размер1].
Двумерный массив int a[3][4] можно представить в виде таблички
а[0][0] | a[0][1] | a[0][2] | а[0][3] |
a[l][0] | а[1][1] | a[1][2] | а[1][3] |
а[2][0] | a[2][1] | а[2][2] | а[2][3] |
Пример: float Z[13][[6];
определяет двумерный массив, первый индекс которого принимает 13 значений от 0 до 12, второй индекс принимает 6 значений от 0 до 5. Таким образом, элементы двумерного массива Z можно перечислить так:
Z[0][0], Z[0][l], 2[0][2],...,Z[12][4], Z[12][5]
В примере определен массив Z из 13 элементов-массивов, каждый из которых, в свою очередь, состоит из 6 элементов типа float. Обратите внимание, что нумерация элементов любого массива всегда начинается с 0, т.е. индекс изменяется от 0 до N-1, где N -количество значений индекса.
Инициализация массивов
Очень важно уметь инициализировать массивы, т. е. присваивать элементам массива некоторые начальные значения. В языке С для этого имеются специальные возможности. Самый простой способ инициализации следующий: в процессе объявления массива можно указать в фигурных скобках список инициализаторов:
float farr[6]={ 11. 2.2, 3.3,4.0, 5, 6};
int а[3][5]={1, 2, 3,4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
В другом случае такая форма записи эквивалентна набору операторов: а[0][0]=1; а[0][1]=2; а[0][2]=3; а[0][3]=4; а[0][4]=5; а[1][0]=6; а[1][1]=7; а[1][2]=8; и т. д.
Многомерные массивы, в том числе и двумерные массивы, можно инициализировать, рассматривая их как массив массивов.
Инициализации
int а[3][5]={1, 2, 3,4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
и
int а[3][5]={{1, 2, 3,4, 5}, {6, 7, 8,9, 10}, {11, 12,13, 14, 15}};
эквивалентны. Количество инициализаторов не обязано совпадать с количеством элементов массива. Если инициализаторов меньше, то оставшиеся значения элементов массива не определены.
Символьные массивы могут инициализироваться как обычный массив:
char str[15]={'B\ 'о', Y, 'Г, V, У, 'd\'', 'С,'+', '+•};
а могут - как строка символов:
char str[15]="Borland C++";
Отличие этих двух способов состоит в том, что во втором случае будет добавлен еще и нулевой байт. К тому же второй способ короче.
Допускается также объявление и инициализация массива без явного указания размера массива.
Например, для выделения места под символьный массив обычным способом
При инициализации массива без указания его размера char str[ ]="Это объявление и инициализация массива символов"; компилятор сам определит необходимое количество элементов массива, включая нулевой байт. Можно объявлять таким же способом массивы любого типа:
int mass[]={l, 2, 3, 1,2, 3,4};
и многомерные массивы. При объявлении массивов с неизвестным количеством элементов можно не указывать размер только в самых левых квадратных скобках:
int агг[][3]={ 1, 2, 3, 5, 6, 7, 8, 9, 0};
Пример: ввод массива, вывод в обратном порядке
#include <conio.h>
#include <stdio.h>
int main () {
const int sizeArray=10;
int i, j;
int ar[sizeArray];
for (i=0; i<sizeArray; i++) {
printf("ar[%d]=",i);
scanf("%d",&ar[i]);
}
for (j=0, i=sizeArray-1; i>=0; j++, i--)
printf("ar[%d]=%d“, i, ar[i]);
getch();
return 0;
}
/* 06_05.c - поиск в массиве. Размер задан инициализацией. */
#include <stdio.h>
int main () {
int i, number, count=-1;
int size;
int ar[]={0,1,2,3,4,5,4,3,2,1,0};
printf("number=");
scanf("%d",&number);
size=sizeof(ar)/sizeof(ar[0]);
for (i=0; i<size; i++)
if (number == ar[i]) count=i;
printf("count=%d",count);
return 0;
}
Массивы символов. Строки
Массивы типа char - символьные массивы - занимают в языке особое место. Во многих языках есть специальный тип данных - строка символов (string). В языке С отдельного типа строки символов нет, а реализована работа со строками путем использования одномерных массивов типа char. Кроме того в Си++ можно создать классы для более удобной работы с текстом (готовые классы для представления строк имеются в стандартной библиотеке шаблонов).
В языке С символьная строка - это одномерный массив типа char, заканчивающийся нулевым байтом. Нулевой байт - это байт, каждый бит которого равен нулю. Для нулевого байта определена специальная символьная константа '\0'. Это следует учитывать при описании соответствующего массива символов. Так, если строка должна содержать N символов, то в описании массива следует указать N+1 элемент.
# include <stdio.h>
# include <iostream.h>
/* Ввод строки с клавиатуры */
main() {
char str[80]; /* Зарезервировали место для строки */
cout<<"Bвeдите строку длиной менее 80 символов:"<<endl;
cin>>str; /* читает строку с клавиатуры, пока не нажмете клавишу Enter */
cout<<"Bы ввели строку \n" << str;
printf("Bвeдите строку длиной менее 80 символов:");
gets(str); /* читает строку с клавиатуры, пока не нажмете клавишу Enter */
puts(str);
printf("BBeдите еще одну строку длиной менее 80 символов: ");
scanf("%s", str); /* читает строку с клавиатуры, пока не встретится пробел */
printf("Bы ввели строку ");
printf("Bы ввели строку %s \n", str);
}