Массивы 2


B.I.Березін,С.Б.Березін(С.83) МАСИВИ І ПОКАЖЧИКИ


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


ОГОЛОШЕННЯ МАСИВУ В ПРОГРАМІ


Основна форма оголошення масиву розмірності N така:


тип <ім'я масиву>[размер1][размер2]...[размерН]


Частіше за все використовуються одновимірні масиви:


тип <ім'я масиву> [розмір] ;


тип
- базовий тип елементів
масиву, розмір - кількість елементів
одновимірного масиву.


При описі двовимірного масиву
оголошення має наступний вигляд:


тип <ім'я масиву> [размері][размер2];


У цьому описі можна трактувати оголошення двовимірного масиву як оголошення масиву масивів, т. е. масив розміру [размер2], еле­ментами якого є одновимірні масиви <ім'я масиву>[размер1].


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


ОДНОВИМІРНІ МАСИВИ


У мові С індекс
завжди починається з нуля.
Коли ми говоримо про перший елемент масиву, то маємо на увазі елемент з індексом 0. Еслі ми оголосили масив


int a[100] ;


це означає, що масив містить 100 елементів від а[0] до а[99]. Для одновимірного масиву легко підрахувати, скільки байт в пам'яті бу­де займати цей масив:


кільк.байтів=<розмір базового типу>*<кільк.елементів>.


У мові С під масив завжди виділяється безперервне місце в опе­ративній пам'яті.


У мові С не перевіряється вихід індексу за межі масиву.
Якщо масив а[100]
описаний як цілочисельний масив, що має 100 елемен­тів, а ви в програмі вкажете а[200], то повідомлення про помилку не буде видане,
а як значення елемента а[200] буде видано деяке число,
що займає відповідні 2 байти. Можна визначити масив будь-якого визначеного раніше типу, наприклад


unsigned arr[40], long double al[1000], char ch[80].





/*поміняти місцями max з min*/


#include <iostream.h> main()


{ int i,j,a[10], max. nmax, min, nmin, temp; clrscr(); for (i=0; i<10; i++) сіп » a[i]; max=min=a[0]; nmax=nmin=0; for (i=0; i<10; i++) if(a[i]>max) { max=a[i]; nmax=i;} else if(a[i]<min) {min=a[i], nmin=i;} tern p= a[n m ax]; a[n max]=a[nm і n]; a[nm і n]=temp; for (i=0; i<10; i++) cout « a[i] «" "; }


// Сортування і програвання масиву


#include<iostream.h> #include<dos. h> #'
nclude<conio. h> void main() { int temp, і, j, a[ 1 0]; clrscr(); for (i=0;i<10;i++) сіп » a [ і ]; for (i=0;i<9;i++) for (j=i+1 ;j<10;j++) if (a[i]>a[j]) { temp=a[i]; a[i]=a[j]; a[j]=temp; } for (i=0;i<1 0;i++) { cout « a[i]«" "; sound(a[i]*80); delay(500); nosou nd(); } getch(); }



МАСИВИ СИМВОЛІВ. РЯДКИ


Однак масиви типу char - символьні масиви - займають в мові осо­бливе місце. У багатьох мовах е спеціальний тип даних - рядок сим­волів (string). У мові С окремого типу рядка символів немає, а ре­алізована робота з рядками шляхом використання одновимірних маси­вів типу char. У мові С символьний рядок - це одновимірний масив типу char, що закінчується нульовим байтом. Нульовий байт - це байт, кожний біт якого рівний нулю. Для нульового байта визначена спеціальна символьна константа ' 0 ' . Це потрібно враховувати при описі відповідного масиву символів. Так, якщо рядок повинен
місти­ти N символів, то в описі масиву
потрібно указати N+1 елемент.


Наприклад, опис


char str[11] ;


