Массивы. Их связь с указателями. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Массивы. Их связь с указателями.



 

Массивы – это один из примеров структурированного типа данных.

Массив – это расположенные вплотную друг за другом в памяти элементы одного и того же типа. Каждый массив имеет имя. Доступ к отдельным элементам массива осуществляется по имени массива и индексу (порядковому номеру) элемента.

Основные свойства массива:

все элементы массива имеют один и тот же тип;

все элементы массива расположены в памяти друг за другом; индекс первого равен 0;

имя массива является указателем-константой, равной адресу начала массива (первого байта первого элемента массива).

Признаком массива при описании является наличие парных скобок [ ]. Константа или константное выражение в квадратных скобках задает число элементов массива. Например:

char buffer[81]; int Key[4];

При описании массива может быть выполнена инициализация его элементов.

Существует два метода инициализации массивов:

1) инициализация по умолчанию; она применяется только к статическим и внешним массивам (о классах хранения и внешних переменных см. в 8.2 и 8.4); по умолчанию все элементы внешних и статических массивов инициализируются компилятором нулями;

2) явная инициализация элементов; после описания массива помещается список начальных значений элементов массива, заключенный в фигурные скобки. Существуют две формы явной инициализации элементов массива:

а) явное указание числа элементов массива и список начальных значений, возможно с меньшим числом элементов.

Например:

char array[10] = { ‘A’, ‘B’, ‘C’, ‘D’ };

Здесь описывается массив из 10 элементов. Первые 4 элемента массива инициализируются символами ‘A’, ‘B’, ‘C’, ‘D’. Значения остальных 6 элементов либо равно 0, если массив внешний или статический, либо не определено. Если список начальных значений содержит больше элементов, чем число в квадратных скобках, Borland C++ генерирует сообщение об ошибке;

б) только со списком начальных значений. Компилятор определяет число элементов массива по списку инициализации. Например:

char array[] = { ‘A’, ‘B’, ‘C’, ‘D’ };

В результате создается массив ровно из 4 элементов, и эти элементы получают начальные значения из списка инициализации.

Если при описании массива отсутствуют значение в квадратных скобках и список начальных значений, компилятор обычно регистрирует ошибку. Однако в тех контекстах, где не требуется резервирование места в памяти, этого не происходит:

если массив объявляется как внешний при условии, что в том месте, где массив описывается, приведена информация о числе его элементов. Например:

extern char array[];

в описании функции, если указатель на первый элемент массива является аргументом функции. Например:

int function (int input_array[], int index)

{ /* тело функции */ }

в прототипах функций, использующих в качестве аргумента указатель на первый элемент массива.

Доступ к отдельным элементам массива может выполняться либо с помощью индекса, либо операцией *. В первом случае для ссылки на нужный элемент указывается его порядковый номер в массиве, заключенный в квадратные скобки. Самый первый элемент массива имеет порядковый номер 0. Пример:

int a[] = { 1, 2, 3, 4, 5 };

int index = 0, first, last, bad;

first = a[index]; /* first = 1 */

last = a[4]; /* last = 5 */

bad = a[index + 6]; /* bad случайно */

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

Другой способ доступа к элементам массива - использование механизма указателей. Так как имя массива - это указатель-константа на первый байт первого элемента массива, то, используя операцию *, можно выполнить доступ к любому из элементов массива. Будут полностью эквивалентными ссылки на i-й элемент массива array (независимо от типа элемента) array[i] и *(array + i), причем оба способа для Borland C++ дают практически одинаковый по производительности код. Следующие выражения являются тождествами:

array == &array[0],

(array + i) == &array[i].

 

ОПЕРАТОРЫ

 

Общие сведения

 

Операторы управления вычислительным процессом позволяют выполнять ветвление, циклическое повторение одного или нескольких операторов, передачу управления в нужное место кода программы. Под вычислительным процессом понимают процесс выполнения операторов программы. Операторы программы могут быть простыми или составными. Простой оператор - это оператор, не содержащий другие операторы. Разделителем простых операторов служит точка с запятой. Специальным случаем простого оператора является пустой оператор, состоящий из единственного символа ‘;’. Составной оператор, или блок,- это любая совокупность простых операторов, заключенная в фигурные скобки {}. Составной оператор идентичен простому оператору и может находиться в любом месте программы, где синтаксис языка допускает наличие оператора, но дополнительно влияет на так называемую видимость переменных.

 

Оператор if

 

Операторы ветвления выбирают в программе из группы альтернатив возможное продолжение вычислительного процесса. Выбор выполняется исходя из значения заданного выражения. В С++ используются два оператора ветвления: if...else и switch.

Оператор if имеет следующую общую форму записи:

if (cond_expression) TRUE_statement

[else FALSE_statement]

