
Зв'язок вказівників і масивів
У мові С існує важливий зв'язок між масивами і вказівниками. У мові С прийнято, щоб ім'я масиву - це адреса пам'яті, починаючи з якої розташований масив, тобто адреса першого елемента масиву. Таким чином, якщо був оголошений масив
int plus[10];
то plus є вказівником на масив, точніше, на перший елемент масиву. Оператори
p1=plus;
і
p1=&plus[0];
приведуть до тому самому результату.
Для того щоб одержати значення 6-го елемента масиву plus, можна написати
plus[5] або *(р1+5).
Результат буде той самий. Перевага використання другого варіанта в тому, що арифметичні операції над вказівниками виконуються швидше, якщо ми працюємо з елементами масива, що йдуть підряд. Якщо ж вибір елементів масиву випадковий, то швидша і більш наочна робота з індексами.
Дуже часто доводиться працювати над опрацюванням текстів, тобто з масивами рядків. Як ми пам'ятаємо, у мові С рядок - це масив символів, що закінчується нульовим байтом. Розглянемо дві програми, що реалізуют практично, ті самі дії.
# include <stdio.h>
# include <ctype.h>
/* Приклад 31. */
main()
{
char str[]=”String From Letters in Different Registers";
/* Рядок, що складається з Літер Різних Регистрів"; */
int i;
printf(" Рядок Буде Надрукований Заголовними Літерами");
while (str[i])
printf(“%c”, toupper(str [ i++]));
}
# include <stdio.h>
# include <ctype.h>
/* Приклад 32 б. */
main()
{
char str[]=" String From Letters in Different Register";
/* "Рядок, що складається з Літер у Різних Регистрах"/ рrintf("Рядок буде надрукований малими літера");
p=str;
while(*p)
printf(“%c”, tolower(*p++));
}
Якщо в цих прикладах замінити рядок англійською мовою на набрану російськими літерами, то ніякого перетворення літер у рядкові або, навпаки, у прописні не відбудеться. Це зв'язано з тим, що стандартні функції toupper() і tolowеr() аналізують значення аргументу і повертають те ж саме значення, якщо він не є відповідно рядковою або прописною літерою латинського алфавіту. Якщо ж аргумент є мала літера латинського алфавіту, то значенням функції toupper() буде відповідна прописна літера (точніше, код цієї літери). Функція tolower() змінює код лише прописних літер латинського алфавіту. Прототипи цих функцій знаходяться в заголовному файлі ctype. h.
Масиви вказівників
Вказівники, як і змінні будь-якого іншого типу, можуть об'єднуватися в масиви. Оголошення масиву вказівників на 10 цілих чисел має вид
int *x[10];
Кожному з елементів, масиву можна привласнити адресу; наприклад, третьому елементу привласнимо адресу цілої змінної в:
х[2]=&у;
щоб знайти значення змінної у, можна написати *х[2].
Приведемо приклад використання масиву вказівників.Частіше усього це буває зручно при опрацюванні масиву рядків.
#include <stdio.h>
#include <string.h>
#include <stlib.h>
#include <conio.h>
/* Приклад 33 */
main()
{
char ext[]={exe", "com", "dat", "c", "pas", "cpp")
char ch, s1[80];
for(;;)
{ do
{ рrintf(“Файли з розширенням:\n");
printf(“l. exe\n");
printf("2. com\n");
printf("3. dat\n");
printf("4. c\n");
printf("5. pas\n");
printf("6. cpp\n");
printf("7. guit\n");
printf("Baш вибір: \n");
ch=getche();
printf(\n);
{
while ((ch<'l'||(ch>'7'));
if (ch==’7') break;
strcp(s1, "dir*.");
strcat(s1, ext[ch-1]);
system(s1);
}
}
Тут функція system() - бібліотечна функція, що змушує операційну систему DOS виконати команду, що є аргументом цієї функції.
Дуже часто масив вказівників використовується, якщо треба мати поcилання на стандартний набір рядків. Наприклад, якщо ми хочемо зберегти повідомлення про можливі помилки, це зручно зробити так:
char *errors[]={"Cannot open file ",
"Cannot close file" ,
"Allocation eiror ",
"Syaem error "
};
При такому оголошенні рядкові константи будуть занесені в розділ констант у пам'яті, масив вказівників буде перебувати з чотирьох елементів під який буде виділена пам'ять, і ці елементи будуть ініціалізовані адресами, що вказують на початок цих рядкових констант.
Взагалі рядкова константа в мові С асоціюється з адресою початку рядка в пам'яті, тип рядка утворюється char* (вказівник на тип char). Тому можливо й активно використовується наступне присвоювання:
сhar *pc:
рс = "Hello, World ! ";
У мові С можлива також ситуація, коли покажчик вказує на покажчик. У цьому випадку опис буде мати наступний вигляд:
int **point;
Вказівник Вказівник Змінна
-
Адреса
------>
Адреса
------>
Значення
point має тип вказівник на вказівник на int. Відповідно, щоб одержати цілочисельне значення змінної, на якій вказує point, треба у виразі використовувати **point.
Приклад використання:
#include <sidio.h>
/* Приклад 32. */
main()
{
int i, pi, ppi;
i=7;
pi=&i;
ppi=π
printf(“i=%d pi=%р ppi=%р \n", i, pi, ppi);
*pi++;
printf(“i=%d pi=%p ppi=%p \n", i, pi, ppi);
*ppi=12;
printf("i=%d pi=%p ppi=%р \n", i, pi, ppi);
return 0;
}