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 |


