int stud[10]={10,12,14,16,12,10,17,10,15,13};

main( )

{ int i;

extern int stud{ }; /*необязательное описание*/

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

printf(“Группа N %d %d студентов”, i+1, stud[i]); }

Массив stud[10] инициировали списком, заключенным в скобки, используя при этом запятые для разделения элементов списка. Количество элементов в списке должно соответствовать размеру массива. Если элементов в списке меньше размера массива, то оставшиеся элементы массива будут иметь нулевые значения. Если элементов в списке больше, будет сообщение об ошибке.

Инициализацию элементов массива можно осуществить и в следующем виде:

int stud[ ]={10,12,15,16,17,11,18,10};

main ( )

{ int i;

extern int stud [ ];

for (i=0; i<sizeof stud/(sizeof(int)); i++)

printf (“Группа N %d %d студентов.\n”,i+1,stud[i]); }

Если для инициализации массива используются пустые кнопки, то компилятор сам определяет количество элементов в списке и выделит для него массив нужного размера. При определении размера массива используется оператор sizeof. Оператор sizeof определяет размер в байтах объекта или типа. Следующего за ним. Для получения количества элементов массива общее число байтов, занимаемое массивом, делится на 2 (в данной системе размер каждого элемента типа int равен 2 байтам). В общем случае делится на значение переменной sizeof соответствующего типа.

Указатели массивов. Ранее было отмечено, что указатели позволяют организовать работу с символическими адресами. (В этом случае обработка массива будет организована более эффективно). Обозначение массива представляет собой скрытую форму использования указателей.

НЕ нашли? Не то? Что вы ищете?

Например, имя массива определяет также последний элемент, т. е. если a[ ] массив, то последний a[0].

Оба значения являются константами типа указатель, т. к. они не изменяются на протяжении всей программы. Их можно присваивать (как значения) переменной типа указатель и изменять значение переменной. Рассмотрим пример, в котором к значению указателя прибавляется число:

{ int a[4], *pti, i;

float b[4], *ptf;

pti=a; /*присваивает адрес указателю массива*/

ptf=b;

for (i=0, i<4,i++)

printf(“Указатели +%d: %8u %10u\n”, i, pti+i, ptf+i); }

Результат:

указатель +0: 56014 56026 (начальные адреса массивов)

указатель +1: 56016 56030 (результат прибавления единицы к адресу)

указатель +2: 56018 56034

указатель +3: 56020 56038

Единицей адресации является байт, но тип int использует 2 байта, а тип float – 4 байта.

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

Рассмотрим следующие равенства:

a+2==&a[2]; /*один и тот же адрес*/

*(a+2)==a[2]; /*одно и то же значение*/

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

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

Использование указателей при работе с массивами. Напишем функцию, использующую массивы, а затем перепишем ее, применяя указатели.

int func(a, l)

int a[ ], l;

{ int i, sum;

for (i=0, sum=0; i<l; i++)

if (a[i]%2!=0)

sum+=a[i];

return (sum); }

for (i=0,sum=0;i<l; i++)

sum+=a[i];

return ((int) (sum/l)); }

Оператор вызова в вызывающей программе может выглядеть следующим образом:

func(x, size);

Перепишем функцию с использованием указателей. Объявим pа указателем на тип int. Затем заменим элемент массива a[i] на соответствующее значение: *(pa+i).

int func(pa, l)

int *pa, l;

{ int i, sum;

for (i=0, sum=0; i<l; i++)

sum+=*(pa+i);

return ((int) (sum/l));

}

for (i=0, sum=0; i<l; i++)

if (*(pa+i)%2!=0)

sum+=*(pa+i);

return (sum); }

Вызов функции остается в том же виде:

func(x, size)/

Т. к. имя массива является указателем, отметим, что следующие операторы описания идентичны по действию: оба объявляют ра указателем:

int pa[ ]; и int *pa;

В программе можно применять любой из них, хотя до сих пор мы использовали второй в виде *(pa+i).

Использование указателей при работе с двумерными массивами. Рассмотрим массив a[3][2].

int a[3][2]; /* массив типа int из 3 строк и 2 столбцов */

int *pri; /* указатель на целый тип */

pri=a; /* указатель указывает на элемент a[0][0] */

a==&a[0][0]; /* pri+1 указывает на a[0][1] */

Т. обр. в нашем примере:

pri==&a[0][0]; /* 1-я строка, 1 столбец */

pri+1==&a[0][1]; /* 1-я строка, 2 столбец */

pri+2==&a[1][0]; /* 2-я строка, 1 столбец */

