Смекни!
smekni.com

Массивы 2 (стр. 2 из 3)

Потрібно пам'ятати, що пам'ять для всіх масивів, які визначені як глобальні, відводиться в процесі компіляції і зберігається весь час, поки працює програма.

Часто двовимірні масиви використовуються для роботи з таблицями, що містять текстову інформацію. Також дуже часто використовуються масиви рядків.

ІНІЦІАЛІЗАЦІЯ МАСИВІВ


Дуже важливо уміти ініціалізувати масиви, тобто привласнювати елементам масиву деякі початкові значення. У мові С для цього є спеціальні можливості. Самий простий спосіб ініціалізації наступ­ний: в процесі оголошення масиву можна указати в фігурних дужках список ініціалізаторів:

float а[6]={1.1, 2.2, 3.3, 4.0, 5, 6};

В іншому випадку така форма запису еквівалентна набору операторів:

а[0]=1.1; а[1]=2.2; ... а [5] =6.

Багатовимірні масиви, в тому числі і двовимірні масиви, можна ініціалізувати, розглядаючи іх як масив масивів.

Ініціалізації int а[3][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

і int а[3][5]={{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}};

еквівалентні.

Кількість ініціалізаторів не зобов'язана співпадати з кількістю

елементів масиву. Якщо ініціалізаторів менше, то значення решти

елементів масиву не визначені.

У той же час ініціалізації

int а[3][5]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);

і

int а[3][5]={{1, 2, 3}, {4, 5, 6, 7, 8}, {9, 10, 11}};

різні.

//change strings: 1-6, 2-5, 3-4

#i nclude<std io. h >

void mai n()

{ int temp, i, j, a[6][4]={1,2,3,4,

5,6,7,8,

9,10,11,12,

1 3,14,1 5,16,

17,18,19,20,

21 ,22,23,24};

for (i=0;i<3;i++) for (j=0;j<4;j++)

{ temp=a[i][j]; a[i][j]=a[5-i][j]; a[5-i][j]=temp; } for (i=0; i<6; i++)

{

for (j=0;j<4;j++)

printf ("%4d", a[i][j]);

printf("&bsol;n");

}}

Символьні масиви можуть ініціалізувати як звичайний масив:

char str[15]={'В', ' о ' , ' г ' , ' 1 ' , ' а ' , ' n ' , ' d' , ' ',' С',^',^'};

а можуть - як рядок символів:

"char str[15]= Borland C++";

Відмінність цих двох способів полягає в тому, що у другому випа­дку буде доданий ще і нульовий байт. До того ж другий спосіб коро­тше. Допускається також оголошення і ініціалізація масиву без яв­ної вказівки розміру масиву. Наприклад, для виділення місця під символьний масив звичайним способом

char str[80]= "Це оголошення і ініціалізація масиву символів";

ми повинні вважати кількість символів в рядку або указати явно більший розмір масиву.

При ініціалізації масиву без вказівки його розміру


char str[ ]= "Це оголошення і ініціалізація масиву символів";

компілятор сам визначить необхідну кількість елементів масиву, включаючи нульовий байт. Можна оголошувати таким же способом маси­ви будь-якого типу:

int mass []={!, 2, 3, 1, 2, 3, 4};

Від LG: При ініціалізації можна не вказувати розмірність масиву, вона обчислюється авто­матично (проте для двовимірних масивів кількість стовпців треба указати), а при оголошенні - обов'язково. При оголошенні масивів з невідомою кількістю елемен­тів можна не вказувати розмір тільки в самих лівих квадратних дужках.

ПОКАЖЧИКИ І АДРЕСИ (Керніган, Рітчі і Б.І.Березін,С.)(Б.Березін)

Пам'ять машини являє собою масив послідовно розташованих і пронумерованих комірок, з якими можна працювати окремо і зв'язани­ми ділянками. Покажчик - це група комірок в пам'яті комп'ютера, в яких може зберігатися адреса.

Унарний оператор & видає адресу об'єкта, так що ін­струкція

р=&а;

привласнює адресу комірки а змінній р (тепер р вказує на а або по­силається) .

Оператор & застосовується тільки до об'єктів, розташованих в пам'яті: до змінних і елементам масивів. Його операндом не може бути ні вираз, ні константа, ні регістрова змінна.

Унарний оператор * є оператор розкриття посилання. Застосований до покажчика, він видає об'єкт, на який даний покаж­чик посилається.

ОГОЛОШЕННЯ ПОКАЖЧИКІВ

Якщо змінна буде покажчиком, то вона повинна бути оголошена таким чином:

тип *<ім'я змінної>;

У цьому оголошенні тип - деякий тип мови С, визначальний тип об'єкта, на який вказує покажчик (адреса якого містить); * - озна­чає, що наступна за нею змінна є покажчиком.

ОПЕРАЦІЇ НАД ПОКАЖЧИКАМИ

З покажчиками пов'язані дві спеціальні операції.: & і *. Обидві ці операції є унарними, т. е. мають один операнд, перед якими вони ставляться. Операція & відповідає операції "взяти адресу". Опера­ція * відповідає словам "значення, розташоване за вказаною адре­сою" .

