Процедурное программирование на языке С. Часть 1. Основные понятия языка С: Методические указания к лабораторным работам по курсам «Алгоритмические языки и программирование» и «Процедурное программирование», страница 11

Например, * (mas + 1) = 3 или {  i = 0;   *(mas +i+2)=7; }.

При реализации на компьютере первый способ осуществляется через  второй, т.е. индексное выражение mas[i] преобразуется к адресному *(mas + i), а поскольку от перемены мест слагаемых сумма не меняется, то записи mas[i] и i[mas] будут эквивалентными и обозначают элемент массива с номером i.

3.4. «НАСТРОЙКА» УКАЗАТЕЛЯ НА  МАССИВ

Указатель, используемый и в индексном выражении, и в  операции раскрытия ссылки, не обязательно должен быть константой-указателем, он может быть и переменной-указателем. В частности, если объявить переменную ptr с инициализацией         int *ptr = mas;     –     доступ к 1-му  элементу массива mas  можно получить с помощью указателя ptr в форме ptr[1] или в форме * (ptr + 1).

Такая «настройка» переменной-указателя на массив, предусматривающая возможность изменения самого указателя, сокращает время доступа, повышая тем самым  скорость выполнения программы.

В примере 3.1 оператор цикла уменьшит на 1 значения всех элементов исходного массива.

Пример 3.1.

int  j, mas[]  =  {10, 43, 24, 15, 7};  int *ptr = mas;  

 for (j=0,j<5;j++) --*ptr++;

Подобные действия с именем массива (т.е. mas++ ) – не допустимы, т.к. mas  – имя константы, которая не может быть изменена.

Явные преимущества возникают при настройке переменных-указателей на символьные массивы. Классическим примером является прием инвертирования строки, представленный в примере 3.2. Инвертирование строки можно осуществить и без указателей с использованием индексации, но такой способ и более трудоемок, и дольше выполняется на компьютере.

Пример 3.2.

# include <stdio.h>

void main()

{ char*p, * q,  str[] = "advantage", sim; 

   p = st;  q = &str[8];

  while (p < q) {sim = *p; *p++ = *q; *q-- = sim;}

  p=p-4;

  printf("\n new stroka = %s ",p);  }

Именно с использованием настройки указателей на строки работают библиотечные функции обработки строк, в частности, функция копирования строк и функция вычисления длины строки (общего количества символов в строке без нулевого символа). В примере 3.3 в главной функции происходит копирование строки с константным адресом str в участок памяти с начальным адресом st. Одновременно вычисляется и длина r исходной (и новой) строки.

Пример 3.3.

# include <stdio.h>

void main()

{ char st[10], str[] = "advantage"; 

  char *p = str, * q=st; int r=0;

  for (;*p;*q++ = *p++, r++);

  *q='\0';

  printf("\n new stroka = %s ",st); printf("\n dlina stroki = %d ",r);

}

Циклfor используется без тела, копирование происходит в заголовке цикла, в операторе изменения значений параметров цикла. Оператор присваивания   *q++ = *p++;   выполняется так же, как последовательность операторов:  *q = *p;  q = q + 1;  p = p + 1;

Цикл прекращается, когда выражение *p обращается в 0, это происходит после  смещения указателя p к нулевому символу, завершающему исходную строку.  Поэтому копирование нулевого символа не происходит, что делает необходимым наличие оператора *q='\0';.  (иначе на экране после слова «advantage» появятся произвольные символы, так называемый «мусор»).

3.5. ФУНКЦИИ ДЛЯ РАБОТЫ С ДИНАМИЧЕСКОЙ ПАМЯТЬЮ

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

Программа получает доступ к механизму распределения динамической памяти, если в ее исходном тексте присутствует директива препроцессору    #include <stdlib.h>, в соответствии с которой в программу включается заголовочный файл stdlib.h, содержащий прототипы всех библиотечных функций, работающих с динамической памятью. Рассмотрим 5 функций.