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



ЗНАЕТЕ ЛИ ВЫ?

Этот тип позволяет представлять числа с дробной частью.

Поиск

Лекция 0

Возникновение языка С

 

Кен Томпсон Денис Ритчи

 

Язык программирования Си был разработан в начале 1970-х годов сотрудниками лаборатории Bell Кеном Томпсоном и Денисом Ритчи для использования в создаваемой ими операционной системе Unix. Для выполнения работы по созданию Unix разработчики нуждались в таком языке программирования, который был бы крат­ким, а также мог бы обеспечивать эффективное управление аппаратными средствами, мог бы создавать компактные, быстро работающие программы.

Традиционно такие потребности программистов удовлетворял язык ассемблера, который тесно связан с внутренним ма­шинным языком компьютера. Однако ассемблер — язык низкого уровня, т.е. он привя­зан к определенному типу процессора (или компьютера). Поэтому если программу на языке ассемблера необходимо перенести на компьютер другого типа, ее приходится пе­реписывать заново на другом языке ассемблера. Это можно сравнить с ситуацией, ког­да при покупке нового автомобиля вы каждый раз обнаруживаете, что конструкторы решили изменить расположение и назначение органов управления, вынуждая вас зано­во переучиваться вождению.

Операционная система UNIX предназначалась для работы на компьютерах различных типов (или платформах). А это предполагало использование языка высокого уровня. Язык высокого уровня ориентирован на решение задач, а не на конкретное аппаратное обеспечение. Специальные программы, которые называются компиляторами, транслируют программу, написанную на языке высокого уровня, в ко­манды внутреннего языка конкретного компьютера. Таким образом, используя отдель­ный компилятор для каждой платформы, одну и ту же программу на языке высокого уровня можно выполнять на разных платформах. Разработчики Unix нуждались в языке, который со­четал бы в себе эффективность и возможность доступа к аппаратным средствам, обес­печиваемые языками низкого уровня, с более общим характером и переносимостью, присущими языкам высокого уровня. Поэтому на основе имевшихся в то время более старых языков программирования Ритчи и Томпсоном был разработан язык С.

 

Типы данных в языке C++. Общие понятия.

 

В языке С++ имеется две группы встроенных типов данных: базовые и составные или производные.

Для хранения в компьютере элемента информации программа должна отслеживать три его основных свойства; в частности, она определяет:

• где хранится информация

• какое значение там хранится

• вид хранящейся информации.

 

К примеру, в объявлении int i=5 имя i определяет значение переменной, равное 5. При этом это целочисленная переменная.

 

Правила именования переменных

  • Для переменных рекомендуется выбирать имена, отражающие их назначение. В именах можно использовать буквы алфавита, цифры и символ подчеркивания.
  • Первый символ не может быть цифрой.
  • Символы верхнего и нижнего регистров рассматриваются как разные.
  • В качестве имен нельзя использовать ключевые слова языка C++.
  • Не рекомендуется определять имена, начинающиеся с двух символов подчеркивания или с символа подчерки­вания и следующей за ним буквы в верхнем регистре. Имена, начинающиеся с одного символа под­черкивания, зарезервированы для использования реализацией языка в качестве глобальных идентификаторов.
  • В языке C++ на длину имени не накладывается никаких ограничений, т.е. учиты­вается каждый символ имени.

Типы данных в языке C++. Целочисленные типы данных

 

Целые числа — это числа без дробной части, например 2, 98, -5286 или 0. В некоторых языках, например Standard Pascal, су­ществует только один тип целочисленных данных (один тип данных — для представле­ния всех целых чисел), однако C++ включает несколько типов таких данных. Это позволяет программисту выбрать такой тип целочисленных данных, который лучше все­го соответствует требованиям конкретной программы.

В языке C++ одни типы данных (со знаком) могут представлять и положительные, и отрицательные значения, тогда как другие типы данных (без знака) не могут представлять отрицательные значения.

Базовые типы целочисленных данных языка C++ именуются char, short, int и long. Каждый из этих типов данных подраз­деляется на две разновидности: со знаком и без знака. В результате программист имеет выбор из восьми различных типов целочисленных данных.

 

Тип Размерность (байт) Диапазон
char   от -128 до 127
unsigned char   От 0 до 255
int   от -32768 до 32767
unsigned int   от 0 до 65535
short   от -32768 до 32767
unsigned short   от 0 до 65535
long   от -2147483648 до 2147483647
unsigned long   от 0 до 4294967295

