Индивидуальные задания к лабораторной работе №12 приведены в предыдущей работе.
Контрольные вопросы для подготовки и самостоятельной работы
1 Какой заголовочный файл необходим для работы с библиотечными функциями обработки символьных данных?
2 Какой символ необходим в конце строки для нормальной работы со строками?
3 Что означает модификатор const при объявлении формальных параметров функций?
4 Для чего можно использовать массив указателей при работе с символьными данными?
5 Объясните форматы приведённых в теоретической части функций.
6 Что означает буква n в функциях strncmp(), strnset()?
7 Что означает буква i в strcmpi()?
8 Что означает дополнительная буква r в функции strrchr()?
9 Что адресует указатель на n- ный символ в строке?
Лабораторная работа № 13
Вложенные циклы. Многомерные массивы. Массивы указателей
(2часа)
Цель работы: изучить конструкции языка С и операторы для обработки многомерных массивов с применением оператора цикла for.
Теоретические сведения
Массивы и указатели, индексные выражения
Идентификатор массива является указателем на первый элемент этого массива. По определению, оператор индексирования [ ] интерпретируется таким образом, что А[В] эквивалентно *(А+В). В соответствии с правилами преобразования, которые выполняются при операции "+", если А является именем массива (имя массива является указателем на тип элементов массива), то индексное выражение А[В] указывает на В -ый элемент массива А. В является индексом массива и имеет целый тип (int). Индексирование является коммутативной операцией, поэтому допустимы записи В[А], * (В+А).
А[ ][ ][ ][ k]
В случае использования многомерных массивов интерпретация индексного выражения следующая. Если А[i][j][кi][k] представляет собой n- мерным массив с рангом i*j *...*k, то, если A встречается в выражении, он рассматривается как вектор, содержащий i (n -1)- мерных массивов с рангом j*...*k. Имя массива A является указателем на этот вектор. Если к указателю применяется оператор (*) в явном или в неявном виде (как результат индексирования), то результат будет указывать на элемент (n-1)- мерного массива.
|
Рассмотрим, например массив int x[N][M] - массив целых чисел размерности N* M. Массивы в языке С хранятся построчно (последний индекс изменяется быстрее), а первый индекс (N) в объявлении массива позволяет определить объем необходимой для массива памяти, но не играет никакой роли в вычислении смещения указателя при доступе к элементу массива – х[i][j]. Данный элемент расположен фактически в i+1 строке, j+1 столбце, т.к. индексы в массиве начинаются с нулевого. Массив рассматривается как одномерный (вектор), содержащий N элементов, каждый из которых является массивом (в данном случае) из М элементов типа int. Имя массива x является указателем на нулевой элемент массива. Рассмотрим элемент данного массива x[i][j]. В выражении * x[i], которое эквивалентно * (x+i), x – указатель на нулевой элемент массива. Для доступа к i- тому элементу i умножается на длину объекта, на который указывает указатель, а именно на длину массива (строки) из М элементов типа int, т.е. (i*М*sizеof(int)). В результате индексной операции получается указатель, который адресует нулевой элемент i -го одномерного массива (строки) х[i][o]. Для второго индекса снова применяется тот же алгоритм.. Указатель смещается на величину (j* sizеof(int)), после чего происходит разыменование. На этот раз результат будет иметь тип int. Элемент массива можно представить также в виде *(*(х+i)+j).
|
Таким образом, общее смещение в байтах указателя на нулевой элемент массива X[N][M] при доступе x[i][j] вычисляется по формуле ((i*M+j)* sizеof(int)).
Для трёхмерного массива float х3D[N][M][K] величина смещения в байтах для доступа к элементу х3D[i][j][k] вычисляется по формуле
i*(M+K)+j*R+k)* sizеof (float).
Для доступа к элементу массива 4х3D[i][j][k] можно также использовать выражение *(*(*(х3D+i)+j)+k).
Пример
/* ЗАНЯТИЕ N 13
Разработал Петров Ю.В.
Объявить массивы различной размерности, выполнить их инициализацию
с применением указателей и массива указателей. Получить доступ к
элементам массивов с использованием различных синтаксических
конструкций */
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
enum en{K=2,N=3,M=4};//Аналгично #define K 5 #define N 5 #define M 4
typedef int mas1_int[N*M];//Объявление типа 1-мерный массив (вектор)
typedef int mas2_int[N][M];//Объявление типа 2-мерный массив
//(массив 1-мерных массивов) элементов типа int
typedef int mas3_int[K][N][M]; //Объявление типа 3-мерный массив
//(вектор 2-мерных массивов) элементов типа int
int * matrix(int n_str, int m_stolb);//Функция инициализации массива
//с применением указателей и выделением памяти для массива в "куче"
void main()
{ int d,a,b,i,j,k;
int *pi, *para, *c[N];
mas1_int mas1; mas2_int mas2; mas3_int mas3;
clrscr(); randomize();
for(i=0;i<N;i++) c[i]=&mas2[i][0];
printf("\nИнициализация одномерного массива:\n");
for(i=0;i<N*M;i++)
{ mas1[i]=random(10);
printf("mas1[%d]=%2d ",i,mas1[i]);
if ((i+1)%5==0) printf("\n");
}
printf("\nВведите индекс элемента одномерного массива i<N: ");
|
scanf("%d",&i);
pi=mas1;
printf("mas1[%d]=%2d cмещение: %2d байт\n",i,*(pi+i),i*sizeof(int));
getch();
randomize();
printf("Инициализация двумерного массива\n");
printf("c использованием массива указателей:\n");
for(i=0;i<N;i++)
for(j=0;j<M;j++)
{ *(c[i]+j)=random(10);
printf("c[%d][%d]=%2d ",i,j,*(c[i]+j));
if ((j+1)%M==0) printf("\n");
}
printf("\nВведите индексы элемента двумерного массива i<N, j<M: ");
scanf("%d %d",&i,&j);
printf("mas2[%d][%d]=%2d cмещение: %2d байт \n",i,j,mas2[i][j],\
(i*M+j)*sizeof(int));
printf("Другие формы записи доступа к элементам двумерного массива:\n");
printf("*(*mas2+i*M+j)= %2d\n", *(*mas2+i*M+j));
printf("(*mas2)[i*M+j] = %2d\n", (*mas2)[i*M+j]);
printf("*(*(mas2+i)+j)= %2d\n", *(*(mas2+i)+j));
printf("*(c[i]+j)= %2d\n", *(c[i]+j));
getch(); randomize();
printf("\nИнициализация двумерного массива в функции\n");
printf("с выделением памяти для массива в \"куче\":\n");
para=matrix(N,M);
for(i=0;i<N;i++)
for(j=0;j<M;j++)
{ printf("mas2[%d][%d]=%2d ",i,j,*(para+i*M+j));
if ((j+1)%M==0) printf("\n");
}
printf("\nВведите индексы элемента двумерного массива i<N, j<M: ");
scanf("%d %d",&i,&j);
printf("mas2[%d][%d]=%2d cмещение: %2d байт ",i,j,*(para+i*M+j),\
(i*M+j)*sizeof(int));
free(para); //Освобождение памяти, выделенной для массива в "куче"
getch(); randomize();
printf("\nИнициализация трехмерного массива:\n");
for(i=0;i<K;i++)
for(j=0;j<N;j++)
{ for(k=0;k<M;k++)
{ mas3[i][j][k]=random(10);
printf("mas3[%d][%d][%d]=%2d ",i,j,k,mas3[i][j][k]);
if ((k+1)%4==0) printf("\n");
}
if ((j+1)%N==0) printf("\n");
}
printf("\nВведите индексы элемента трехмерного массива i<K, j<N, k<M: ");
scanf("%d %d %d", &i, &j, &k);
printf("mas3[%d][%d][%d]=%2d cмещение: %2d байт\n",i,j,k,\
mas3[i][j][k],(i*M*N+j*M+k)*sizeof(int));
printf("Другие формы записи доступа к элементам трехмерного массива:\n");
printf("*(**mas3+i*M*N+j*M+k)= %2d\n",*(**mas3+i*M*N+j*M+k));
printf("*(*(*(mas3+i)+j)+k)= %2d\n",*(*(*(mas3+i)+j)+k));
getch();
}//main
int * matrix(int n, int m)
{ int i,j;
randomize(); //Выделение памяти для массива в "куче"
int *pa=(int *)malloc(n*m*sizeof(int));
for(i=0;i<n;i++)
for(j=0;j<m;j++) //*(pa+i*m+j)-аналогично pa[i*m+j]
{ *(pa+i*m+j)=random(51)-25;
// printf("mas[%d][%d]=%2d ",i,j,pa[i*m+j]);
// if ((j+1)%m==0) printf("\n");
}
return pa;
}
/* Инициализация одномерного массива:
mas1[0]= 6 mas1[1]= 0 mas1[2]= 0 mas1[3]= 8 mas1[4]= 4
mas1[5]= 0 mas1[6]= 7 mas1[7]= 4 mas1[8]= 0 mas1[9]= 7
mas1[10]= 6 mas1[11]= 6
Введите индекс элемента одномерного массива i<N: 10
mas1[10]= 6 cмещение: 20 байт
Инициализация двумерного массива
c использованием массива указателей:
c[0][0]= 7 c[0][1]= 0 c[0][2]= 0 c[0][3]= 1
c[1][0]= 3 c[1][1]= 8 c[1][2]= 6 c[1][3]= 3
c[2][0]= 6 c[2][1]= 9 c[2][2]= 6 c[2][3]= 1
Введите индексы элемента двумерного массива i<N, j<M: 1 3
mas2[1][3]= 3 cмещение: 14 байт
Другие формы записи доступа к элементам двумерного массива:
*(*mas2+i*M+j) = 3
(*mas2)[i*M+j]= 3
*(*(mas2+i)+j) = 3
*(c[i]+j) = 3
Инициализация двумерного массива в функции
с выделением памяти для массива в "куче":
mas2[0][0]= 7 mas2[0][1]=-1 mas2[0][2]=19 mas2[0][3]=15
mas2[1][0]=-6 mas2[1][1]=-15 mas2[1][2]= 2 mas2[1][3]=11
mas2[2][0]=-24 mas2[2][1]=24 mas2[2][2]=21 mas2[2][3]=-6
Введите индексы элемента двумерного массива i<N, j<M: 2 0
mas2[2][0]=-24 cмещение: 16 байт
Инициализация трехмерного массива:
mas3[0][0][0]= 1 mas3[0][0][1]= 9 mas3[0][0][2]= 3 mas3[0][0][3]= 1
mas3[0][1][0]= 8 mas3[0][1][1]= 7 mas3[0][1][2]= 3 mas3[0][1][3]= 8
mas3[0][2][0]= 0 mas3[0][2][1]= 3 mas3[0][2][2]= 9 mas3[0][2][3]= 0
mas3[1][0][0]= 8 mas3[1][0][1]= 6 mas3[1][0][2]= 8 mas3[1][0][3]= 5
mas3[1][1][0]= 2 mas3[1][1][1]= 6 mas3[1][1][2]= 5 mas3[1][1][3]= 5
mas3[1][2][0]= 4 mas3[1][2][1]= 9 mas3[1][2][2]= 5 mas3[1][2][3]= 4
Введите индексы элемента трехмерного массива i<K, j<N, k<M: 1 2 2
mas3[1][2][2]= 5 cмещение: 44 байт
Другие формы записи доступа к элементам трехмерного массива:
*(**mas3+i*M*N+j*M+k)= 5
*(*(*(mas3+i)+j)+k)= 5 */
Ход работы
1 Изучить теоретические сведения.
2 В соответствии с индивидуальным заданием разработать алгоритм и программу с применением указателей на массив и массив указателей для работы с двумерным и трёхмерным массивом.
3 Показать использование различных видов синтаксических конструкций, включая индексные выражения и указатели на тип элементов массива для доступа к элементам массива.
4 Набрать и отладить программу на компьютере.
5 Изучить работу операторов.
6 Получить результаты.
7 Оформить отчет.
8 Подготовиться к защите лабораторной работы, изучив контрольные вопросы по данной теме.