ТОП 10:

Массивы. Адресная арифметика языка Си



Массив - это совокупность элементов данных одного и того же типа, объединенных общим именем и расположенных в непрерывной области памяти ЭВМ так, что к каждому элементу массива можно получить доступ, зная его порядковый номер или индекс.

Описание массива

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

 

int a[100], ab[2*40];

double c[200], speed[100];

char name[20];

 

Имя массива без квадратных скобок за ним имеет значение, равное адресу первого элемента этого массива.

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

 

d[0], d[1], d[2], d[3], d[4].

 

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

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

Ввод-вывод массива

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

 

#include <stdio.h>

 

void main(void)

{

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 ) { getch(); clrscr(); }

}

 

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

Инициализация массива

Инициализация - присвоение значений вместе с описанием данных. Ранее была рассмотрена инициализация простых переменных, например:

 

int a = 5;

 

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

 

int a[4] = { 15, 21, 1, 304 };

индексы элементов -> 0 1 2 3

 

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

 

int c[] = { 1, 15, 18, 11, 20 };

 

транслятор выделит 10 байт для хранения массива из 5 двухбайтовых целых чисел.

Частный случай инициализации массива - инициализация строк. Массив символов может быть проинициализирован стандартным образом:

char s[] = { 'A', 'B', 'C', 'D' };

 

Строка символов дополнительно должна завершаться нуль-символом.

char s[] = { 'A', 'B', 'C', 'D', '\0' };

 

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

char s[] = "ABCD";

этом случае нуль-символ автоматически дописывается в конец строки. Два последних примера инициализации строки совершенно эквивалентны.

Программа вычисления длины строки символов

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

 

#include <stdio.h>

void main (void)

{

int len;

char str[81];

printf("Введите строку: "); scanf("%s", str);

for(len=0; str[len]; len++);

printf("Длина строки = %d\n", len);

}

В этой программе используется цикл for с пустым оператором тела цикла. Цикл будет выполняться до тех пор, пока в строке не встретится нуль-символ, то есть пока выражение str[len] будет отлично от нуля. После окончания цикла переменная len станет равной количеству символов строки str, исключая нуль-символ.

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

 

int StrLen (char str[])

{

int len;

for(len=0; str[len]; len++);

return len;

}

При наличии функции StrLen два последних оператора предыдущей программы можно заменить одним

printf("Длина строки = %d\n", StrLen(str));

Пример обработки одномерного массива.

Дан массив из 50 целых чисел. Найти наибольший элемент в массиве и его порядковый номер.

# include <stdio.h>

#include <conio.h>

# define n 50 // определение константы n=50

int i, max, nom, a[n]; //описание массива целых чисел из n элементов

main()

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

{printf( “\n Введите элемент массива ”);

scanf ("%d", &a[i])};

for (i=1,max=a[0],nom=0; i<n; i++)

if (max<a[i])

{nom=i; max=a[i];}

printf("\n Вывод элементов исходного массива : \n");

for (i=0; i<n; i++) printf ( "%6d", a[i] );

printf ("\n Максимальное число в массиве %4d, его индекс %4d " , max, nom);

getch();

}

9.5. Двумерные массивы (массивы массивов)

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

 

int a[4][3];

 

Анализ подобного описания необходимо проводить в направлении выполнения операций [], то есть слева направо. Таким образом, переменная a является массивом из четырех элементов, что следует из первой части описания a[4]. Каждый элемент a[i] этого массива в свою очередь является массивом из трех элементов типа int, что следует из второй части описания.

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

 

Массив а Столбец 0 Столбец 1 Столбец 2
Строка 0
Строка 1
Строка 2
Строка 3

 

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

Имя двумерного массива с одним индексным выражением в квадратных скобках за ним обозначает соответствующую строку двумерного массива и имеет значение адреса первого элемента этой строки. Например, в нашем случае a[2] является адресом величины типа int, а именно ячейки, в которой находится число 30, и может использоваться везде, где допускается использование адреса величины типа int.

Имя двумерного массива с двумя индексными выражениями в квадратных скобках за ним обозначает соответствующий элемент двумерного массива и имеет тот же тип. Например, в нашем примере a[2][1] является величиной типа int, а именно ячейкой, в которой находится число 52, и может использоваться везде, где допускается использование величины типа int.

В соответствии с интерпретацией описания двумерного массива (слева-направо) элементы последнего располагаются в памяти ЭВМ по строкам.

Инициализация двумерного массива также проводится по строкам, например, для того чтобы получить вышеописанный массив a, можно было бы провести следующую инициализацию

 

int a[][3] = {

{ 18, 21, 5 },

{ 6, 7, 11 },

{ 30, 52, 34 },

{ 24, 4, 67 }

};

 

Здесь первый размер массива будет определен компилятором. Следует отметить, что второй размер массива должен быть всегда указан. Это необходимо для того, чтобы сообщить компилятору размер строки массива, без которого компилятор не может правильно разместить двумерный массив в памяти ЭВМ.

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

 

char s[][17] = {

"Строка 1",

"Длинная строка 2",

"Строка 3"

}

 

Размер памяти заказанный под каждую строку в этом случае должен быть равным длине самой длинной строки с учетом нуль-символа. При этом, для части строк (строка 1 и строка 3) будет выделено излишнее количество памяти. Таким образом, хранение строк различной длины в двумерном массиве символов недостаточно эффективно с точки зрения использования памяти.

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

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

for (j=0; j<m; j++)

{

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

scanf ("%lf", &a[i][j]);

}

 

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

 

Вывод такого же двумерного массива иллюстрирует следующий фрагмент:

 

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

{

for (j=0; j<m; j++) printf ("%9.3lf ", a[i][j]);

printf("\n");

}

В данном фрагменте после вывода очередной строки массива осуществляется переход на следующую строку дисплея.

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

 

Пример обработки многомерного массива.

Дана матрица A(3,4). Найти сумму элементов в каждой строке.

 

#include <stdio.h>

#include <conio.h>

main ( )

{ int a[3] [4], sum [3], i, j; // описание матрицы и вектора

for ( i=0 ; i<3; i++) // ввод матрицы

for ( j=0; j<4; j++)

{printf (“\n Введите элемент a [%d][%d]=”, i ,j);

scanf (“%d”,&a[i] [j];)

}

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

{sum [ i ]=0;

for ( j=0; j<4; j++)

sum [i] = sum [i]+ a[i] [ j];

}

printf (“\n Вывод матрицы:\n);

for (i=0; i<3; i++) //форматный вывод матрицы по строкам

{ for (j=0; j<4; j++)

printf (“%4d”,a [i] [j] );

printf (“\n”); // переход на новую строку

}

printf (“\n Вывод массива сумм:\n);

for (j=0; j<3; j++)

printf (“%5d”,sum [ j ] ); // вывод массива sum

getch();

return 0;

}

В программе элементы матрицы вводятся по строкам по одному с подтверждением клавишей Enter. А выводятся в общепринятом виде: каждая строка матрицы с новой строки экрана (цикл i по строкам внешний, а цикл j – внутренний). Если поменять местами циклы, то будет вывод матрицы по столбцам.







Последнее изменение этой страницы: 2016-04-08; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 54.236.59.154 (0.021 с.)