Читайте также:
|
|
Массивы и указатели. При описании массивов указываются тип данных и требуемый класс памяти. К массивам, как и в случае простых переменных, применяется тот же принцип умолчания. Рассмотрим примеры описаний массивов:
int b[30]; /*внешний массив из 30 целых элементов*/
float a[30]; /*автоматический массив из 30 чисел типа float*/
static char c[20]; /*статический массив из 20 символов*/
extern b[ ]; /*внешний массив; размер указан выше*/
В зависимости от класса памяти различают внешние, статические, автоматические и регистровые массивы. Рассмотрим инициализацию массивов. В описании типа можно инициализировать только внешние и статические массивы. Описание внешних и статических массивов предполагает по умолчанию обнуление элементов этих массивов.(Итак, для обнуления статического и внешнего массива ничего предпринимать не нужно). Рассмотрим пример инициализации внешнего массива, значениями элементов массива будет количество студентов в каждой группе потока:
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. Указателем на какой элемент массива является имя массива?
Дата добавления: 2015-11-04; просмотров: 99 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Тема 7. Указатели в Си. | | | Тема 9. Символы и строки в Си. |