При выполнении оператора if сначала вычисляется логическое выражение cond_expression. Если результат - ИСТИНА (любое отличное от нуля значение), выполняется оператор TRUE_statement. Если результат логического выражения – ЛОЖЬ (равен 0), то выполняется оператор FALSE_statement. Если ключевое слово else отсутствует, то в этом случае оператор TRUE_statement пропускается, а управление передается на следующий после if оператор.

Операторы TRUE_statement и FALSE_statement сами могут быть операторами if, образуя так называемые вложенные if. Компилятор интерпретирует вложенные if, сопоставляя каждое из ключевых слов else с последним встретившимся словом if, не имеющим " своего" else. Соответствие ищется в пределах блока, в который заключено слово if. Внутренние и внешние блоки при этом не рассматриваются. Если соответствия для if не найдено, компилятор полагает, что if не имеет ветви else. Например,

int a, b; то же самое, но int a, b;

if(b>0) в первом операторе if(b>О)

а=1; if отсутствует else а=1;

else if(b==0)

if(b==0) a=0;

а=0; else

else a=-1;

а=-1;

В результате переменной а будет присваиваться значение -1, если b<0, +1, если b>0, и 0, если b=0. Но ошибочной будет следующая последовательность операторов:

int x=1, у=1;

if(x==1)

if(y==1) puts("х равно 1 и y равно 1);

else

puts("х не равно 1");

Строка" х не равно 1" будет выводиться тогда, когда значение х на самом деле равно 1. Ошибка происходит из-за того, что компилятор сопоставляет if с ближайшим else так, как это показано тонкой сплошной чертой. Ошибка может быть исправлена, если использовать фигурные скобки, ограничивающие блок:

int x=1, у=1;

if(x==1)

{

if(y==1) puts("х равно 1 и y равно 1);

}

else

puts("х не равно 1");

Операция условия?: является частным случаем оператора if...else. Например, фрагмент

if(cond_expression)

x=y;

else x=y+4;

эквивалентен более короткой записи:

х=(cond_expression)? y:y+4;

 

Операторы switch и break

 

Часто возникающая в программировании задача – выбор одного варианта из многих. Можно это сделать с помощью вложенных if...else. Однако более удобный способ - использование оператора switch, общий формат которого таков:

switch(switch expression)

{

сase constantl: statementl; [break;]

.......

саse constanti: statementi; [break;]

........

case constantN: statementN; [break;]

[default: statementN+1;]

}

Оператор switch выполняется так. Сначала вычисляется значение выражения switch_expression. Тип значения должен быть одним из целых - char, int, unsigned int, long int и long unsigned.Вычисленное значение сравнивается со значениями констант или константных выражений сonstant1,..., сonstantN. При совпадении значения switch expression с constani выполняется оператор statementi. Затем управление передается на оператор сразу после switch, если в i-й ветви присутствует оператор break. В противном случае выполняются операторы в ветвях i+1, i+2 и так далее до тех пор, пока в них не встретится оператор break или не будет выполнен оператор statementN+1.

Если значение switch_expression не совпало ни с одной из констант constant1,..., constantN, выполняется оператор в ветви, помеченной default. При ее отсутствии выполняется следующий после switch оператор.

Приводимая далее программа выводит на экран меню из трех функций: Sin, Соs, Atan; по первой введенной с клавиатуры букве распечатывается информация о функции:

//Prim5_1.cpp

#include <stdio.h>

void main(void)

{

рuts("введите первую букву имени функции:\n"\

" S-Sin\n С-Сos\n А-Atan\n");

switch(getchar())

{

case's': case'S':

рuts("вычиcление синуса аргумента в радианах");

break;

case'c': case'C':

рuts ("Вычисление косинуса аргумента в радианах");

break;

case'a': case'A':

рuts("Вычисление тангенса аргумента в радианах");

break;

default: рuts("Ошибка\а\n");

}

}

При отсутствии операторов break во всех ветвях происходило бы следующее:

1) ввод с клавиатуры буквы 's' или 'S' вызывал бы вывод на экран сразу четырех сообщений:

Вычисление синуса аргумента в радианах

Вычисление косинуса аргумента в радианах

Вычисление тангенса аргумента в радианах

Ошибка (звучит звуковой сигнал)

2) ввод с клавиатуры буквы 'с' или 'С' вызывал бы вывод на экран сразу трех сообщений:

Вычисление косинуса аргумента в радианах

Вычисление тангенса аргумента в радианах

Ошибка (звучит звуковой сигнал)

3) ввод с клавиатуры буквы 'а' или 'А' вызывал бы вывод на экран сразу двух сообщений:

Вычисление тангенса аргумента в радианах

Ошибка (звучит звуковой сигнал)

 

Операторы цикла

 

Язык С++ имеет удобные операторы организации циклов. Общая форма записи операторов цикла такова:

while(cond_expr) operator;

