ptr = &message[0];
В этом выражении символ «&» выполняет операцию взятия адреса первого элемента массива message. И именно эта функция была реализована нами в строке 5 исходного примера.
Выполняемое в рассмотренном выше программном фрагменте действие, может быть оформлено на Си другим образом, без использования указателя:
void main(void) {
static char message[] = "What a wonderful day!";
int i;
for (i=0; i<21; i++) putchar(message[i]);
}
Обратите внимание, что в данном примере внутренняя переменная цикла i принимает значения от 0 до 20 включительно, выводя при этом на экран 21 символ. Приведенный способ реализации задачи вывода на экран строки символов обладает одним существенным недостатком. При смене числа символов в записи, выводимой на экран, придется написать новый фрагмент кода. Указанный недостаток исправлен в следующем программном фрагменте:
void main(void) {
char *ptr;
static char message[] = "What a wonderful day!";
ptr = message;
while(*ptr != '\0') {
putchar(*ptr);
ptr++;
}
}
В этом примере указатель ptr используется для передачи в функцию putchar одного кода символа, который будет выведен на экран. Далее содержимое ptr увеличивается на 1, адресуя тем самым следующий элемент массива. По условию цикла while вывод на экран закончится, если в последовательно перебираемом массиве будет найден код конца строки.
Во встраиваемых системах указатели используются для обращения к регистрам специальных функций микроконтроллера. Рассмотрим следующую запись:
#define PORTA *(volatile unsigned char *) 0x1000
Эта запись информирует компилятор о том, что однобайтовая целочисленная переменная с именем PORTA располагается в памяти по адресу 0x1000. Служебное слово volatile информирует программу (и отладчик) о том, что значение PORTA может изменяться не только под управлением программы. Любое упоминание имени PORTA далее по тексту программы будет связано с выполнением операций чтения или записи в регистр данных PORTA по его физическому адресу 0x1000. Поэтому следующий программный фрагмент позволит прочитать содержимое порта PORTA в переменную new_value:
DDRA = 0x00; //инициализировать порт PORTA на ввод
new_value = PORTA; //читать содержимое регистра данных PORTA в
//переменную new_value
Возможности языка Си позволяют объединить под одним именем переменные с разным форматом представления данных. Для этого используется понятие структуры.
Структура — это объект, состоящий из данных различных типов. При использовании структур следует различать объявление (или описание) структуры, как нового типа данных, например тип данных «структура x», от фактического определения некоторой переменной с типом данных «структура x». Пример объявления структуры типа car:
struct car {
int doors;
char color[10];
char *maker;
int num_cyl;
int year;
}
Служебное слово struct указывает начало объявления или определения структуры. За ним следует имя, которое присваивается данной структуре, оно называется идентификатором структуры. В фигурных скобках указывается список определений отдельных элементов, образующих структуру. Элементы структуры могут иметь любой тип, включая массивы, другие структуры и объединения.
Анализируя приведенную запись, отметим, что имя car — это имя нового типа данных. Не следует путать его с именем переменных типа car, которые далее будут определены в программе:
struct car your_car;
struct car my_car;
struct car his_car;
Записав приведенные выше строки, мы определили в программе три переменные с именами your_car, my_car, his_car, и каждая из этих переменных представляет собой структуру с одним и тем же набором элементов. Так первым элементом каждой из этих переменных структур будет двухбайтовое целое число. Численные значения этих первых элементов для всех переменных структур различаются, но формат представления данных для всех трех первых элементов одинаков.
Каждый элемент структуры имеет свое собственное имя: doors, color, maker и т.д. Допускается обращение к каждому элементу структуры с использованием его имени:
your_car.doors = 4;
Если переменная типа структура передается в качестве параметра в какую либо функцию, то следует помнить, что передаются не сами элементы структуры, а лишь указатель на первый элемент названной структуры. Поэтому при обращении внутри функции к отдельным элементам структуры следует вместо оператора «.» использовать оператор «–>». Например, в программе определяется функция assign_doornumber, которая присваивает численное значение первому элементу структуры типа car:
Читать дальше