Основные языки программирования С/С++

Автор работы: Пользователь скрыл имя, 09 Ноября 2013 в 12:54, курсовая работа

Краткое описание

В качестве написания программного обеспечения используется среда программирования Visual Studio 2012 с использованием стандартных компонентов. Для создания программных продуктов используется принцип структурно-модульного программирования. Задание курсовой работы состоит реферата по двум теоретическим вопросам с номерами 8 и 28, а также создания четырех программ, которые решают поставленные задачи с номерами 8, 28, 48 и 68.
Язык Си не связан с какими-либо определенными аппаратными средствами или системами, и на нем легко писать программы, которые можно пропускать без изменений на любой ЭВМ, имеющей Си-компилятор.

Содержание

Календарний план 2
Реферат 3
Введение 5
Теоретическое задание № 1 6
Теоретическое задание № 2 25
Описание решения для задания 1 35
Описание решения для задания 2 36
Описание решения для задания 3 38
Описание решения для задания 4 39
Вывод 41
Список использованной литературы: 42
Приложения 43
Приложение № 1 (код программы 1) 43
Приложение № 2 (код программы 2) 45
Приложение № 3 (код программы 3) 46
Приложение № 4 (код программы 4) 46

Прикрепленные файлы: 1 файл

пояснительная записка к курсовой.docx

— 248.78 Кб (Скачать документ)

"Издательский дом \"Питер\""

Все строковые литералы рассматриваются  компилятором как различные объекты.

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

"Никто не доволен своей  \ 
внешностью, но все довольны \ 
своим умом"

полностью эквивалентна строке

"Никто не доволен своей  внешностью, но все довольны своим  умом"

В конец каждого строкового литерала компилятором добавляется нулевой  символ, представляемый управляющей  последовательностью \0. Поэтому длина  строки всегда на единицу больше количества символов в ее записи. Таким образом, пустая строка "" имеет длину 1 байт. Обратите внимание на разницу  между строкой из одного символа, например, "A", и символьной константой 'A'.

Пустая символьная константа недопустима.

Ссылки в C++

Ссылка представляет собой синоним имени, указанного при инициализации ссылки. Ссылку можно рассматривать как указатель, который всегда разыменовывается. Формат объявления ссылки:

тип & имя;

где тип — это тип величины, на которую указывает ссылка, & — оператор ссылки, означающий, что  следующее за ним имя является именем переменной ссылочного типа, например:

int коl; 
int& pal = kol; // ссылка pal - альтернативное имя для коl 
const char& CR = '\n '; // ссылка на константу

Запомните следующие правила.

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

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

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

Указатели

Когда компилятор обрабатывает оператор определения переменной, например, inti=10;, он выделяет память в соответствии с типом (int) и инициализирует ее указанным значением (10). Все обращения в программе к переменной по ее имени (i) заменяются компилятором на адрес области памяти, в которой хранится значение переменной. Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями.

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

  • указатели на объект,
  • указатели на функцию
  • указатели на void,

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

Указатель на функцию

Указатель на функцию содержит адрес в сегменте кода, по которому располагается исполняемый код функции, то есть адрес, по которому передается управление при вызове функции. Указатели на функции используются для косвенного вызова функции (не через ее имя, а через обращение к переменной, хранящей ее адрес), а также для передачи имени функции в другую функцию в качестве параметра. Указатель функции имеет тип «указатель функции, возвращающей значение заданного типа и имеющей аргументы заданного типа»:

тип (*имя) ( список_типов_аргументов );

Например, объявление:

int (*fun) (double, double);

задает указатель с именем fun на функцию, возвращающую значение типа int и имеющую два аргумента  типа double.

Указатель на объект

Указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа (основного или составного). Простейшее объявление указателя на объект (в дальнейшем называемого просто указателем) имеет вид:

тип *имя;

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

Звездочка относится непосредственно к имени, поэтому для того, чтобы объявить несколько указателей, требуется ставить ее перед именем каждого из них. Например, в операторе

int *a, b, *c;

описываются два указателя на целое  с именами а и с, а также целая переменная b.

Размер указателя зависит от модели памяти. Можно определить указатель  на указатель и т. д.

Указатель на void

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

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

Примеры объявления указателей

Указатель может быть константой или  переменной, а также указывать  на константу или переменную. Рассмотрим примеры:

int i; // целая переменная 
const int ci = 1; // целая константа 
int * pi; // указатель на целую переменную 
const int * pci; // указатель на целую константу 
int * const ср = &i; // указатель-константа на целую переменную 
const int * const срс = &ci; // указатель-константа на целую константу

Как видно из примеров, модификатор const, находящийся между именем указателя  и звездочкой, относится к самому указателю и запрещает его  изменение, а const слева от звездочки  задает постоянство значения, на которое  он указывает. Для инициализации  указателей использована операция получения адреса &.

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

Инициализация указателей. Динамическое выделение памяти

Указатели чаще всего используют при  работе с динамической памятью, называемой некоторыми эстетами кучей (перевод  с английского языка слова heap). Это свободная память, в которой  можно во время выполнения программы  выделять место в соответствии с  потребностями. Доступ к выделенным участкам динамической памяти, называемым динамическими переменными, производится только через указатели. Время жизни динамических переменных — от точки создания до конца программы или до явного освобождения памяти. В C++ используется два способа работы с динамической памятью. Первый использует семейство функций malloc и достался в наследство от С, второй использует операции new и delete.

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