передбачає, що рядок містить 10 символів, а останній байт зарезер­вований під нульовий байт. Звичайно, ми задали звичайний одновимі­рний масив, але якщо ми хочемо трактувати його як рядок символів, то це буде рядок максимум з 10 елементів.


Хоча в мові С немає спеціального типу рядка, мова допускає ряд­кові константи. Рядкова константа - це список літер, взятих в по­двійні лапки. Наприклад,


"Borland C++ ", "Це рядкова константа".


У кінець рядкової константи не треба ставити символ '0'. Це зробить компілятор, і рядок "Borland C++" в пам'яті буде вигляда-














В


о


г


1


а n


d


С


+


+


0



Є два
простих способи ввести рядок
з клавіатури. Перший спосіб -скористатися функцією scanf() зі специфікатором введення %s. Треба пам'ятати, що функція scanf() вводить
символи до першого пропуско-вого символа. Другий
спосіб - скористатися спеціальною бібліотеч­ною функцією gets(), оголошеною
в файлі stdio.h. Функція
gets() дозволяє вводити рядки, що містять пропуски.
Введення закінчується натисненням клавіші Enter. Обидві функції автоматично ставлять в кінець рядка нульовий байт. Не забудьте зарезервувати для нього місце. Як параметр в цих функціях використовується просто ім'я ма­сиву.





#i ncl ude <stdio. h> void main () { char s1[80], s2[80]; scanf( %s, "s1); І"
можна об'єднати 2 scanf в один s c a n f ( % s % s , " s 1 , s 2); * / scanf("%S", s2); printf("%sn", s1); printf("%s", s2); } ввели: Hello! Good I uck! Резул ьтат: Hello! Good


#i nclude <std io. h> void main () { char s1[80], s2[80]; gets(s1); gets(s2) puts(s1); puts(s2);


} ввели: Hello! Good luck! Результат: Hello! Good luck!



Виведення виробляється функціями printf() або puts(). Обидві фу­нкції виводять вміст масиву до першого нульового байта. Функція puts() додає в
кінці рядка, що виводиться символ нового рядка.
У функції printf() перехід
на новий рядок треба передбачати в
рядку формату самим.


ФУНКЦІЇ ДЛЯ РОБОТИ З РЯДКАМИ


Для роботи з рядками існує спеціальна бібліотека, опис якої знаходиться в файлі string.h.
Найчастіше використовуються функції


strcpyO, strcat(), strlenQ, strcmpO.


Виклик функції strcpy() має вигляд


strcpy(si, s2) ;


Функція strcpy() використовується для копіювання вмісту рядка s2 в


рядок s1.
Масив s1 повинен бути досить великим, щоб в нього вміс­тився рядок s2. Якщо місця мало, компілятор не видає вказівки на помилку або попередження; це не перерве виконання програми, але може привести до псування інших даних або самої програми і непра­вильній роботі програми надалі. Виклик функції strcat() має вигляд


strcat(sl, s2) ;


Функція strcat() приєднує рядок s2 до рядка s1 і вміщує його в
ма­сив, де знаходився рядок s1,
при цьому рядок s2 не змінюється. Ну­льовий байт, який завершував рядок s1, буде замінений першим сим­волом рядка s2. їв функції strcpyO, і в функції strcat() рядок, що виходить, автоматично завершується нульовим байтом.


Розглянемо простий приклад використання цих функцій.




Резул ьтат:


Hello, World!


Hello, World! World!



#include <stdio.h>


#і ncl ude <string . h>


main () {


char s1[20], s2[20];


strcpy(s1 , "Hello, ");


strcpy(s2, "World!");


puts(s1);


puts(s2);


strcat(s1, s2);


puts(s1);


puts(s2);


}


Виклик функції strcmpO має вигляд


strcmp(sl, s2);