pri+3==&a[1][1]; /* 2-я строка, 2 столбец */

pri+4==&a[2][0]; /* 3-я строка, 1 столбец */

pri+5==&a[2][1]; /* 3-я строка, 2 столбец */

Двумерный массив представлен как массив массивов, т. е. можно рассмотреть 3 строки, каждая из которых является массивом из двух элементов. Имя первой строки a[0], второй – a[1], третьей – a[2]. Имя массива является указателем на этот массив, т. е. ссылается на первый его элемент. Значит

a[ 0]==&a[0][0]

a[ 1]==&a[1][0]

a[ 2]==&a[2][0].

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

main( )

{ static int b[3][4]={{6,4,8,10},

{10,20,30,40},

{20,40,60,80}};

int i;

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

printf(“Среднее значение строки %d равно %d\n”, i, func(b[i], 4));

/*b[i] – одномерный массив из 4 элементов*/

}

/*нахождение среднего значения в одномерном массиве*/

int func(x, n)

int x[ ],n;

{ int l;

float s;

for (l=0, s=0; l<n; l++)

s+=x[l];

return ((int) (s/n)); }

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

main()

{ static int b[3][4]={{6,4,8,10},

{10,20,30,40},

{20,40,60,80}};

sr(b); }

Приведем заголовок функции sr(b):

sr(b)

int b[ ][4];

int mult (int b[ ][4], int m)

{ int i, j; p=1;

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

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

if (b[i][j]!=0) p=p*b[i][j]; }

Рассмотрим еще один способ:

Дан массив b[5,4]. Можно привести такое описание:

mult (int a[ ], int size)

Обращение к функции будет иметь вид:

mult (b, 5*4); (b будет рассматриваться как одномерный массив, содержащий 20 элементов).

Основная литература: 1осн[295-304], 2осн[346-370], 3осн[84-108],

Дополнительная литература: 9доп[135-190], 11доп[4-13]

Контрольные вопросы:

1. Приведите примеры инициализации различных видов массивов?

2. Что содержать указатели в качестве значения?

3. Какие три значения могут использоваться для инициализации указателя?

4. К переменным какого класса памяти не может быть применена операция взятия адреса?

5. Указателем на какой элемент массива является имя массива?

Тема 9. Символы и строки в Си.

Объявление строки символов. Имеется несколько способов определения строк. К основным способам относятся использование строковых констант, массивов типа char и массивов, состоящих из символьных строк. Строковая константа заключается в двойные кавычки. Символы, заключенные в кавычки, и завершающий символ ‘\0’ записываются в последовательные ячейки памяти. Компилятор подсчитывает количество символов для определения размера памяти при запоминании (размещении) строки. Строковые константы можно определять при помощи директивы #define. Если в строке нужно использовать символ двойной кавычки, то перед этим символом записывается символ обратной дробной черты. Например:

printf (“\” Сведения о сессии”\n”);

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

char c[ ]=”Определение максимального балла”; (внешний массив)

Как и в случае обычных массивов имя c является указателем на первый элемент массива:

c==&c[0]; *c==’0’, и *(c+1)==c[1]==’n’;

Используем указатель для создания строки. Например:

char *c1=”\n ввод баллов”;

Это почти то же самое, что и

static char c1[ ]=”\n ввод баллов”;

Оба описания говорят об одном: с1 является указателем строки. Можно явно задать размер памяти. Во внешнем описании можно записать:

char c[35]=”определение максимального балла”; вместо

char c[ ]=”определение максимального балла”;

Число элементов на один символ больше, чем длина строки (включая нуль-символ). Как и в других статических или внешних массивах, любые использованные элементы автоматически инициализируются нулем (который в символьном виде является нуль-символом, а не символом цифры нуль).

Массивы символьных строк. Рассмотрим массив символьных строк, каждая строка массива представляет собой символьный массив. Приведем описание статического массива в следующем виде:

static char *m[4]={“регистр”,”ячейка”,”указатель”,”элемент”};

Массив *m[4]является массивом, состоящим из 4 указателей на символьные строки. Итак, т. к. символьные строки являются массивами, то имеется в рассмотрении 4 указателя на эти массивы. Первым указателем является m[0], он ссылается на первую строку. Второй указатель m[1] ссылается на вторую строку. При этом каждый указатель, в частности, ссылается на первый символ своей строки:

*m[0]==’р’; *m[1]==’я’; *m[2]==’у’; *m[3]==’э’;

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

{{…},{…},…,{…}};

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

static char m[4][10];

неиспользованные (лишние) элементы строки статического (внешнего) массива инициализируются символом “\0” (нуль-символом).

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27