Смекни!
smekni.com

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


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

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

Декларація

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. exe&bsol;n"); "printf( 2. com&bsol;n"); "printf( 3. cpp&bsol;n"); "pnntf( 4. з &bsol; n ");

printf("5. pas&bsol;n"); printf("6. *&bsol;n"); //any extension printf("7. quit&bsol;n");

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

ch=getche();

printf("&bsol;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 &bsol;n", i, pi, ppi);

*pi++;

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

**ppi = 12;

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

}

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

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

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

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

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

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