Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Мет-каС++.doc
Скачиваний:
18
Добавлен:
31.05.2015
Размер:
734.21 Кб
Скачать

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

  1. Укажите типы массивов, применяемых в языке С.

  2. Формы (способы) работы с элементами массива.

  3. Как описываются строки в языке С?

  4. Чем отличаются функции scanf() и gets(), printf() и puts()?

Лабораторная работа №4 Многомерные массивы, указатели, динамическое распределение памяти

Цель работы:

Изучить работу с многомерными массивами, освоить возможности динамического размещения данных.

Краткие теоретические сведения

Кроме одномерных массивов возможна работа с многомерными массивами. Объявление многомерного массива:

<тип><имя>[<размер 1 >][<размер 2 >]…[<размер N>]={{список начальных значений}, {список начальных значений},…};

Наиболее быстро изменяется последний индекс элементов массива, поскольку многомерные массивы размещаются в памяти компьютера в последователь­ности столбцов.

Например, элементы двухмерного массива b[2][1] размещаются в памяти в следующем порядке:

b[0][0], b[0][1], b[1][0], b[1][1], b[2][0], b[2][1].

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

int a[3][4] = {{0,1,2,0},{9,-2,0,0},{-7,1,6,8}};

Если в какой-то группе {…} отсутствует значение, то соответствующему элементу присваивается 0. Предыдущий оператор будет эквивалентен следующему определению:

int a[3][4] = {{0,1,2},{9,-2},{-7,1,6,8}};

Пример программы

Создать двумерный массив целых чисел NxM (N и M не более 50), используя функцию rand и вывести на экран в форме матрицы, N,M ввести с клавиатуры:

#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

#define rnd (rand()/ 32768.0) // rand - генератор случайных чисел от 0 до

int, rnd – от 0 до 1

void main(void)

{ int i,j,n,m,a[50][50];

puts(“\n Input n, m:”); scanf(“%d %d”,&n,&m);

printf(“\n Array a \n”);

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

for(j=0; j<m; j++) {

a[i][j]=rnd*10-5; // диапазон от –5 до 5

printf(“%d%c“, a[i][j], (j= =m-1)?’\n’:’ ‘);

}

getch();

}

Указатели и операции над адресами

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

- по имени, как мы до сих пор делали;

- по указателю (косвенная адресация).

Указатель – это переменная, которая может содержать адрес некоторого объекта в памяти компьютера, например адрес другой переменной. И через указатель, установленный на переменную можно обращаться к участку оперативной памяти, отведенной компилятором под ее значения.

Указатель объявляется следующим образом:

тип *идентификатор;

Например: int *a, *d;

float *f;

Здесь объявлены указатели a, d, которые можно инициализировать адресами целочисленных переменных и указатель f, который можно инициализировать адресами вещественных переменных.

С указателями связаны две унарные операции: & и *. Операция & означает «взять адрес» операнда (т.е. установить указатель на операнд). Данная операция допустима только над переменными. Операция * имеет смысл: «значение, расположенное по указанному адресу» и работает следующим образом:

- Определяется местоположение в оперативной памяти переменной типа указатель.

- Извлекается информация из этого участка памяти и трактуется как адрес переменной с типом, указанным в объявлении указателя.

- Производится обращение к участку памяти по выделенному адресу для проведения некоторых действий.

Пример 1:

int x, /* переменная типа int */

*y; /* указатель на элемент данных типа int */

y=&x; /* y - адрес переменной x */

*y=1; /* косвенная адресация указателем поля x

/* “по указанному адресу записать 1”, т.е. x=1; */

Пример 2:

int i, j=8, k=5, *y;

y=&i;

*y=2; /* i=2 */

y=&j; /* переустановили указатель на переменную j */

*y+=i; /* j+=i , т.е. j=j+1 -> j=j+2=10 */

y=&k; /*переустановили указатель на переменную k */

k+=*y; /* k+=k, k=k+k = 10 */

(*y)++; /* k++, k=k+1 = 10+1 = 11 */

Говорят, что использование указателя означает отказ от именования (разыменование) адресуемого им объекта.

Отказ от именования объектов при наличии возможности доступа по указателю приближает язык С по гибкости отображения «объект-память» к языку ассемблера.

При вычислении адресов объектов следует учитывать, что идентификатор массива и функции именует переместимую адресную константу (термин ассемблера), или константу типа указатель (термин языка C). Такую константу можно присвоить переменной типа указатель, но нельзя подвергать преобразованиям:

int x[100], *y;

y=x; // присваивание константы переменной

...

x=y; // Ошибка: в левой части - указатель-константа

Указателю-переменной можно присвоить значение другого указателя либо выражения типа указатель с использованием, при необходимости операции приведения типа (приведение необязательно, если один из указателей имеет тип "void *").

int i, *x;

char *y;

x=&i; /* x -> поле объекта int */

y=(char *)x; /* y -> поле объекта char */

y=(char *)&i; /* y -> поле объекта char */

Рассмотрим фрагмент программы:

int a=5, *p, *p1, *p2;

p=&a; p2=p1=p;

++p1; p2+=2;

printf(“a=%d, p=%d, p=%p, p1=%p, p2=%p.\n”,a,p,p,p1,p2);

Результат выполнения:

a=5, *p=5, p=FFC8, p1=FFCC, p2=FFD0.

Конкретные значения адресов зависят от ряда причин: архитектура компьютера, тип и размер оперативной памяти и т.д.