dо operator while(cond_expr);

for(init_expr; cond_expr; increment_ехрг) operator;

Оператор while организует повторение оператора operator до тех пор, пока логическое выражение cond_expr не примет значение ЛОЖЬ (0). Оператор while называют оператором цикла с предусловием, так как истинность cond_expr проверяется перед входом в цикл. Следовательно, возможна ситуация, когда operator не выполняется ни разу.

Если необходимо обеспечить выполнение цикла xотя бы один раз, используют оператор цикла с постусловием do... while;. Здесь сначала выполняется operator, а затем проверяется значение выражения cond_ехрг. Повторение тела цикла происходит до тех пор, пока cond_ехрг не примет значение ЛОЖЬ (0).

Наиболее сложная форма оператора цикла - это оператор for. Он эквивалентен следующему фрагменту:

init_ехрг

while(cond_expression)

{

operator

increment_expression

}

Перед вхождением в цикл выполняется init_expression. Затем проверяется значение cond_expression. Повторение тела цикла происходит до тех пор, пока cond_expression не примет значение ЛОЖЬ (0). Циклически повторяемый участок состоит из оператора, заданного после for, и increment_expression, указанного в самом операторе for. Как increment_expression, так и init_expression могут быть любой (в том числе и пустой) последовательностью простых операторов, разделяемых оператором запятая. Наличие инициализирующей части, состоящей из произвольного числа операторов, дает основание утверждать, что любую программу на языке Си можно представить в виде единственного оператора for, однако не следует этого делать.

Различные операторы циклов могут выражаться друг через друга. Выражение оператора for через while уже приводилось. А вот и другие эквивалентные пары:

for(; cond_expr;) эквивалентен while(cond ехрг)

operator operator

 

for(operator;cond_ехрr;) эквивалентен dо

operator

while(cond_expr);

 

Одна из самых неприятных особенностей операторов цикла заключается в возможности образования бесконечного цикла или,как говорят, в зацикливании программы. Причина этого в том, что значение cond_ехрr из-за ошибки в программе никогда не становится ложным. Вот простой пример такой ошибки, приводящей к зацикливанию:

int i=0;

while(i<60);

{

printf("i=%d\n", i); i++;

}

Причина зацикливания - в незаметном знаке';' после oператора while. Компилятор полагает, что повторяемый в цикле оператор - это не составной оператор, заключенный в фигурные скобки, а пустой оператор. Значение i не увеличивается, и логическое выражение i<60 при проверке всегда дает значение ИСТИНА.

Приводимая далее программа и иллюстрирует использование оператора цикла while. Она подсчитывает число русских гласных букв в слове, введенном с клавиатуры:

//Prim5_2.cpp

#include<stdio.h>

void main()

{

int total=0, rus=0;

char ch;

while((ch=getchar())!='\n')

{

total++;

switch(ch)

{

case'A': case'a': case'E': case'e':

case'И': case'u': case'O': case'o':

case'У': case'y': case'Э': case'э':

сase'Ю': case'ю': саsе'Я': сasе'я':

rus++;

}

}

printf("Введено %d символов, из них %d "\

" русских гласных букв\n", total, rus);

}

Приводимая ниже программа демонстрирует использование цикла dо... while для вывода на экран приглашения

"Продолжаете? (Да/Нет). Esc- отмена выбора.",

приема с клавиатуры и анализа ответа пользователя. При нажатии клавиши с русской буквой 'д' выводится слово "Да",а при нажатии клавиши с русской буквой 'н' - слово "Нет". При нажатии клавиши Esc (Ключ) выводится сообщение "Отмена выбора". При нажатии любых других клавиш звучит сигнал динамика, указывая на ошибку. Программа использует в своей работе библиотечную функцию bioskey(0), возвращающую так называемый код нажатия клавиши.

Для того чтобы программа не зависела от регистра клавиатуры (Рус/Лат), расширено число меток для ветвей "Да" и "Нет". Здесь приведен вариант программы для стандартной русифицированной по альтернативной таблице клавиатуры со 101/102 клавишами:

//Prim5_3.cpp

#include<stdio.h>

#includе <bios.h>

#define YES 0

#define NO 1

#define ESC 27

int main(void)

{

char сh;

puts("Продолжаете? (Д/Н). Esc-отмена выборa");

do

{

сh=bioskey(0);

switch(ch)

{

case'д': case 'Д': case'l: саse 'L':

puts("ДА");

return(YES);

case'н': case 'Н': case'y': саse 'Y:

puts("Hem");

return(NO);

саcе ESC: break;

default: putchar('\a');

}

}

while(ch!=ESC);

рuts("Отмена выбора");

return(ESC);

 



Поделиться:


Последнее изменение этой страницы: 2017-02-05; просмотров: 353; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.146.105.194 (0.44 с.)