Особливість мови С полягає в тому, що знак * відповідає двом операціям, що не мають один до одного ніякого відношення: арифме­тичній операції множення і операції взяти значення. У той же час сплутати їх в контексті програми не можливо, оскільки одна з опе­рацій унарна (містить один операнд), інша - множення - бінарна (містить два операнди). Унарні операції & і * мають найвищий пріо­ритет нарівні з унарним мінусом.


В оголошенні змінної, що є покажчиком, дуже важливий базовий тип. Якщо покажчик має базовий тип int, то змінна займає 2 байти, char - 1 байт тощо. Приклад.

int а=3, Ь=5;

int *р;

р = &а; /* тепер р вказує на а*/ Ь = *р; /* b тепер дорівнює З*/ *р= 0; /*а тепер дорівнює О*/

&*а => а - розадресація.

Унарні оператори * і & мають більш високий пріоритет, ніж арифметичні оператори:

b = *р + 1 (взяти те, на що вказує р, додати до нього 1, а результат привласнити змінній b.

До покажчиків можна застосувати операцію привласнення. Покаж­чики одного і того ж типу можуть використовуватися в операції при­власнення, як і будь-які інші змінні. Розглянемо приклад. #include <stdio. h> void mai n() { int x= 1 0;

int *p, *g;

p=&x;

g=p;

printf("%p", р); /* друк вмісту р */

printf("%p",g); /* друк вмісту g */

р г і n t f (" % d % d ", x, * g); / * друк величини хі величини за адресою g*/

} Результат: FFF4 FFF4 10 10

У цьому прикладі приведена ще одна специфікація формату функ­ції printf() - %р. Цей формат використовується для друку адреси пам'яті в шістнадцятковій формі.

Не можна створити змінну типу void, але можна створити покаж­чик на тип void. Покажчику на void можна привласнити покажчик будь-якого іншого типу. Однак при зворотному привласненні необхід­но використати явне перетворення покажчика на void/­void *pv;

float f, *pf;

pf=&f;

pv=pf;

pp=(fioat*) pv;

У мові С допустимо привласнити покажчику будь-яку адресу па­м'яті. Однак, якщо оголошений покажчик на ціле

int *р;

а за адресою, яка привласнена даному покажчику, знаходиться змінна х типу float, то при компіляції програми буде видане повідомлення про помилку в рядку

р=&х;

Цю помилку можна виправити, перетворювавши покажчик на int до типу покажчика на float явним перетворенням типу:

p=(int*)&x;

Але при цьому втрачається інформація про те, на який тип вка­зував початковий покажчик.

Як і над іншими типами змінних, над покажчиками можна виробля­ти арифметичні операції: складання і віднімання (операції ++ і є окремими випадками операцій складання і віднімання). Арифметичні


дії над покажчиками мають свої особливості. Виконаємо найпростішу програму

#include <stdio. h> void main() { і n t x= 1 0;

int *p, *g;

p=&x;

g=p;

printf("%p", p); /* друк вмісту p */ printf("%p", p++); /* друк вмісту g */ } Результат: FFF4 FFF6

Після виконання цієї програми ми побачимо, що при операції ++1 значення покажчика р збільшилося не на 1, а на 2. І це правильне, оскільки нове значення покажчика повинно вказувати не на наступну адресу пам'яті, а на адресу наступного цілого. А ціле, як ми па­м'ятаємо, займає 2 байти. Якби базовий тип покажчика був не int, a double, то були б надруковані адреси, відмінні на 8 (Результат:

FFEE FFF6), саме стільки байт пам'яті займає змінна типу double, тобто при кожній операції ++р значення покажчика буде збільшувати­ся на кількість байт, що займаються змінної базового типу покажчи­ка .

Операції над покажчиками не обмежуються тільки операціями ++ і

--. До покажчиків можна додавати деяке ціле або відняти ціле. int *p=2000; float *p=2000;

Р=Р+3; р=р+10;

Результат: р=2006 Результат: р=2040

Загальна формула для обчислення значення покажчика після вико­нання операції р=р+п; буде мати вигляд

<р>=<р>+п*<кільк.байтів пам'яті базового типу покажчика>

Можна також відняти один покажчик з іншого. Так, якщо р і pi -покажчики на елементи одного і того ж масиву, то операція р-рі дає такий же результат, як і віднімання індексів відповідних елементів масиву.

Інші арифметичні операції над покажчиками заборонені, напри­клад не можна скласти два покажчики, помножити покажчик на число і т.д.

#include <std io. h > void rnai n() { int *p, *g, x; p=&x;

g=p;

printf("&bsol;n&bsol;n&bsol;np=%p", p); P= P + 8; printf(" p+5=%p", p); printf(" g=%p", g); printf(" p-g=%p", p-g);

} Результат: p=07DO p+5=07EO g=07DO p-g=0008

#incl ude <std io. h> void main() { int *p, *g, x; p=&x;

g=p;

p r і n t f (" &bsol; n &bsol; n &bsol; n p = % p ", p); P= P + 8; printf(" p+5=%p", p); printf(" g=%p", g); printf(" p+g=%p", p+g); } Результат: Error UKAZAT2.CPP 14: Invalid pointer addition

Покажчики можна порівнювати. Застосовні всі 6 операцій:

<, >, <=, >=, =, == і !=.

Порівняння р < g означає, що адреса, що знаходиться в р, менше адреси, що знаходиться в g.

Якщо рід вказують на елементи одного масиву, то індекс еле­мента, на який вказує р, менше індексу масиву, на який вказує g.