Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Комплексное пособие Си.pdf
Скачиваний:
57
Добавлен:
12.03.2015
Размер:
1.57 Mб
Скачать

Обработка массивов

Массивы

Массив - упорядоченная последовательность пронумерованных элементов одинакового типа.

Индекс - номер элемента массива. Индексы элементов массива начинаются с нуля. Элемент массива может иметь несколько индексов. Размерность массива - количество индексов каждого элемента.

Вектор - одномерный массив (один индекс).

Матрица – двумерный массив (первый индекс - номер строки, второй - номер столбца).

Объявление массива

Переменная типа массив в Turbo C описывается следующим образом:

<Имя базового типа> <Имя массива>[<Количество элементов>];

Доступ к элементам массива осуществляется с использованием имени массива и индекса элемента. Элементы массива индексируются начиная с 0, соответственно последний элемент массива имеет индекс равный <Количество элементов>-1.

Пример работы с массивом целых чисел из 3 элементов:

int A[3];

A[0]=1;

A[1]=A[0]+5;

A[2]=A[1]/2;

printf(“%d%d%d”,A[0],A[1],A[2]);

Язык Си не имеет встроенных средств для ввода-вывода массива целиком, поэтому массив вводят и выводят поэлементно с помощью циклов, как, например, в следующей программе:

#include <stdio.h> void main(void)

{

66

double a[100]; int n, i;

printf("Введите количество чисел n = "); scanf("%d", &n);

if( n>(sizeof a)/sizeof(double) )

{ printf("Слишком много элементов\n"); return; } for(i=0; i<n; i++)

{

printf("a[%d] = ", i); scanf("%lf", &a[i]);

}

/* Операторы, обрабатывающие массив */

}

Во многих случаях удобно возложить на программу подсчет числа элементов, вводимого массива, при этом ввод завершается при появлении во входном потоке признака конца данных. Таким признаком в следующей программе служит число большее 1.0e300

#include <stdio.h> void main(void)

{

double a[100], temp; int n, end;

for(end=n=0; n<(sizeof a)/sizeof(double); n++)

{

printf("a[%d] = ", n); scanf("%lf", &temp);

if( temp>=1.0e300 ) { end=1; break; } a[n] = temp;

}

if( end )

{

/* Операторы, обрабатывающие массив */

}

else

printf("Переполнение массива\n");

}

Вывод массива, содержащего большое количество элементов желательно производить в несколько строк с остановом после заполнения экрана.

Следующий фрагмент программы выводит массив строками по 5 элементов. После вывода 120 элементов программа останавливается для просмотра выдачи. Очередные 120 элементов выводятся после нажатия на любую клавишу.

for (i=0; i<n; i++)

{

printf("%10.3lf ", a[i]);

if( (i+6) % 5 == 0 ) printf("\n"); if ((i+121) % 120 == 0 )

67

{

getch();

clrscr();

}

}

Здесь стандартная функция clrscr() очищает экран.

Использование и обработка массивов

Если в условии задачи даны переменные с индексами, для них не обязательно использовать массив. Массив нужен для входных или выходных данных, если их элементы обрабатываются неоднократно или не в том порядке, в котором вводятся или выводятся. В этих случаях приходится одновременно хранить в памяти все элементы в виде массива.

В языке СИ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных выражений следующих за идентификатором массива, причем каждое константное выражение заключается в свои квадратные скобки.

Каждое константное выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных выражения, трехмерного - три и т.д. Отметим, что в языке СИ первый элемент массива имеет индекс равный 0.

Примеры:

int a[2][3]; /*

представлено в виде матрицы

 

 

 

 

a[0][0]

a[0][1] a[0][2]

*/

 

double b[10];

 

a[1][0]

a[1][1] a[1][2]

тип double */

/* вектор

из 10 элементов имеющих

int w[3][3] =

{

{ 2, 3,

4 },

 

 

{3, 4, 8 },

{1, 0, 9 } };

Впоследнем примере объявлен массив w[3][3]. Списки, выделенные в

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

В языке СИ можно использовать сечения массива, как и в других языках высокого уровня (PL1 и т.п.), однако на использование сечений

68

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

Примеры:

int s[2][3];

Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.

int b[2][3][4];

При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению наложенному на использование сечений массива.

Пример объявления символьного массива.

char str[] = "объявление символьного массива";

Следует учитывать, что в символьном литерале находится на один элемент больше, так как последний из элементов является управляющей последовательностью '\0'.

Примеры

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

Пример

/*обращение массива*/ #include <stdio.h> main()