Функція strcmpO порівнює рядки si і s2 і повертає значення О, якщо рядки однакові, тобто містять одне і те ж число однакових си­мволів. Під порівнянням рядків ми розуміємо порівняння в лексико­графічному значенні, так як це відбувається, наприклад, в словни­ку. Звичайно, в функції відбувається посимвольне порівняння кодів символів. Код першого символа одного рядка порівнюється з кодом символа другого рядка. Якщо вони однакові, розглядаються другі си­мволи тощо. Якщо зі лексикографічно (в значенні словника) більше s2, то функція strcmpO повертає додатне значення, якщо менше -від'ємне
значення.


Виклик функції strlen() має вигляд


strlen(s)
;


Функція strlen() повертає довжину рядка з,
при цьому завершаль­ний нульовий байт не враховується.
Виклик length("Hello") поверне


значення 5.


Розглянемо застосування цієї функції для обчислення довжини ря­дка, що вводиться з клавіатури.


#include <stdio.h>


#incl ude <string . h > m а і n () { char s(80], printf( "Введіть рядок:");


gets(s);


printf( "Рядокп%зп має довжину %d символів n", s, strlen(s)); }


ДВОВИМІРНІ МАСИВИ


Як ми вже зазначали, мова С допускає багатовимірні масиви,
най­простішою формою яких е двовимірний масив
(two-dimentional
array). Можна сказати, що двовимірний масив - це масив одновимірних маси­вів .


Двовимірний масив int a[3][4] можна подати у вигляді таблички:




Другий індекс



Перший індекс

















а[0] [0]


а[0][1]


а[0][2]


а[0] [3]


а[1] [0]


а[1][1]


а[1][2]


а[1][3]


а[2][0]


а[2] [1]


а[2][2]


а[2] [3]



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


Кільк.байтів = <розмір типу даних>*<кільк.рядків>*<кільк.ствпців>.