Типы данных в языке C++. Булевский тип данных.

В программирова­нии переменная Boolean — это переменная, которая может принимать два значения: true (истина) или false (ложь). Для представления булевских значений используется тип данных bool и предопределенные литералы true и false. Други­ми словами, допустимы операторы, подобные следующему:

bool bIsReady = true;

Типы данных в языке C++. Числа с плавающей точкой

Число с плавающей точкой

Число с плавающей точкой

Число с плавающей точкой

Кг

Операции и выражения.

Выражение в языке С++ – это последовательность операндов, операций и символов-разделителей. Операнды – это переменные, константы либо другие выражения. Разделителями в С++ являются символы:

 

[ ] () { },;: * = #,

 

каждый из которых выполняет свою функцию. Выражение может состоять из целого ряда операций и определять выполнение целого ряда шагов по преобразованию информации.

По типу выполняемой операции различают арифметические операции, поразрядные логические, присваивания, операции отношения.

 

Операции и выражения.

Операция присваивания.

 

Язык C++ имеет несколько особенностей выполнения операции присваивания, задаваемого символом операции =. При выполнении операции значение операнда справа от знака равенства записывается в переменную, указанную слева от знака.

В отличие от других языков программирования в С++ допускается запись в одном предложении сразу нескольких операций присваивания. Например:

int a,b,c,d;

a=b=c=d=145;

Другая особенность операции присваивания в языке С++ - наличие так называемой комбинированной операции присваивания:

переменная операция = выражение

 

Где переменная – это обычная как-то задаваемая переменная.

Операция – это одна из операция, задаваемых знаками: *, /, +, -, %, <<, >>, &, ^, |.

Выражение – любое выражение.

 

Например:

int a,b;

a=b=10;

a+=12; // a теперь имеет значение 22

b-=(a+4); // b теперь имеет значение -16

Арифметические выражения.

Арифметические выражения

Преобразования типов данных

 

Разнообразие типов данных в языке C++ дает программисту возможность выбирать вариант, соответствующий конкретной потребности. Однако такое разнообразие, с дру­гой стороны, усложняет задачу компьютера. Например, сложение двух чисел типа short может выполняться с помощью иных машинных команд, чем сложение двух чи­сел типа long. Когда имеется 11 типов целочисленных данных и три типа данных с плавающей точкой, компьютеру приходится обрабатывать множество различных случа­ев, особенно если в одной операции смешаны данные различных типов. Чтобы не допу­стить возможной путаницы, в языке C++ многие преобразования типов данных выпол­няются автоматически:

 

  • Преобразование данных осуществляется, когда данные одного арифметического типа присваиваются переменной другого арифметического типа.

 

// данные типа int преобразуются в данные // типа float

float tree = 3;

// данные типа float преобразуются

// в данные типа int

int guess = 3.9832;

Результат:

tree = 3.0

guess = 3

  • Преобразование данных осуществляется, когда в выражении содержатся данные разных типов.

 

Когда некоторая операция выполняется над данными двух разных типов, то дан­ные меньшего типа преобразуются в данные большего типа. Например:

 

int i=45;

float f=450.123;

float r=i+f; // результат float

 

  • Преобразование данных осуществляется при передаче аргументов в функции.

Если не знать, что происходит при таких автоматических преобразованиях, то ре­зультаты выполнения некоторых программ могут оказаться для вас неожиданными.

Приведение типов:

 

В общем виде:

(имяТипа) значение

// преобразует значение в данные типа имяТипа

ИмяТипа (значение)

// преобразует значение в данные типа имяТипа

 

Пример:

float f=450.123;

int guess;

guess = (int)(3.9832 + f);

Или

guess = int(3.9832 + f);

Операции и выражения.

Операции и выражения.

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

Цикл for.

 

Цикл for – это один из операторов цикла, которыепредназначены для выполнения повторяющихся действий.

Общая форма записи оператора цикла for имеет следующий вид.

 

for(инициализация цикла;

условие продолжения цикла;

обновление переменной цикла)

Тело цикла

Управление циклом осуществляется с помощью переменной цикла.