{

int p,i=0;

static a[10]={10,11,12,13,14, 15,16,17,18,19};

while(i<10/2)

69

{

p=a[i]; a[i]=a[9-i]; a[9-i]=p; i++;

}

i=0;

while(i<10)

printf(" %d",a[i++]);

}

Следующая программа позволяет в целочисленном массиве найти разность максимального и минимального элемента. Обратите внимание, что функция fmax при первом обращении к ней дает максимальный элемент массива, а при повторном вызове - минимальный, так как предварительно мы изменили знаки элементов на противоположные. Это изменение знаков учитывается при вызове функции printf. В языке Си отсутствует возможность динамически распределять память под массивы: надо при описании массива задать точно его размер. Но если тот же массив описывается еще раз в другой программе, размеры можно не указывать, достаточно после имени сохранить пару квадратных скобок, например int x[]. Если при вызове функции в качестве аргумента ей передается имя массива, то, в отличие от простых переменных, берется фактически адрес начала этого массива. Поэтому записи fmax(a, 10) и fmax(&a[0], 10) равносильны.

Пример

/*в массиве найти разность мин. и макс. элементов */

int fmax(x,n) int x[],n;

{

int max, i=0; max=x[0]; while(i<n)

{

if(x[i]> max) max=x[i];

i++;

}

return(max);

}

#include <stdio.h> main()

{

static int a[10]=

70

{1,-2,3,-4,5,-6,7,-8,9,-13}; max=fmax(a,10);

i=0;

while(i<10)

{

a[i]=-a[i]; i++;

}

main=fmax(a,10); printf("макс-мин=%d\n",max+min);

}

В следующем пример массив описан как внешний. Функция main подсчитывает наибольшее число одинаковых идущих подряд элементов массива, определенного вне функции main.

Пример

/*макс одинаковых подряд*/ #include <stdio.h>

int a[]={5,6,6,6,4,3,3,3,3,3,8}; int n=10;

main()

{

int i,k,max; i=k=max=1; while(i<n)

{

if(a[i]==a[i-1]) k++;

else

{

if(k>max)max=k;

k=1;

}

i++;

}

printf("kmax=%d\n",(k>max)?k:max);

}

Если, как в данном примере, размер массива пропущен, то транслятор определит его длину, считая присваиваемые значения во время начальной инициализации. Условная операция (k>max)?k:max в операторе printf предусмотрена для того частного случая, когда весь массив состоит из одинаковых элементов. Приведем несколько примеров, в которых ведется обработка двумерных массивов. Но прежде одну полезную возможность языка Си. Речь идет о препроцессорном утверждении #define, позволяющем присваивать символические имена константам. В общем случае это

71

утверждение записывают так: #define строка1 строка2 (точка с запятой не ставится).

Прежде чем исходный текст программы будет передан компилятору, он обрабатывается препроцессором, который всюду в исходном тексте заменит вхождение "строка1" на "строка2". Например, строка #define max 80, записанная в начале программы, обеспечит всюду замену указанного имени max на соответствующую константу. Замена имени связана не только числами, но и текстами. А теперь вернемся к примерам. В следующей программе строится единичная матрица a[m][m], размер которой определяется с помощью конструкции #define m 5. Сам алгоритм вычисления элементов матрицы основан на возведении (i/j)*(j/i) равно единице тогда и только тогда, когда i равно j. В остальных случаях оно равно нулю.

Пример

#define M 5 #include <stdio.h> main()

{

int a[M][M]; int j,i=0; while(i<M)

{

j=1;

while(j<M)

{

a[i][j]=(i/j)*(j/i);

printf("%d",a[i][j]);

j++;

}

i++;printf("\n");

}

}

В программе определяется минимальный элемент каждой строки матрицы и выполняется обмен местами найденного и диагональю этой же строки.

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

72