|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Тема 8. Использование указателей при обработке одномерных и двумерных массивовМассивы и указатели. При описании массивов указываются тип данных и требуемый класс памяти. К массивам, как и в случае простых переменных, применяется тот же принцип умолчания. Рассмотрим примеры описаний массивов: 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], Дополнительная литература: 6доп[135-190], 8доп[4-13] Контрольные вопросы: 1. Приведите примеры инициализации различных видов массивов? 2. Что содержать указатели в качестве значения? 3. Какие три значения могут использоваться для инициализации указателя? 4. К переменным какого класса памяти не может быть применена операция взятия адреса? 5. Указателем на какой элемент массива является имя массива? Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.008 сек.) |