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

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

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

double y[] = {1.0, 2.0,3.0,4.0}; char str[] = “abcdef”

В данном примере длину массива компилятор вычисляет по количеству начальных значений, перечисленных в фигурных скобках. После такого объявления элементам массива yприсвоятся следующие значения: y[0]=1.0, y[1]=2.0, y[3]=3.0, y[4]=4.0. Количество элементов в символьном массиве на единицу больше, чем количество символов в строковой константе, использованной для инициализации. Последний элемент массива в таком случае всегда равен ‘\n’. Таким образом, массив str, будет состоять из семи элементов и им присвоятся следующие значения: str[0]=’a’,str[1]= ‘b’,str[2]=’c’,str[3]=’d’,str[4]=’e’,str[5]=’f’,str[6]=’\n’.

Если количество начальных значений меньше, чем объявленная длина массива, то начальные значения примут только первые элементы массива:

intz[10] = {1,2,3,4};

В этом примере будут определены значения только элементов z[0],z[2],z[3],z[4]. Остальные элементы определены не будут.

Пример инициализации двумерного массива представлен ниже:

intx[2][3] = {{1,2,3},{4,5,6}};

После такого объявления элементам массива присвоятся следующие значения: x[0][0] =1,x[0][1] =2,x[0][2] =3,x[1][0] =4,x[1][1] =5,x[1][2] =6.Тот же результат можно получить с одним списком инициализации:

intx[2][3] = {1,2,3,4,5,6};

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

Массивы и указатели

Массивы языков Си и Си++ обладают очень интересным свойством, отличающим их от массивов в других алгоритмических языках. При объявлении массивов, как и в других алгоритмических языках, им выделяются участки оперативной памяти. Но как только память для массива выделена, имя массива воспринимается как константный (т. е. неизменный) указатель того типа, к которому отнесены элементы массива. Однако для этого указателя две операции выполняются особенным образом:

  • Операция sizeof,примененная к имени массива, определяет размер выделенного участка памяти для всего массива, а не участка, выделенного для указателя. Например, значение выражения sizeof(x) для последнего примера равно 12.

  • Операция получения адреса, примененная к имени массива, определяет адрес начального (с нулевым индексом) элемента массива.

Во всех остальных случаях значением имени любого массива является адрес первого (нулевого) элемента массива, и это значение невозможно изменить. Таким образом, для любого массива соблюдается соотношение:

Имя_массива == &имя_массива == имя_массива [0]

Если применить это правило к рассмотренному ранее массиву х, то получим:

x== &x== &x[0]

Да, но что такое x[0]? Ведь массив х объявлен как двумерный! Дело в том, что в соответствии с синтаксисом языка Си, в языке существуют только одномерные массивы. Однако, элементами одномерного массива, в свою очередь, могут быть массивы. Поэтому двумерный массив определяется как массив массивов. Таким образом, х[0] – это нулевой элемент массива х (нулевая строка матрицы х), который в свою очередь является одномерным массивом элементов типа int,x[1] – первый элемент (первая строка матрицы) и т. д. Аналогично строятся трехмерные и n – мерные массивы. Но, если x[0] –это нулевая строка матрицы х, то как обозначится ее нулевой элемент? Очевидно, как x[0][0]. Поэтому:

x== &x==x[0] = &x[0] == &x[0][0].

Итак, запомним, что имя массива – это константный указатель на тип данных входящих в него элементов, значение которого – адрес нулевого элемента. Например, inta[10]означает, что а – константный указатель на тип intи a== &a[0],floaty[5][8] –означает, что у - константный указатель на тип floatи y==y[0] = &y[0][0].Но в таком случае, что может означать выражение х + 1 и y[0] +1? Очевидно, a+ 1означает увеличение адреса на одно поле типа int(вспомним операции над указателями), т. е. на два байта, что предполагает перемещение к элементу x[1]. Выражение y[0] +1означает увеличение адреса на одно поле типа float, т. е. на 4 байта, что предполагает перемещение к элементу y[0][1].Таким образом, справедливо:

a[1] == *(a + 1)

y[0][1] == *(y[0] +1) .

Или в общем виде:

a[i] == *(a + i)

y[0][j] == *(y[0] +j) .

Следует отметить, что хотя y==y[0], выражение *( y+j)не воспринимается транслятором как перемещение к j–ому элементу нулевой строки. Дело в том, что в этом выражении слева от знака ‘+’ должен размещаться объект, который может восприниматься как одномерный массив (y–это двумерный массив, а y[0] – одномерный массив).

А теперь вернемся к указателям и рассмотрим одновременное участие указателя и массива. Пусть имеются такие объявления:

int z[10];

int *pz;

pz= &z[0];

В таком случае: pz+ 1 -это адрес первого элемента; pz+ 2 -это адрес второго элемента; pz+i-это адрес i -го элемента;

кроме того: pz==z

pz[i] == *(pz+i) ==z[i] &z[i] ==z+iНиже приведен пример программы, демонстрирующий использование указателей при обращении к элементам массива и использование имен массивов как указателей при обращении к тем же элементам.

#include<stdio.h>

#include<conio.h>

void main ()

{ int z[2][3]={1,2,3,4,5,6};

int a[3]={1,2,3};

int *p;

int i,j;

clrscr();

printf("***array z***\n");

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

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

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

printf("\n");

}

printf("************\n");

p = z[1];

printf("z[0][1] = %d\n",z[0][1]);

printf("*(z[0]+1) = %d\n",*(z[0]+1));

printf("*(p + 1)= %d\n",*(p + 1));

printf("z[1][1] = %d\n",z[1][1]);

p=a;

printf("***array a***\n");

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

printf("%d ",*(p + i));

getch();

}

При выполнении этой программы на экране получим:

"***array z***

1 2 3

4 5 6

z[0][1] = 2

*(z[0] +1) =2

*(p + 1)=5

z[1][1]= 5

***array a***

1 2 3

В этой программе объявляются и инициируются два массива целых чисел: двумерный массив и одномерный массив а. На экране видно, что вначале выданы элементы массива z. Затем р настраивается на первую строку массива z(оператор p=z[1];). Далее мы видим, что выражение z[0][1]эквивалентно выражению *(z[0] +1)(и то и другое “достают” из массива для выдачи элемент z[0][1], равный 2); выражение *(p+ 1)эквивалентно выражению z[1][1] (и то и другое “достают” из массива для выдачи элемент z[1][1], равный 5). Далее р настраивается на массив а и значения элементов массива а выдаются в цикле по i с помощью выражения *(p+i).Любознательный читатель спросит: “А зачем нам нужны такие хитрости? Почему нельзя всегда “честно” пользоваться обращением к элементам массивов переменными с индексами (z[i][j], a[i])?”. Ответ такой: “Да, можно поступить и так, но тогда мы не сможем использовать рассмотренные возможности для разработки эффективных программ на Си и вряд ли сможем считать себя программистами на Си ”. А теперь вернемся к вопросу, который возник при решении задачи 2 настоящего раздела. Как реализовать динамический массив, т. е. массив с заранее неизвестным числом элементов?

Соседние файлы в папке attachments_05-09-2012_18-55-54