Способы инициализации  указателей

  1. Присваивание указателю адреса существующего объекта:
    • с помощью операции получения адреса: 
      int а = 5; // целая переменная 
      int* р = &а; //в указатель записывается адрес а 
      int* р (&а); // то же самое другим способом
    • с помощью значения другого инициализированного указателя: 
      int* r = р;
    • с помощью имени массива или функции, которые трактуются как адрес: 
      int b[10]; // массив 
      int* t = b; // присваивание адреса начала массива 
      ... 
      void f(int а ){ /* ... * / } // определение функции 
      void (*pf)(int); // указатель на функцию 
      pf = f; // присваивание адреса функции
  2. Присваивание указателю адреса области памяти в явном виде: 
    char* vp = (char *)0хВ8000000; 
    Здесь 0хВ8000000 — шестнадцатеричная константа, (char *) — операция приведения типа: константа преобразуется к типу «указатель на char».
  3. Присваивание пустого значения: 
    int* suxx = NULL; 
    int* rulez = 0;В первой строке используется константа NULL, определенная в некоторых заголовочных файлах С как указатель, равный нулю. Рекомендуется использовать просто 0, так как это значение типа int будет правильно преобразовано стандартными способами в соответствии с контекстом. Поскольку гарантируется, что объектов с нулевым адресом нет, пустой указатель можно использовать для проверки, ссылается указатель на конкретный объект или нет.
  4. Выделение участка динамической памяти и присваивание ее адреса указателю:
    • с помощью операции new: 
      int* n = new int; //1 
      int* m = new int (10); // 2 
      int* q = new int [10]; // 3
    • с помощью функции malloc (для того чтобы использовать malloc, требуется подключить к программе заголовочный файл <malloc.h>.) 
      int* u = (int *)malloc(s1zeof(int)); // 4

В операторе 1 операция new выполняет  выделение достаточного для размещения величины типа 1 nt участка динамической памяти и записывает адрес начала этого участка в переменную n. Память под саму переменную п (размера, достаточного для размещения указателя) выделяется на этапе компиляции.

В операторе 2, кроме описанных выше действий, производится инициализация  выделенной динамической памяти значением 10.

В операторе 3 операция new выполняет  выделение памяти под 10 величин типа int (массива из 10 элементов) и записывает адрес начала этого участка в  переменную q. которая может трактоваться как имя массива. Через имя можно обращаться к любому элементу массива.

Если память выделить не удалось, по стандарту должно порождаться исключение bad_alloc. Старые версии компиляторов могут  возвращать 0.

В операторе 4 делается то же самое, что  и в операторе 1, но с помощью  функции выделения памяти та 11 ос, унаследованной из библиотеки С, В функцию передается один параметр — количество выделяемой памяти в байтах. Конструкция (int*) используется ц,ля приведения типа указателя, возвращаемого функцией, к требуемому типу.Если память выделить не удалось, функция возвращает 0.

Операцию new использовать предпочтительнее, чем функцию malloc, особенно при работе с объектами.

Освобождение памяти, выделенной с  помощью операции new, должно выполняться  с помощью delete, а памяти, выделенной функцией malloc — посредством функции free. При этом переменная-указатель  сохраняется и может инициализироваться повторно. Приведенные выше динамические переменные уничтожаются следующим  образом:

delete n; delete m; delete [ ] q; free (u);

Если память выделялась с помощью new[], для освобождения памяти необходимо применять delete[]. Размерность массива  при этом не указывается. Если квадратных скобок нет, то никакого сообщения об ошибке не выдается, но помечен как  свободный будет только первый элемент  массива, а остальные окажутся недоступны для дальнейших операций. Такие ячейки памяти называются мусором.

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

int *(*р[10])();

объявляется массив из 10 указателей на функции без параметров, возвращающих указатели на int.

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

При интерпретации сложных описаний необходимо придерживаться правила  «изнутри наружу»:

  1. если справа от имени имеются квадратные скобки, это массив, если скобки круглые — это функция;
  2. если слева есть звездочка, это указатель на проинтерпретированную ранее конструкцию;
  3. если справа встречается закрывающая круглая скобка, необходимо применить приведенные выше правила внутри скобок, а затем переходить наружу;
  4. в последнюю очередь интерпретируется спецификатор типа.

Для приведенного выше описания порядок  интерпретации указан цифрами:

int *(*р[10])(); 

5   4  2  1   3 // порядок интерпретации описания;


Операции с указателями  в C++

С указателями можно выполнять  следующие операции:

  • разадресация, или косвенное обращение к объекту (*)
  • присваивание,
  • сложение с константой,
  • вычитание,
  • инкремент (++),
  • декремент (—),
  • сравнение,
  • приведение типов.

При работе с указателями часто  используется операция получения адреса (&).

Операция разадрееации, или разыменования, предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявлена как константа):

char а; // переменная типа char 
char * р = new char; /* выделение памяти под указатель и под динамическую переменную типа char */ 
*р = 'Ю'; а = *р; // присваивание значения обеим переменным

Как видно из примера, конструкцию *имя_указателя можно использовать в левой части оператора присваивания, так как она является L-значением, то есть определяет адрес области  памяти. Для простоты эту конструкцию  можно считать именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа (если указатель инициализирован). На одну и ту же область памяти может  ссылаться несколько указателей различного типа. Примененная к ним  операция разадресации даст разные результаты. Например, программа

#include <stdio.h> 
int main(){ 
unsigned long int A = 0Xcc77ffaa; 
unsigned short int* pint = (unsigned short int*) &A; 
unsigned char* pchar = (unsigned char *) &A; 
printf("| %x | %x | %x |", A, *pint, *pchar); 
return 0; 
}

на IBM РС-совместимом компьютере выведет  на экран строку ():

| cc77ffaa | ffaa | аа |

Значения указателей pint и pchar одинаковы, но разадресация pchar дает в результате один младший байт по этому адресу, а pint — два младших байта.

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

Информация о работе Основные языки программирования С/С++