У пам'яті комп'ютера масив розташовується безперервно по ряд­ках, тобто а[0][0], а[0][1], а[0][2], а[0][3], а[1][0], а[1][1], а[1] [2], а[2] [1],. ... а[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("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("nnnp=%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 (" n n 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.


ЗВ'ЯЗОК ПОКАЖЧИКІВ І МАСИВІВ


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


Декларація


int a[10]


визначає масив а розміру 10:



Запис а[і] посилає нас до і-му елемента масиву. int *р;


р=&а[0]; /* р вказує на нульовий елемент а або містить адресу елемента а[0] */



х = *р; => х = а[0], У= *(Р+1); => У = а[1];


Значення змінної типу масив (ім'я масиву)
є адреса нульового елемента масиву.


р = &а[0]; => р = а;


*(а+і) ^ а[і] &а[і] => а+і


Результат буде один і той же. Перевага використання другого варіанту полягає в тому, що арифметичні операції над покажчиками виконуються швидше, якщо ми працюємо з підряд йдучими елементами масиву. Якщо ж вибір елементів масиву випадковий, то швидше і більш наочна робота з індексами.


Між ім'ям масиву і покажчиком,
-виступаючим в ролі імені маси­ву, існує одна відмінність.
Покажчик змінна, тому можна написати р = а або р++.
Але ім'я масиву не є змінною, і записи типу а = р або а++ не допускаються.


Дуже часто доводиться працювати над обробкою текстів, т. е. з масивами рядків. Як ми пам'ятаємо, в мові С рядок - це масив сим­волів, що закінчується нульовим байтом. Розглянемо дві програми, що реалізовують практично, одні і ті ж дії.


#incl ude <std io. h>


#include <ctype.h>


void main()


{ char *p, str[]="String From Letters in Different Registers";


/* Рядок, що Складається з Букв в Різних Регістрах; */ int і=0; printf( "Рядок Буде Надрукований Заголовними Буквами");


while (str[i]) printf("%c", toupper(str[i++]));


p=str; printf(" Рядок Буде Надрукований Малими Буквами");


while (*p) printf("%c", tolower(*p++)); }


Якщо в цих прикладах замінити рядок на англійській мові на ря­док, набраний російськими буквами, то ніякого перетворення букв в рядкові або, навпаки, в прописні не станеться. Це пов'язано з тим, що стандартні функції toupper() і tolower () аналізують значення


10 аргументу і повертають те ж саме значення, якщо він не є відповід­но малою або великою буквою латинського алфавіту. Якщо ж аргумент є малою буквою латинського алфавіту, то значенням функції toupper() буде відповідна велика буква (точніше, код цієї букви). Функція tolower () змінює код лише великих букв латинського алфаві­ту. Прототипи цих функцій знаходяться в заголовному файлі ctype.h.


МАСИВИ ПОКАЖЧИКІВ


Покажчики, як і змінні будь-якого іншого типу, можуть об'єдну­ватися в масиви. Оголошення масиву покажчиків на 10 цілих чисел має вигляд int *x[10] ;


Кожному з елементів масиву можна привласнити адресу; наприклад, третьому елементу привласнимо адресу цілої змінної у:


х[2]=&у;


щоб знайти значення змінною у, можна написати *х(2].


Наведемо приклад використання масиву покажчиків. Частіше за все це буває зручно при обробці масиву рядків.


/* you must run. exe-file to watch the rezult of this program. Перегляд файлів в поточному каталозі з одним з шести розширень */


#include <std io. h >


#include <string.h> ^include <stdlib. h>


#include <conio. h>


main()


{char ch, s[80], *ext[]={"exe", "corn", "cpp", "c", "pas", "*"};


clrscr();


for(;;) {do { printf( "Файли з розширенням:^");


printf("1. exen"); "printf( 2. comn"); "printf( 3. cppn"); "pnntf( 4. з n ");


printf("5. pasn"); printf("6. *n"); //any extension printf("7. quitn");


printf("BauJ вибір(1-7):)( n");


ch=getche();


printf("n");


} while (ch<'1' ;! ch>'7');


if (ch=='7') break;


strcpy(s, "dir *."); strcat(s, ext[ch-'0'-1 ]); strcat(s, "/p"); system(s);} }


Тут функція system() - бібліотечна функція, яка примушує опе­раційну систему DOS виконати команду, що є аргументом цієї функ­ції.


Взагалі рядкова константа в мові С асоціюється з адресою початку рядка в пам'яті, тип рядка виходить char* (покажчик на тип char). Тому можливо і активно використовується наступне привласнення:


char *pc;


"рс = Hello, World!";


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


int -*'*point;



point має тип покажчик на покажчик на int. Відповідно, щоб набу­ти цілочисельного значення змінною, на яку указьіваеі point, треба у вираженні використати **point.;


Приклад використання:


11


^include <stdio. h>


void m а і n()


{ int i, pi, ppi;


і =7; pi=&i;


p p i = & p i;


printf( "i = %d pi = %p ppi = %p n", i, pi, ppi);


*pi++;


printf( "i = %d pi = %p ppi = %p n", i, pi, ppi);


**ppi = 12;


printf( "i = %d pi = %p ppi = %p n", i, pi, ppi);


}


ІНІЦІАЛІЗАЦІЯ ПОКАЖЧИКІВ


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


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


Вважають, що покажчик, який вказує в "нікуди", повинен мати значення null, однак і це не робить його "безпечним". Після того, як він попаде в праву або ліву частину оператора привласнення, він знову може стати "небезпечним".


З іншого боку нульовий покажчик можна використати, наприклад, для позначення кінця масиву покажчиків.


Якщо була спроба привласнити яке-небудь значення тому, на що вказує покажчик з нульовим значенням, система видає попередження, що з'являється під час роботи програми (або після закінчення робо­ти програми) "Null pointer assignment". Поява цього повідомлення є мотивом для пошуку використання неініціалізувати покажчика в програмі.

Сохранить в соц. сетях:
Обсуждение:
comments powered by Disqus

Название реферата: Массивы 2

Слов:3835
Символов:33827
Размер:66.07 Кб.