Инициализация цикла выполняется только один раз. Как правило, это выражение применяется для задания начального значения переменной цикла, после чего дан­ная переменная может использоваться для подсчета ко­личества итераций цикла (в этом случае ее называют счетчиком цикла.

Условие продолжения цикла определяет, следует ли завершить выполнение цикла. Как правило, это выра­жение является выражением сравнения. Если результат сравнения оказывается истинным, тогда программа выполняет тело цикла, иначе выполнение цикла прекращается.

Обновление переменной цикла. Это выражение, которое присваивает переменной цикла новое значение.

Пример.

 

for (i = 1; i < 5; i++) { printf("i = %d/n", i);}

Результат:

i = 1

i = 2

i = 3

i = 4

На самом деле в качестве условия продолжения цикла в C++ может при­меняться не только выражение сравнения, образующие значения типа " ИСТИНА-ЛОЖЬ ". Для этого может быть ис­пользовано любое выражение. Так, если в результате вычисления подобного выражения получается нуль, тог­да цикл завершается. А если результат вычисления вы­ражения оказывается ненулевым, тогда выполнение цикла продолжается. Например, допустима следующая запись.

 

for(i=1;5-i;i++)

{

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

}

Результат работы программы будет аналогичен предыдущему.

Цикл for является циклом с входным условием (или с предусловием). Это означает, что условие продолжения цикла проверяется перед вьшолнением каждой итерации цикла. При этом тело цикла вообще не выполняется, если не выполняется условие продолжения цикла.

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

В качестве выражений, управляющих циклом, может использоваться любое действительное выражение C++.

Тело цикла может состоять как из нескольких операторов, заключаемых в фигурные скобки, так и может состоять всего лишь из одного единственного оператора. Например.

int i,j=0;for (i = 1; i < 125; i++) j+=i;

 

Переменная цикла не обязательно должна иметь положительное значение. Допустимы значения, меньшие нуля.

 

int i,j=0;for (i = -10; i < 0; i++) j+=i;

 

Переменная цикла также не обязательно должна подвергаться только операции инкремента. Допустим и декремент.

 

int i,j=0;for (i = 10; i > 0; i--) j+=i;

 

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

 

int i,j=0;for (i = 1; i < 100; i=(i+1)+i*2) j+=i;

 

Для цикла for в качестве переменной цикла, инициализации цикла и обновления переменной цикла допустимо использование не только целочисленных переменных.

 

double i;

for (i=1.0;i < 100.0;i+=sin(0.524)) j+=i;


Тело цикла

 

Прежде всего, программа проверяет условие продол­жения цикла. Если в результате вычисления этого вы­ражения получается логическое значение true, тогда программа выполняет операторы в теле цикла. Подоб­но циклу for, тело данного цикла состоит либо из одного опе­ратора, либо из блока, обрамляемого парой фигурных ско­бок.

После завершения выполнения тела цикла программа возвращается к анализу условия продолжения цикла и вычисляет его снова. Если данное условие оказывает­ся ненулевым, то программа снова выполняет тело цикла. Подобный цикл проверки и выполнения продол­жается до тех пор, пока в результате вычисления выра­жения условия не получится логическое значение false.

Подоб­но циклу for, while является циклом с входным услови­ем продолжения цикла (цикл с предусловием). Таким образом, если в результате вычисления условие продолжения цикла ока­зывается ложным с самого начала, программа вообще не выполняет тело цикла.

 

Пример.

int i=0;

while(i<100)

{

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

i++;

}

Результат: будут выведены все числа в диапазоне от 0 до 99.

 

Частные случаи применения цикла while.

Бесконечный цикл.

 

While(1)

{

// операторы

}

Цикл задержки по времени.

long i=0;

while(i<10000)

{

i++;

// операторы

}

 

Тело цикла

while (условие продолжения цикла);

 

Тело рассматриваемого цикла может состоять из од­ного оператора или ограниченного фигурными скобка­ми блока операторов.

Использовать цикл do while лучше всего в тех случаях, когда должна быть выполнена по крайней мере одна итерация.

 

Пример.

int i=0;

do

{

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

i++;

}while(i<100);

 

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

Пример:

int i=0;

while(i<100);

{

i++;

// операторы

}

Здесь из-за незаметно указанного знака точки с запятой после оператора while компилятор полагает, что повторяемый в цикле оператор – это не составной оператор, заключенный в фигурные скобки, а пустой оператор. Значение i не увеличивается, и логическое выражение (i<100) при проверке всегда дает значение ИСТИНА.

 

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

Операторы break и continue.

 

Операторы break и continue позволяют программе про­пускать фрагменты кода. Оператор break исполь­зуется в операторе ветвления switch, о котором речь пойдет позже, и влюбых циклах. Этот опе­ратор вызывает переход к оператору, следующему за оператором цикла.

Оператор continue ис­пользуется в циклах и приводит к тому, что программа пропускает остальную часть тела цикла и начинает но­вую итерацию цикла (см. рис.).

 

 

В цикле for оператор continue заставляет програм­му перейти непосредственно к выражению обновления, а затем к проверочному выражению. Однако в цикле while оператор continue заставляет программу перейти непосредственно к проверочному выражению. Таким образом, любое выражение обновления в теле цикла while, следующее за continue, будет пропущено. В ряде случаев это может создавать проблему.

Пример:

for(i=1;i<100;i++)

{

// операторы

if(какое-то условие) continue;

// операторы

}

While(какое-то условие)

{

// операторы

if(какое-то условие) break;

// операторы

}

 

 

Операторы ветвления.

Оператор if.

 

Когда программе C++ нужно решить, выполнять ли заданное действие, можно использовать оператор if. Этот оператор имеет две формы: if и if else. Вна­чале рассмотрим более простую форму — if. Оператор if приводит к тому, что программа выполняет оператор или группу операторов, если про­верочное условие ИСТИННО, и пропускает этот оператор или группу операторов, если условие ЛОЖНО. Синтаксис этой формы оператора if следующий:

 

if(проверочное условие)

Оператор

 

Истинное или ненулевое проверочное условие приво­дит к выполнению программой оператора, которым может быть отдельным оператором или блоком операторов, заключенным в скобки. Ложное или нулевое проверочное условие приводит к тому, что оператор пропускается программой.

Чаше всего проверочное условие — это выражение сравнения, подобное тем, что используются для управ­ления циклами.

Пример:

double i,j;

if(i>0.0) j=sqrt(i);

 

Следующая форма оператора if определяет составной оператор, когда по условию выполняется группа операторов в блоке.

if(проверочное условие)

{

оператор 1;

оператор 2;

оператор n;

}

Простая форма оператора if позволяет выбрать оператор, возможно, составной, или пропустить его. Язык Си предоставляет также возможность выбрать любой из двух операторов путем использования конструкции if-else.

Общий вид оператора if-else выглядит следующим образом:

 

if(проверочное условие) оператор 1;else оператор 2;

Если проверочное выражение ИСТИННО, то выполняется первый оператор и пропускается второй оператор, а если ЛОЖНО, то выполняется оператор, следующий за ключевым словом else. Операторы могут быть простыми или составными, заключенными в фигурные скобки. В случае составных операторов, в отличие от некоторых языков программирования, например, таких как BASIC или FORTRAN С++ не считает автоматически блоком все, что располагается между операторами if-else, поэтому для заключения операторов в блок необходимо использовать фигурные скобки.

 

Пример:

double i,j;

if(i>0.0){ j=sqrt(i); printf(“j=%g\n”,j);}else{ j=sqrt(fabs(i)); printf(“j=%g\n”,j);}

Итак, простая конструкция if позволяет выбрать, выполнить или нет некоторое действие; конструкция же if-else дает возможность выбрать одно из двух действий.

Конструкция if else if else

Компьютерные программы, как и реальная жизнь, мо­гут ставить вас перед необходимостью выбора более чем из двух возможных вариантов. Для удовлетворения этой потребности можно расширить возможности оператора if else C++. Как было показано ранее, за ключевым сло­вом else должен следовать единый оператор, который может быть также и блоком. Поскольку if else сам является еди­ным оператором, он может следовать за else:

int i,j;

if(i>0)

j--;

else if(i<0)

j++;

Else

j=0;

Это выглядит подобно новой управляющей структуре if else if else, но на самом деле это один оператор if else, содержащийся внутри другого.

 

Операторы ветвления.

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

 

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

switch(expression) { сase constant1: statement1; break; case constant2: statement2; break;... case constantk: statementk; break; default: statement(k+1);}

Оператор switch выполняется так. Сначала вычисляется значение выражения expression. Тип значения должен быть одним из целых – char, int, unsigned int, long int, unsigned long. Вычисленное значение сравнивается со значениями констант или константных выражений constant1,…, constantk. При совпадении значения expression с константным выражением constantk выполняется оператор statementk. Оператор может быть единичным, а может быть представлен группой операторов. Операторы внутри группы не обрамляются фигурными скобками, а просто отделяются друг от друга точкой с запятой. После выполнения данных операторов управление передается оператору, следующему сразу после switch, если в данной ветке присутствует оператор break. Если такой оператор отсутствует, то выполняются нижеследующие ветви, пока не встретится оператор break или не будет выполнен оператор statement(k+1).

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

Пример:

 

double res;

// переменная, хранящая первую букву

// выполняемой функции

char operation;

// значение угла

double ugol_rad;

// задание operation какого-то значения

// задание ugol_rad какого-то значения

// реализация выбораswitch(operation) { сase ‘s’: сase ‘S’: res=sin(ugol_rad); printf(“Вычислен синус\n”); break; сase ‘c’: сase ‘C’: res=cos(ugol_rad); printf(“Вычислен косинус\n”); break; сase ‘t’: сase ‘T’: res=tan(ugol_rad); printf(“Вычислен тангенс\n”); break; default: printf(“Ошибка\n”);}

 

Типичная ошибка, допускаемая с оператором switch, - когда программист забывает ставить оператор break. В этом случае выполняется и данная ветка, и как минимум следующая. Например, уберем в предыдущем примере все операторы break. Если перед входом в оператор switch переменная operation имеет значение ‘s’, то на экран будет выведено следующее:

Вычислен синусВычислен косинусВычислен тангенсОшибка

 

То есть, программа пройдется по всем веткам. Если перед входом в оператор switch переменная operation имеет значение ‘t’, то на экран будет выведено следующее:

Вычислен тангенсОшибка

 

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

 

Ввод-вывод данных.

 

Ситуация с вводом-выводом в языке С++

 

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

В языках С и С++ не было и нет особых операторов для ввода или вывода данных. Причиной этого является как слишком большое разнообразие операций ввода и вывода в разных операционных системах, особенно графических, так и возможность определения новых типов данных в языке С++. Вывод даже простой строки текста в MS DOS, MS Windows и в X Window настолько различен, что пытаться придумать общие для всех них операторы было бы слишком негибко и на самом деле затруднило бы работу. Что же говорить о классах, определенных программистом, у которых могут быть совершенно специфические требования к их вводу-выводу.

Первоначально в языке С реализация ввода/вывода была оставлена на усмотрение раз­работчиков компиляторов. В результате разработчики получили творческую свободу при создании функций ввода/вывода данных, которые наилучшим образом смогут удовлет­ворять аппаратные запросы компьютера. На практике большинство разработчиков для вво­да/вывода использовали набор функций, первоначально разработанных для среды UNIX. В стандарте С было формализовано применение этого пакета, названного пакетом стандартного ввода/вывода (Standart Input/Output): он был сделан обязательным компонен­том стандартной библиотеки С. В языке C++ также поддерживается данный пакет, поэтому те, кто знаком с семейством функций С, объявленных в файле stdio.h, могут использо­вать их и в программах, написанных на C++.

Однако в C++ чаще используется ввод/вывод в стиле C++, а не в стиле языка С. Это делается при помощи набора классов, стандартно поставляемых вместе с компилятором, которые и реализуют основные операции ввода-вывода. Функционал библиотеки определен в заголовочных файлах iostream (ранее iostream.h) и fstream (ранее fstream.h). Классы – это специальные, особые типы данных, создаваемые программистом, которые в своём составе содержат как непосредственно данные, так и функции, работающие с этими данными.

 

Указатели

 

В языке С++ существует два способа доступа к переменной - это ссылка на переменную по её имени и использование механизма указателей.

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

Указатель-константа – это значение адреса оперативной памяти.

В языке определены две специальные операции для доступа к переменным через указатели. Это операции & и операция *.

Результатом операции & является выдача адрес объекта, к которому операция применяется. Например &var1 дает адрес, по которому переменная var1 хранится в памяти (точнее адрес её первого байта).

Операция * - это операция обращения к содержимому памяти по адресу, хранимому в переменной-указателе или равному указателю константе.

Признаком переменной-указателя для компилятора является наличие в описании переменной двух компонентов:

ü Типа объекта данных, для доступа к которому используется указатель (или, как еще говорят, на который ссылается указатель).

ü Символа * перед именем переменной.

Сочетание типа данныйх и символа * воспринимается компилятором как особый тип данных – «указатель на что-либо». Таким образом, описание

int var1,*ptr;

приводит к появлению переменной var1 и указателя-переменной ptr. Здесь переменная ptr будет иметь тип int*, т.е. тип «указатель на целое».

Указатели при их описании могут, как и обычные переменные, получать начальные значения:

int var1,*ptr=&var1;

Здесь указателю ptr присваивается начальное значение – адрес, по которому в памяти хранится переменная var1.

Еще одна инициализация при описании:

int *ptr=(int*)200;

Операцию *, пытаясь выразить словами смысл выражения, можно заменить фразой: - «взять содержимое по адресу, равному значению указателя». Например, оператор присваивания

*ptr2=*ptr1+4;

 

Можно интерпретировать так: взять содержимое памяти по адресу, равному значению указателя ptr1, прибавить к этому содержимому 4, а результат поместить по адресу, равному значению указателя ptr2.

Сам указатель-переменная тоже имеет адрес. Поэтому, например, корректным будет фрагмент:

int var1, *ptr1, *ptr2 = &var1;

ptr1 = (int*)&ptr2;

 

Здесь описываются два указателя-переменные, Указатель ptr2 инициализируется значением адреса переменной var1. Затем указателю ptr1 присваивается значение адреса, по которому в памяти располагается указатель ptr2.

Для указателей-переменных разрешены некоторые операции: присваивание, инкремент или декремент, сложение или вычитание, сравнение.

Язык разрешает операцию сравнение указателей одинакового типа (!). При выполнении присваивания значение указателя в правой части выражения пересылается в ячейку памяти, отведенную для указателя в левой части.

Важной особенностью арифметических операций с указателями является то, что физическое увеличение или уменьшение его значения зависит от типа указателя, т.е. от размера того объекта, на который ссылается указатель. Если к указателю, описанному как type *ptr, прибавить или отнять константу N, значение ptr изменяется на N* sizeof(type). Разность двух указателей type *ptr1 и type *ptr2 – это разность их значений, поделенная на sizeof(type).

В частности, арифметические операции над указателями типа char* (размер типа равен 1) выполняются как над обычными целыми числами с той лишь разницей, что значения, участвующие в операции, - это адреса в оперативной памяти. Однако для других типов это не так. Например:

 

void main(void)

{

long *ptr1=(long*)100;

long *ptr2=(long*)200;

ptr1++;

ptr2-=10;

printf(“ptr2=%ld,ptr1=%ld,

ptr2-ptr1=%ld\n”,

ptr2,ptr1,ptr2-ptr1);

}

Результат: ptr2=160,ptr1=104,ptr2-ptr1=14

 

Так как указатель имеет тип long* (длина 4 байта), то «единица измерения» указателя равна 4 байтам.

В самом деле:

ptr1=100+1*4=104.

ptr2=200-10*4=160.

ptr2-ptr1=(160-104)/4=56/4=14.

 

Для чего нужны указатели? Указатели появились, прежде всего, для нужд системного программирования. Поскольку язык Си предназначался для "низкоуровневого" программирования, на нем нужно было обращаться, например, к регистрам устройств. У этих регистров вполне определенные адреса, т.е. необходимо было прочитать или записать значение по определенному адресу. Благодаря механизму указателей, такие операции не требуют никаких дополнительных средств языка.

int *ptr=(int*)200;

 

Однако использование указателей нуждами системного программирования не ограничивается. Указатели позволяют существенно упростить и ускорить ряд операций. Предположим, в программе имеется область памяти для хранения промежуточных результатов вычислений. Эту область памяти используют разные модули программы. Вместо того, чтобы каждый раз при обращении к каждому конкретному модулю копировать эту область памяти, мы можем передавать указатель на эту область в качестве аргумента вызова функции, тем самым упрощая и ускоряя вычисления.

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

 

Массивы

 

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

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

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

ü Все элементы массива расположены в памяти друг за другом; индекс первого элемента равен НУЛЮ.

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

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

Например:

char array[81];

int key[4];

 

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

ü Инициализация по умолчанию. Это случай, когда все элементы массивов инициализируются нулями.

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

Существуют две формы явной инициализации элементов массива:

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

Например:

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

 

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

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

Например:

 

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

 

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

 

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

 

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

extern char array[];

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

int function (int array[], int index)

{

// тело функции

}

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

 

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



Поделиться:


Последнее изменение этой страницы: 2016-04-26; просмотров: 409; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

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