Символьные и строковые константы. A2.5.2

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

Примеры:

“1234567890”

“\t состав президиума”

“начало строки \t и конец строки”.

В качестве терминирующего символа выбран символ с кодом 0 (не путайте его с символом "0"). Таким образом, определение

char HelloStr = "Hello, world";

фактически интерпретируется как

char HelloStr = {"H", "e", "l", "l", "o", " ", ",", "w", "o", "r", "l", "d", "\0"};

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

printf ("Hello, world\n");

на самом деле интерпретируется как

char str1 = "Hello, world\n";

При размещении строки в памяти транслятор автоматически добавляет в ее конец символ ‘\0’, т.е. нулевой байт.

Количество элементов в таком массиве на 1 больше, чем в изображении соответствующей строковой константы, т.к. в конец строки добавили нулевой байт ‘\0’.

У строк есть еще особенность: транслятор отводит каждой строке отдельное место в памяти ЭВМ даже в тех случаях, когда несколько строк полностью совпадают (стандарт языка СИ предполагает, что в конкретных реализациях это правило может не выполняться).

Присвоить значение массиву символов (т.е. строке) с помощью обычного оператора присваивания нельзя. Поместить строку в массив можно либо с помощью инициализации (при определении символьного массива), либо с помощью функций ввода. В функции scanf () или printf () для символьных строк используется спецификация преобразования % s .

Пример:

/*печать символьной строки*/

#include

{ char B=”Cезам, откройся!”;

printf(“%s”,B); } /*конец программы*/

Результат выполнения программы: Сезам, откройся!

В программе длина массива В – 17 элементов, т.е. длина строки, помещаемой в массив (16 символов), плюс нулевой байт окончания строки. Именно 17 байтов выделяется при инициализации массива в приведенном примере. Инициализация массива символов с помощью строковой константы представляет собой сокращенный вариант инициализации массива и введена в язык для упрощения. Можно воспользоваться обычной инициализацией, поместив начальные значения элементов массива в фигурные скобки и не забыв при этом поместить в конце списка начальных значений специальный символ окончания строки ‘\0’. Таким образом, в программе была допустима такая инициализация массива В:

char B = {‘C’,’е’,’з’,’а’,’м’,’,’,’ ’,’о’,’т’,’к’,’р’,’о’,’й’,’с’,’я’,’!’,’\0’};

Как вводить строки или выводить их на экран?

Выводиться строка может или уже известной вам функцией printf() со спецификатором ввода "%s ", либо специальной функцией int puts (char *string), которая выводит строку string на экран и возвращает некоторое ненулевое значение в случае успеха.

Зачем нужен спецификатор "%s "? Это делается для того, чтобы можно было выводить строки с любыми символами. Сравните:

Пример:

char str = "Захотелось мне вывести %d...";

printf ("%s", str); /* Правильный вариант */

printf ("\n"); /* Разделитель новой строки */

printf (str); /* Неправильный вариант */

В первом случае функция напечатает именно то, что от нее требуется. А вот во втором случае printf() , встретив в строке str спецификатор "%d" (ведь теперь эта строка – первая, значит, она задает формат вывода), сделает вывод, что за ней должно следовать число. А так как оно не следует, то вместо "%d " будет напечатан некоторый мусор – число, находящееся в тот момент в стеке.

Последствия могут быть и более серьезными, если в строке находится последовательность "%s", то сочтет ее за строку, и будет выводить ее до тех пор, пока не встретит нулевой символ. А где она его встретит, сколько успеет напечатать и не crash"нется ли из-за обращения не к своей памяти – не знает никто.

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

/*чтение строки с терминала*/

int getline(char s , / *введенная строка*/

int lim) /*ее максимальная длина*/

{ int c, i; /* с – вводимый символ*/

for (i=0; i

s[i] = ’\0’;

      Ввод–вывод строк. Основные функции работы со строками

Одной из наиболее популярных операций ввода-вывода является операция ввода-вывода строки символов. В библиотеку языка СИ для обмена данными через стандартные потоки ввода-вывода включены функции ввода-вывода строк gets () и puts (), которые удобно использовать при создании диалоговых систем.

Для ввода строки существует функция с прототипом

char *gets (char *string),

которая считывает строку с клавиатуры и помещает ее в буфер string , указатель на который и возвращает. Если произошла ошибка, то возвращается EOF.

Функция имеет только один аргумент – указатель s < stdio . h >.

Функция gets() завершает свою работу при вводе символа ‘\ n , который автоматически передается с клавиатуры в ЭВМ при нажатии клавиши . При этом сам символ ‘\ n во вводимую строку не записывается. Вместо него в строку помещается нуль–символ ‘\0’ . Таким образом, функция gets () производит ввод “правильной” строки , а не просто последовательности символов.

Здесь следует обратить внимание на следующую особенность ввода данных с клавиатуры. Функция gets () начинает обработку информации от клавиатуры только после нажатия клавиши < Enter >. Таким образом, она “ожидает”, пока не будет набрана нужная информация и нажата клавиша <Enter >. Только после этого начинается ввод данных в программу.

Пример: #include

int main (void) {

printf ("Input a string:");

printf ("The string input was: %s\n", string);

Функция puts () (вывод строки на экран) в случае успешного завершения возвращает последний выведенный символ, который всегда является символом ‘\ n " , если произошла ошибка, то возвращается из функции EOF. Прототип этой функции имеет следующий вид:

int puts (char*s); /*функция вывода строки*/

Функция имеет только один аргумент – указатель s на массив символов. Прототип функции описан в файле < stdio . h >.

Приведем простейший пример использования этих функций.

#include

char strl = ”введите фамилию сотрудника:”;

Напомним, что любая строка символов в языке СИ должна заканчиваться нуль–символом ‘\0’ . В последний элемент массива strl нуль–символ будет записан автоматически во время трансляции при инициализации массива. Для функции puts() наличие нуль-символа в конце строки является обязательным.

В противном случае, т.е. при отсутствии в символьном массиве символа ‘\0’ , программа может завершиться аварийно, т.к. функция puts () в поисках нуль-символа будет перебирать всю доступную память байт за байтом, начиная, в нашем примере, с адреса strl . Об этом необходимо помнить, если в программе происходит формирование строки для вывода ее на экран дисплея.

Пример : #include

int main (void) {

char string = "This is an example output string\n";

      Функции манипуляции со строками

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

Для манипуляций со строками существует набор функций, объявленных в файле (те, кто пишет под Windows, могут включать вместо него файл <windows.h >).

Наиболее важные функции:

    int strcmp (char *string1, char *string2)

осуществляет сравнение двух строк . Возвращает отрицательное число, если первая строка меньше второй, 0, если строки равны и положительное число, если первая строка больше второй. Более детально, функция возвращает разницу между кодами первых встретившихся неодинаковых символов (если строки неодинаковы по длине, то когда-то ненулевой символ будет сравниваться с нулем).

Пример :

#include

#include

int main (void) {

char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";

ptr = strcmp (buf2, buf1);

if (ptr > 0)

printf("buffer 2 is greater than buffer 1 \n");

printf("buffer 2 is less than buffer 1 \n");

ptr = strcmp(buf2, buf3);

printf("buffer 2 is greater than buffer 3\n");

printf("buffer 2 is less than buffer 3\n");

На экране появится:

buffer 2 is greater than buffer 1

buffer 2 is less than buffer 3

    char *strcpy (char *dest, char *source)

осуществляет копирование строки source на место строки dest . Опять-таки позаботьтесь о том, чтобы вся строка поместилась в отведенном для нее месте. Функция возвращает указатель на строку-приемник.

Пример: #include

#include

int main (void) {

char *str1 = "a b c d e f g h i";

strcpy (string, str1);

printf("%s \n", string);

На экране появится: a b c d e f g h I

    char *strcat (char *string1, char *string2)

осуществляет склеивание двух строк . Вторая строка добавляется в конец первой. Функция не проверяет (да и не может проверять технически) наличие необходимого количества памяти в конце первой строки – об этом должны позаботиться вы. Функция возвращает указатель на первую строку.

Пример:

#include

#include

int main(void) {

char destination;

char *blank = " ", *c = "C++", *turbo = "Turbo";

strcpy (destination, turbo); //Копирование строки "turbo"

на место destination

strcat (destination, blank); // Склеивание destination …

strcat (destination, c); // сначала с blank , потом с c

printf("%s\n", destination);

На экране появится: Turbo C ++

    int strlen (char *string)

возвращает длину строки string (не считая нулевого символа).

    char *strdup (char *string)

создает дубликат строки string и возвращает указатель на него. Учтите, что в отличие от остальных функций, strdup сама создает строку и поэтому после того, как она стала вам не нужна, не забывайте ее освободить.

    char *strncpy (char *dest, char *source, int count)

    char *strncat (char *string1, char *string2, int count)

аналогично strcpy и strcat , но копируются только первые count символов. Функции не добавляют к строке завершающего нуля – вам придется сделать это самим.

    char *strchr (char *string, int c)

    char *strstr (char *string, char *substring)

ищут первое вхождение в строку string соответственно символа c и подстроки substring . Обе функции возвращают адрес первого вхождения или NULL , если такового не найдено.

Пример :

int main (void) {

char *ptr, c = "r";

//Создаем строку

strcpy (string, "This is a string");

ptr = strchr(string, c);

printf("The character %c is at position: %d\n", c, ptr-string);

printf("The character was not found\n");

Ввод-вывод

Финкции вывода:

%d-целое число со знаком

%u- целое число без знака

%f-вещественное число

%с-символ

Финкции ввода:

24 Типы данных языка Си.

long int counter;

Арифметические константы.

или в шестнадцатеричном виде:

\а сигнал-звонок

\\ обратная наклонная черта

\b возврат на шаг (забой)

\f перевод страницы

\n новая строка

\r возврат каретки

\? знак вопроса

\" одиночная кавычка

\” двойная кавычка

\ooo восьмеричный код

\xhh шестнадцатеричный код

Будьте внимательны и помните, что символьная константа и строка, содержащая один символ, не одно и то же: "х " не то же самое, что "х". Запись "х" обозначает целое значение, равное коду буквы х из стандартного символьного набора, а запись "х" - массив символов, который содержит один символ (букву х) и " \0".

Переменные и их описания.

В Си любая переменная должна быть объявлена раньше, чем она будет использована; обычно все переменные объявляются в начале функции перед первой исполняемой инструкцией. В объявлении описываются свойства переменных. Оно состоит из названия типа и списка переменных, например:

int fahr, celsius;

int lower, upper, step;

В своем объявлении переменная может быть инициализирована, как, например:

char esc = " \ \" ;

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

const double e = 2.71828182845905;

const char msg = "предупреждение: ";

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

int strlen(const char);

Реакция на попытку изменить переменную, помеченную квалификатором const, зависит от реализации компилятора.

Унарные операции в Си.

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

Побитовые операции в Си.

В Си имеются шесть операторов для манипулирования с битами. Их можно применять только к целочисленным операндам, т. е. к операндам типов char, short, int и long, знаковым и беззнаковым.

& - побитовое И.

| - побитовое ИЛИ.

^ - побитовое исключающее ИЛИ. << - сдвиг влево.

>> - сдвиг вправо.

~ - побитовое отрицание (унарный).

Оператор & (побитовое И) часто используется для обнуления некоторой группы разрядов. Например,

n = n & 0177 обнуляет в n все разряды, кроме младших семи.

Оператор | (побитовое ИЛИ) применяют для установки разрядов; так, х = х! SET_ON устанавливает единицы в тех разрядах х, которым соответствуют единицы в SET_ON.

Поразрядные операторы & и | следует отличать от логических операторов && и ||, которые при вычислении слева направо дают значение истинности. Например, если х равно 1, а у равно 2, то х & у даст нуль, а х && у - единицу.

Оператор ^ (побитовое исключающее ИЛИ) в каждом разряде установит 1, если соответствующие разряды операндов имеют различные значения, и 0, когда они совпадают.

Операторы << и >> сдвигают влево или вправо свой левый операнд на число битовых позиций, задаваемое правым операндом, который должен быть неотрицательным. Так, х << 2 сдвигает значение х влево на 2 позиции, заполняя освобождающиеся биты нулями, что эквивалентно умножению х на 4. Сдвиг вправо беззнаковой величины всегда сопровождается заполнением освобождающихся разрядов нулями. Сдвиг вправо знаковой величины на одних машинах происходит с распространением знака ("арифметический сдвиг"), на других - с заполнением освобождающихся разрядов нулями ("логический сдвиг").

Унарный оператор ~ поразрядно "обращает" целое т. е. превращает каждый единичный бит в нулевой и наоборот. Например, х = х & ~077 обнуляет в х последние 6 разрядов.

Условные операторы в Си.

Условный оператор if

Синтаксис:

а) сокращённая форма

if (<выр>) <оператор1>;

б) полная форма

if (<выр>) <оператор1>;

else <оператор2>;

Выражение <выр> может быть арифметическим, логическим или отношением. Если значение <выр> не равно нулю, то исполняется <оператор1>.

В полной форме если <выр> равно нулю, то исполняется <оператор2>.

Условная трёхместная операция (? :)

Синтаксис:

<выр1> ? <выр2> : <выр3>;

Первым вычисляется значение <выр1>.

Если оно не равно нулю (истинно), то вычисляется значение <выр2>. Значение <выр3> не вычисляется.

Если значение <выр1> равно нулю (ложно), то вычисляется значение <выр3>. Вычисление значения <выр2> не производится.

Sign = x<0 ? -1: 1;

35. Оператор-переключатель.

Переключатели

Синтаксис:

switch(<выр>)

case <константа_1> : <операторы_1>;

case <константа_2> : <операторы_2>;

case <константа_L> : <операторы_L>;

default: <операторы>;

При входе в переключатель вычисляется значение <выр>. Если оно совпадает с одной из констант, то выполняются операторы, указанные в соответствующей ветви case. Например, если <выр>==<константа_L>, то выполняются <операторы_L>.

Если значение <выр> не совпадает ни с одной из констант, то выполняются операторы, указанные после default.

Если среди операторов исполняемой ветви нет какого-либо оператора перехода (break, goto, return, exit()), то исполняются операторы следующей ветви.

Если среди операторов исполняемой ветви встретился оператор break, то управление передаётся оператору, следующему за переключателем. Если встретился оператор goto, то управление передаётся на указанную метку.

Ветвь default, может располагаться в любом месте группы ветвей переключателя.

switch (operand) {

case MULTIPLY: x *= y; break;

case DIVIDE: x /= y; break;

case ADD: x += y; break;

case SUBTRACT: x -= y; break;

case INCREMENT2: x++;

case INCREMENT1: x++; break;

case MOD: printf("Not done\n"); break;

default: printf("Bug!\n");

Если operand == MULTIPLY, то будет выполнено x *= y; и обработка переключателя (и исполнение программы) завершится.

Если operand == INCREMENT2, то будет выполнено x++; x++; и обработка переключателя завершится.

Если operand примет значение EXPONENT, ROOT или MOD, то будет исполнено printf("Not done\n"); break;

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

Параметрический цикл For

Синтаксис:

for ([<выр1>]; [<выр2>]; [<выр3>]) <оператор>;

<оператор> повторно исполняется до тех пор, пока <выр2> не примет значения 0 («ложь»).

ДО ПЕРВОЙ итерации цикла вычисляется значение <выр1>. Обычно это используют для инициализации счётчика цикла. Затем вычисляется значение <выр2>.

ПОСЛЕ КАЖДОЙ итерации вычисляется значение <выр3>. Обычно это используют для увеличения значения счётчика цикла. Затем вычисляется значение <выр2>.

<выр1> и <выр3> могут состоять из нескольких выражений, разделённых запятыми.

Все параметры заголовка цикла необязательные, но оба разделителя ‘;’ должны иметь место. Т.е., допустимы формы

For(<выр1>;;) <оператор>;

For(;<выр2>;) <оператор>;

For(;;<выр3>) <оператор>;

For(<выр1>;;<выр3>) <оператор>;

Если отсутствует <выр2>, то его значение считается равным 1 («истина»).

Цикл с предусловием while

Синтаксис:

while (<выр>) <оператор>;

<оператор> <выр> <выр> вычисляется ПЕРЕД каждой итерацией.

Цикл с постусловием do ... while

Синтаксис:

do <оператор> while (<выр>);

<оператор> повторно исполняется пока значение <выр> остаётся не равным нулю. Значение <выр> вычисляется ПОСЛЕ каждой итерациеи.

Оформление функций.

39. Структура Си-программы. Разновидности переменных.

void main() /* главная программа */

int x,y,z; /* объявление переменных целого типа */

x=5; y=6; /* операторы присваиания */

printf("сумма=%d\n",z); /* стандартная функция вывода из библ. */

Переменные нужны там, где требуется хранить какую - либо информацию в памяти компьютера, например, промежуточные результаты вычислений и т. д. Практически ни одна программа не обходится без них. Переменная представляет собой область оперативной памяти с присвоенным именем, через которое можно к этой области обращаться. Имя может достигать 247 символов в длину, всегда должно начинаться с буквы латинского алфавита или знака подчеркивания, за которыми могут следовать другие буквы, цифры и подчёркивания. Регистр символов имеет значение.

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

К целым типам относятся такие типы, как int, short (short int) и long. Переменные типа int занимают в памяти 32 бита. Переменные short в два раза "короче", о чем свидетельствует название. Они занимают в памяти 16 бит. Переменные типа long, соответственно, в два раза длиннее, занимают в памяти 64 бита.

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

К дробным типам относятся float и double - дробные числа одинарной и двойной точности соответственно. Переменные первого типа занимают в памяти 32 бита, второго типа - 64.

Логический тип всего один, и называется он bool. Как следует из названия, этот тип предназначен для хранения логических значений "истина" (true) или "ложь" (false).

Символьный тип тоже единственный. Он называется char и может хранить один символ, точнее, его номер в кодировке ASCII, в этом отношении этот тип близок целым типам. Диапазон значений типа char - целые числа от -128 до 127 (от 0 до 255 для unsigned char), то есть все символы латинского и национального алфавитов, цифры, знаки препинания и специальные символы, такие как переход на следующую строку и т.д. При этом следует помнить, что одиночные символы в C++ заключаются в апострофы.

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

Адресная арифметика.

может быть различной:

результат типа int*

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

Указатели и динамическое выделение памяти были вкратце представлены в разделе 2.2.

Указатель – это объект, содержащий адрес другого объекта и позволяющий косвенно

манипулировать этим объектом. Обычно указатели используются для работы с

динамически созданными объектами, для построения связанных структур данных, таких,

как связанные списки и иерархические деревья, и для передачи в функции больших

объектов – массивов и объектов классов – в качестве параметров.

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

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

типа указатель, и диапазон значений у них одинаков5. Разница состоит в том, как

компилятор воспринимает адресуемый объект. Указатели на разные типы могут иметь

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

может быть различной:

памяти 1000-1003 (в 32-битной системе);

памяти 1000-1007 (в 32-битной системе).

Когда мы применяем операцию взятия адреса (&) к объекту типа int, то получаем

результат типа int*

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

Форматный ввод-вывод.

Две функции: printf для вывода и scanf для ввода (следующий раздел) позволяют преобразовывать численные величины

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

printf(control, arg1, arg2, ...)

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

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

ются в выходной поток, и спецификации преобразований, каждая из которых вызывает преобразование и печать очередного аргу-

мента printf.

Каждая спецификация преобразования начинается с символа "%" и заканчивается символом преобразования (буквой, опреде-

ляющей тип преобразования). Между "%" и символом преобразования могут находиться:

Знак минус, который вызывает выравнивание преобразованного аргумента по левому краю поля.

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

Точка, которая отделяет ширину поля от следующей строки цифр.

Строка цифр (точность); указывает максимальное число символов строки, которые должны быть напечатаны, или число печатаемых справа от десятичной точки цифр для переменных типа float или double.

Модификатор длины l, который указывает, что соответствующий элемент данных имеет тип long, а не int.

Осуществляющая ввод функция scanf является аналогом printf и позволяет проводить в обратном направлении многие

из тех же самых преобразований. Функция scanf(control, arg1, arg2, ...) читает символы из стандартного ввода, интерпретирует их в соответствии с форматом, указанном в аргументе control, и помещает результаты в остальные аргументы. Управляющая строка описывается ниже; другие аргументы, каждый из которых должен быть указателем, определяют, куда следует поместить соответствующим образом преобразованный ввод.

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

ретации входных последовательностей. Управляющая строка может содержать:

Пробелы, табуляции или символы новой строки ("символы пустых промежутков"), которые игнорируются;

Обычные символы (не %), которые предполагаются совпадающими со следующими отличными от "символов пустых промежутков" символами входного потока;

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

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

Строка в СИ является массивом символов,который заканчивается нулвым символом (‘\0’).Доступ к строке осуществляется через указатель,ссылающийся на первый символ строки.Значением строки является адрес ее первого символа.Таким образом,в СИ правомерно сказать, что строка-это указатель,фактически указатель на первый символ строки.Строка может быть привоена в обьявлении либо массиву символов, либо переменной типа char*.

Структуры.

В современных языках программирования существует особый тип данных, который мо-

жет включать в себя несколько элементов более простых (причем разных!) типов.

Структура – это тип данных, который может включать в себя несколько полей - элементов

разных типов (в том числе и другие структуры).

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

Поскольку структура - это новый тип данных, его надо предварительно объявить в начала

char title; // название, символьная строка

int year; // год издания, целое число

int pages; // количество страниц, целое число

Для обращения ко всей структуре используется ее имя, а для обращения к отдельному по-

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

одному. Заполнять их можно в любом порядке. С полем структуры можно работать так же, как

и с переменной соответствующего типа: числовые переменные могут участвовать в арифмети-

ческих выражениях, со строками можно выполнять все стандартные операции.

strcpy (b.author, " А.С. Пушкин ");

Структуры служат для обработки большого объема информации, поэтому чаще всего в

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

рительно (выше) надо объявить саму структуру как новый тип данных.

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

ратных скобках еще номер нужной структуры, например

for (i = 0; i < 20; i ++) // цикл по всем структурам в массива

puts(A[i].title); // вывести название книги

Структуры, так же, как и любые другие типы, могут быть параметрами функций и проце-

Работа с файлами.

Файлы бывают текстовые (в которых можно записывать только буквы, цифры, скобки и

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

Текстовые файлы

(так же, как и для линейных массивов) ошибки отсутствия или недостатка данных в файле.

Двоичные файлы

С двоичным файлом удобно работать тогда, когда данные записала (или будет читать)

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

Описание функций работы с файломи находятся в библиотеке stdio.h

Сначала надо создать указатель на переменную типа FILE (FILE* file;).

Открытие файла производится вызовом функции fopen (file = fopen(file_name, "w");)

Первый параметр этой функции - имя файла, второй - указывает в каком режиме должен быть открыт файл. "w" - открыть для записи, "r" - открыть для чтения, "a" - дополнение файла(это наиболее используемые режимы, хотя есть и другие). Запись и считывание данных из файла осуществляется следующими функциями: fputc, fputs, fgetc, fgets, fprintf, fscanf(описание этих функций смотрите в stdio.h).

Закрытие файла осуществляется вызовом функции fclose (fclose(file);).

Ввод-вывод

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

Финкции вывода:

Int putchar(int c).Выводит один символ в поток стандартного ввода stdout

Int fputs(int c,FILE *f).Выводит один символ в файл f

Int puts(char *s).Выводит строку s до завершающего символа с кодом 0 в поток стандартного вывода.В конце выводится перевод строки

Int fputs(char *s,FILE *f).Выводит строку s до завершающего символа с кодом в файл f.

Int printf().Выводит текст,формат которого описан,в поток стандартного вывода.

Описание формата начинается с символа %

%d-целое число со знаком

%u- целое число без знака

%f-вещественное число

%с-символ

Финкции ввода:

Int getchar(void).читает один символ из потока стандартного вывода stdin

Int fgetc(FILE *f).Читает один символ из файла f

Char *fgets(char *s,int size,FILE *f).Читает из файла f строку размером не более чем size символо,включая символ конца строки и помещает ее по адресу s

Int scanf()Читает из стандартного потока ввода данные в соответствии с заданным форматом

24 Типы данных языка Си.

В Си имеются типы целых чисел различных размеров, со знаком и без, чисел с плавающей запятой, символов, перечисляемых типов (enum) и записей-структур (struct). Кроме того, язык Си предлагает тип объединение (union), с помощью которого можно либо хранить в одном месте памяти разнородные данные, не пересекающиеся по времени существования (это позволяет экономить память), либо обращаться к содержимому участка памяти, как к данным разных типов (что позволяет менять тип-интерпретацию данных, не меняя сами данные).

В Си существует несколько базовых типов:

char - единичный байт, может содержать один символ из допустимого символьного набора;

int - целое, обычно отображающее естественное представление целых в машине;

float - число с плавающей точкой одинарной точности;

double - число с плавающей точкой двойной точности.

Имеется также несколько квалификаторов, которые можно использовать вместе с указанными базовыми типами. Например, квалификаторы short (короткий) и long (длинный) применяются к целым:

long int counter;

В таких объявлениях слово int можно опускать, что обычно и делается.

Квалификаторы signed (со знаком) или unsigned (без знака) можно применять к типу char и любому целочисленному типу. Значения unsigned всегда положительны или равны нулю и подчиняются законам арифметики по модулю 2n, где n - количество битов в представлении типа. Так, если значению char отводится 8 битов, то unsigned char имеет значения в диапазоне от 0 до 255, a signed char - от -128 до 127 (в машине с двоич-

ным дополнительным кодом). Являются ли значения типа просто char знаковыми или беззнаковыми, зависит от реализации, но в любом случае коды печатаемых символов положительны.

Тип long double предназначен для арифметики с плавающей точкой повышенной точности. Как и в случае целых, размеры объектов с плавающей точкой зависят от реализации; float, double и long double могут

представляться одним размером, а могут - двумя или тремя разными размерами.

Арифметические константы.

Целая константа, например 1234, имеет тип int. Константа типа long завершается буквой l или L, например 123456789L; слишком большое целое, которое невозможно представить как int, будет представлено как long.

Беззнаковые константы заканчиваются буквой u или U, а окончание ul или UL говорит о том, что тип константы - unsigned long. Константы с плавающей точкой имеют десятичную точку (123.4), или экспоненциальную часть (1е-2), или же и то и другое. Если у них нет окончания, считается, что они принадлежат к типу double. Окончание f или F указывает на тип float, а 1 или L - на тип long double.

Целое значение помимо десятичного может иметь восьмеричное или шестнадцатеричное представление. Если константа начинается с нуля, то она представлена в восьмеричном виде, если с 0х или с 0Х, то - в шестнадцатеричном. Например, десятичное целое 31 можно записать как 037 или как 0X1F. Записи восьмеричной и шестнадцатеричной констант могут завершаться буквой L (для указания на тип long) и U (если нужно показать, что константа беззнаковая). Например, константа 0XFUL имеет значение 15 и тип unsigned long.

Символьные и строковые константы.

Символьная константа есть целое, записанное в виде символа, обрамленного одиночными кавычками, например "х" . Значением символьной константы является числовой код символа из набора символов на данной машине. Например, символьная константа "0" в кодировке ASCII имеет значение 48, которое никакого отношения к числовому значению 0 не имеет. Когда мы пишем "0" , а не какое-то значение (например 48), зависящее от способа кодировки, мы делаем программу независимой от частного значения кода, к тому же она и легче читается. Символьные константы могут участвовать в операциях над числами точно так же, как и любые другие целые, хотя чаще они используются для сравнения с другими символами.

Некоторые символы в символьных и строковых константах записываются с помощью эскейп-последовательностей, например \n (символ новой строки); такие последовательности изображаются двумя символами, но обозначают один.

Кроме того, произвольный восьмеричный код можно задать в виде "\ооо", где ооо - одна, две или три восьмеричные цифры (0...7) или "\xhh", где hh - одна, две или более шестнадцатеричные цифры (0...9, а...f , А...F). Таким образом, мы могли бы написать

#define VTAB "013" /* вертикальная табуляция в ASCII */

#define BELL "\007" /* звонок В ASCII */

или в шестнадцатеричном виде:

#define VTAB "\xb" /* вертикальная табуляция в ASCII */

#define BELL "\x7" /* звонок в ASCII */

Полный набор эскейп-последовательностей таков:

\а сигнал-звонок

\\ обратная наклонная черта

\b возврат на шаг (забой)

\f перевод страницы

\n новая строка

\r возврат каретки

\t горизонтальная табуляция \v вертикальная-табуляция

\? знак вопроса

\" одиночная кавычка

\” двойная кавычка

\ooo восьмеричный код

\xhh шестнадцатеричный код

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

Строковая константа, или строковый литерал, - это нуль или более символов, заключенных в двойные кавычки, как, например, "Я строковая константа" или “” (пустая строка).

Кавычки не входят в строку, а служат только ее ограничителями. Так же, как и в символьные константы, в строки можно включать эскейп-последовательности; \", например, представляет собой двойную кавычку. Строковые константы можно конкатенировать ("склеивать") во время компиляции; например, запись двух строк "Здравствуй," " мир!" эквивалентна записи одной следующей строки: "Здравствуй, мир!".

Указанное свойство позволяет разбивать длинные строки на части и располагать эти части на отдельных строчках.

Фактически строковая константа - это массив символов. Во внутреннем представлении строки в конце обязательно присутствует нулевой символ "\0", поэтому памяти для строки требуется на один байт больше, чем число символов, расположенных между двойными кавычками. Это означает, что на длину задаваемой строки нет ограничения, но чтобы определить ее длину, требуется просмотреть всю строку.

Лабораторная работа №1

Знакомство с языком программирования С++

Цель работы:

1. Изучение интерфейса программной оболочки Visual C++;

2. Компиляция и создание исполняемых файлов.

3. Изучение основных типов данных языка С++;

Базовые типы данных;

Переменные и константы;

4. Изучение операторов:

Арифметических;

Логических;

Сравнения;

Побитовых;

Ввода и вывода.

5. Приобретение навыков работы в ИСП Microsoft Visual C++ 5.0.

Используемое оборудование:

Персональная ЭВМ, совместимая с IBM PC.

Используемое программное обеспечение:

Операционная система Windows;

Интегрированная среда программирования Microsoft Visual C++ 5.0 (ИСП Microsoft Visual C++ 5.0).

Задание по работе

1.1. Загрузить ИСП Microsoft Visual C++ 5.0.

1.2. Изучить команды ИСП Microsoft Visual C++ 5.0.

1.3. Изучить основные типы данных ИСП Microsoft Visual C++ 5.0.

1.4. Выполнить пример 1, пример 2, пример 3 и задание преподавателя.

1.5. Записать протокол работы с интегрированной средой.

Порядок выполнения работы

2.1. Запустить Microsoft Visual C++ 5.0.

2.2. Создать *.cpp файл в рабочем каталоге.

2.3. Выполнить пример 1, пример 2, пример 3 и задание преподавателя.

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

2.5. Закончить работу с Microsoft Visual C++ 5.0 и запустить программу.

3.1. Наименование лабораторной работы.

3.2. Цель работы.

3.3. Теоретическую часть.

3.4. Алгоритмы выполненных программ.

3.5. Текст выполненных программ.

3.6. Вывод.

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

4.1. Запуск и работа в ИСП Microsoft Visual C++ 5.0.

Для запуска ИСП Microsoft Visual C++ 5.0 необходимо запустить меню Пуск - Microsoft Visual C++ 5.0 - Microsoft Visual C++ 5.0.

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

Ø Запустить Visual C++ (Пуск®Программы® Microsoft Visual C++ 5.0.® Microsoft Visual C++ 5.0. );

Ø Выбрать "New" в меню "File". Проверить, что бы в диалоговой панеле "New" была выбрана закладка "Projects". В списке типов проектов выберите "Win32 Console Application";

Ø Выбрать каталог для проекта ‘Location’ (С:\students\’группа*) и имя проекта ‘Project name’, например, "First" и нажмите кнопку "OK". У вас создадутся "First classes";

Ø После этого выберите опять "New", но с закладкой "Files" и выберите "C++ Source File". В списке ‘File name’ задайте имя например, "First" Далее нажмите "OK" и создастся файл "First.cpp".

Общая структура программы.

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

Ø Область директив препроцессора (include, define..);

Ø Описание пользовательских типов данных;

Ø Неполные объявления функций;

Ø Описание глобальных переменных;

Ø Объявление функции 1;

Ø Объявление функции 2;

Ø Объявление функции main().

Данная схема не имеет такого жесткого порядка как в Паскале, однако, она считается традиционной.

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

Минимальная программа выглядит следующим образом:

Void main(void)

Она состоит из функции main, не принимающей и не возвращающей параметров (void). Тело функции, заключенное в фигурные скобки, также не содержит никаких полезных операторов.

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

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

Выполнение программы по умолчанию заканчивается при завершении работы main, но может прерваться в любом месте при возникновении критической ошибки, или в предусмотренном случае. Для этого обычно используют функцию exit() из библиотеки stdlib.

Вывод строки на экран

Прежде всего, давайте напишем программу, выводящую строку на экран.

Программа должна содержать функцию с именем main(). Ей приписывается роль начала программы. Эта функция не является предопределенной для транслятора, она не может быть перегружена, а ее тип зависит от реализации. Функция main может определяться так:

Пример 1:

// Первая программа на С++

#include

Void main ()

cout << “Thise is my first program\n” << endl;

Для того, чтобы выполнить программу надо ее вначале сохранить. Зайдите в меню File и там нажмите на Save All . Затем надо ее построить (скомпилировать) для этого нужно выполнить следующие действия:

Ø Зайдем в меню (Build®Build *.exe) или сочетание клавиш (F7), начнется построение программы. Если компилятор не выдал сообщение об ошибке, которые можно посмотреть в появившемся внизу окошке, то можно смело запускать программу;

Ø Теперь вам осталось только выполнить программу, для этого зайдите в меню (Build®Execute *.exe.) или сочетание клавиш (Ctrl+F5);

Ø Ваша программа запущенна.

Строка #include сообщает компилятору, чтобы он включил стандартные возможности потока ввода и вывода, находящиеся в файле iostream.h. Без этих описаний выражение cout << "Thise is my first program " не имело бы смысла. Основные стандартные библиотеки приведены в таблице 1.

Таблица 1.

Основные стандартные библиотеки С/С++

Операция << ("поместить в") пишет свой первый аргумент во второй (в данном случае, строку "Thise is my first program " в стандартный поток вывода cout). Строка – это последовательность символов, заключенная в двойные кавычки. В строке символ обратной косой \, за которым следует другой символ, обозначает один специальный символ; в данном случае, \n является символом новой строки. Таким образом, выводимые символы состоят из "Thise is my first program " и перевода строки, которые определяют функцию, названную main . Каждая программа должна содержать функцию с именем main , и работа программы начинается с выполнения этой функции.

Ввод с клавиатуры

Следующая (довольно многословная) программа предлагает вам ввести число дюймов. После того, как вы это сделаете, она напечатает соответствующее число сантиметров.

Пример 2:

#include

Void main()

int inch = 0; // inch - дюйм

cout << "inches";

cin >> inch;

cout << inch;

cout << " in = ";

cout << inch*2.54;

cout << " cm\n";

Первая строка функции main() описывает целую переменную inch . Ее значение считывается с помощью операции >> ("взять из") над стандартным потоком ввода cin .

В этом примере на каждую команду вывода приходится один оператор; это слишком длинно. Операцию вывода << можно применять к ее собственному результату, так что последние четыре команды вывода можно было записать одним оператором:

cout << inch << " in = " << inch*2.54 << " cm\n";

Комментарии

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

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

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

4.6. Типы данных в C++

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

Ø Численные знаковые целые (int, short, char);

Ø Численные знаковые дробные (float, double, long (в С), long double (в С);

Ø Численные без знаковые - все перечисленные выше типы с добавлением Unsigned;

Ø Char так же может использоваться как символьный тип .

Стандартные типы и размеры соответствующих ячеек приведены ниже.

Диапазон Размер (Бт)
char -128..127;
unsigned char 0..255;
int -32 768.. 32 767;
unsigned int 0..65535;
long -2 147 483 648..2 147 483 647;
unsigned long 0..4 294 967 295;
float 3.4e-38..3.4e+38;
double 1.7e-308..1.7e+308;
long double 3.4e-4932..3.4e+4932.

Переменная в C/C++ объявляется следующим образом:

Int iMyVariable;

В приведенном операторе iMyVariable объявлена как целая переменная. А вот объявление переменной типа char :

Char cMyChar;

Такие типы данных, как int , float , char и long , являются неотъемлемой частью C/C++ и вам не нужно писать никакого кода, чтобы сообщить компилятору о том, что означают эти слова. C/C++ позволяет вам также объявлять свои собственные, специальные типы данных.

В примере 3 представлена программа, которая будет выводить размер типов данных в байтах. Пример 3:

#include

Void main(void)

cout << " (unsigned)int = " << sizeof(int) << endl;

cout << " (unsigned)short = " << sizeof(short) << endl;

cout << " (unsigned)char = " << sizeof(char) << endl;

cout << " (unsigned)float = " << sizeof(float) << endl;

cout << " (unsigned)double = " << sizeof(double) << endl;

cout << " (unsigned)long = " << sizeof(long) << endl;

cout << " (unsigned)long double = " << sizeof(long double) << endl;

Для того, чтобы узнать размер ячейки соответствующего типа достаточно написать в программе sizeof (тип). Дело в том, что для различных операционных систем размеры ячейки одного типа может отличаться (например тип int в 16-ти и 32-х разрядных ОС, 1 байт и 2 байта соответственно).

Оператор sizeof вычисляет размер своего операнда в байтах. Операнд должен быть или выражением, которое не вычисляется, или именем типа в скобках. Оператору sizeof нельзя применять к функции, битовому полю, неопределенному классу, типу void или к массиву с неуказанными границами индексов. Байт никак не определяется языком, кроме как результата операции sizeof , именно sizeof (char) есть 1.

4.7. Переменные

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

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

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

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

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

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

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

В языке С++ существуют два классификатора, управляющих доступом и модификацией: const и volatile .

Константа – это именованная область памяти, значение которой не может изменяться в процессе выполнения программы. Константам всегда присваивается некоторое значение при объявлении, и оно не может быть изменено в дальнейшем. Переменные типа const не могут изменяться, однако их можно инициализировать.

Квалификатор volatile сообщает компилятору, что значение переменной может изменяться неявно. Например , адрес глобальной переменной передать таймеру операционной системы и использовать его для отсчета реального времени. В этом случае содержимое переменной изменяется без явного выполнения какого-либо оператора присваивания.

В языке С/С++ предусмотрены управляющие символьные константы , которые приведены в таблице 2.

Таблица 2.

Управляющие символьные константы

Самые знаменитые служебные символы: перевод строки (код 13), возврат каретки (код 10), табуляция (код 9). Для задания их в программе в виде символьных констант используется сочетание двух видимых символов, а именно “\n”, “\r”, “\t” соответственно. Для представления символа “слэш“ используется конструкция “\\”

В языке С существуют четыре спецификатора хранения: extern, static, register, auto.

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


Похожая информация.


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

broiled = " Т "; /* ПРАВИЛЬНО */,

broiled = Т; /* НЕПРАВИЛЬНО */

Если апострофы опущены, компилятор "считает", что мы используем переменную с именем Т , которую забыли описать.

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

ehar bovine;

bovine = " ox "; /*НЕПРАВИЛЬНО */

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

В первом способе используется сам код ASCII. Вы должны только указать номер символа вместе с предшествующим знаком "обратная косая черта". Мы уже делали это в нашей программе "золотой эквивалент". Вот эта строка

beep = " 07 ";

Здесь имеются два важных момента, которые вы должны отчетливо представлять себе. Первый - это то, что последовательность знаков заключается в апострофы точно так же, как это делается с обычным символом. Второе - то, что номер символа должен быть записан в восьмеричном виде. При записи последовательности знаков мы можем случайно пропустить нули в первых позициях; в этом случае для представления кода "сигнал" мы могли бы использовать "7" или даже "7" . Но ни в коем случае не опускайте в записи последние нули! Последовательность символов "20" можно записать в виде "20" , но не "2" .

При использовании кода ASCII необходимо отметить различие между числами и символами, обозначающими числа. Например, символу "4" соответствует код ASCII, равный 52. Это символ "4" а не число 4.

РИС. 3. 4. Формы записи констант целых типов

Во втором способе представления "неудобных" знаков используются специальные последовательности символов. Они называются управляющими последовательностями и выглядят следующим образом:

n новая строка

t табуляция

b шаг назад

r возврат каретки

f подача бланка

обратная косая черта ()

" апостроф (")

" кавычки (")

При присваивании символьной переменной эти последовательно сти тоже должны быть заключены в апострофы. Например, мы могли бы написать оператор

nerf = " n ";

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

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

символ "новая строка" вызывает переход к новой строке;

символ "табуляция" сдвигает курсор или печатающую головку на некоторое фиксированное число позиций 5 или 8;

символ "шаг назад" производит сдвиг назад на одну позицию;

символ "возврат каретки" осуществляет возврат к началу строки;

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

В последних трех управляющих последовательностях символы , " , " можно считать символьными константами [поскольку они служат для определения символьных констант и непосредственно используются в операторе printf() , применение их самих в качестве символов могло бы привести к ошибке]. Если вы хотите вывести на печать строку.

Запомните, " символ называется обратная косая черта".

оператор будет выглядеть так:

printf(" Запомните, " символ называется обратная косая черта. " n");

Здесь у вас могут возникнуть два вопроса. Во-первых, почему мы не заключили управляющие последовательности в апострофы? Во-вторых, в каких случаях необходимо использовать код ASCII и когда управляющие последовательности, которые мы только что обсуждали? (Мы надеемся, что у вас возникли как раз эти вопросы, ПОТОМУ что мы собираемся отвечать именно на них.)

До этого момента, все переменные, которые мы рассматривали, были не константами. Их значения можно было изменить в любое время. Например:

int x { 4 }; // инициализация переменной x значением 4 x = 5; // изменяем значение x на 5

Тем не менее, иногда полезно использовать переменные, значения которых нельзя изменить – константы . Вот например, сила тяжести на Земле: 9.8м/с^2. Оно вряд ли поменяется в ближайшее время. Использовать константу для этого случая — наилучший вариант, так как таким способом мы предотвратим любое (даже случайное) изменение значения.

Чтобы сделать переменную константой – используйте ключевое слово const перед типом переменной или после. Например:

const double gravity { 9.8 }; // предпочтительнее использовать const перед типом данных int const sidesInSquare { 4 }; // ок, но не предпочтительно

Несмотря на то, C++ примет const как до, так и после типа, мы рекомендуем использовать именно перед типом.

Константы должны быть инициализированы при объявлении . Их значения с помощью операции присваивания изменить не получится.

const double gravity { 9.8 }; gravity = 9.9; // не допускается - ошибка компиляции

Объявление константы без инициализации также вызовет ошибку компиляции:

const double gravity; // ошибка компиляции, константа должна быть инициализирована

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

std::cout << "Enter your age: "; int age; std::cin >> age; const int usersAge (age); // в дальнейшем переменная usersAge не может быть изменена

const является наиболее полезным (и наиболее часто используемым) с параметрами функций:

void printInteger(const int myValue) { std::cout << myValue; }

void printInteger (const int myValue )

std :: cout << myValue ;

Таким образом, при вызове функции, константа-параметр говорит нам, что функция не будет изменять значение переменной myValue. Во-вторых, она гарантирует, что функция не изменит значение myValue.

Compile time и runtime

Когда вы находитесь в процессе компиляции программы – это compile time (время компиляции ) . Компилятор проверяет вашу программу на синтаксические ошибки, затем конвертирует код в объектные файлы.

Когда вы находитесь в процессе запуска вашей программы или когда программа уже выполняется — это runtime (время выполнения) . Код выполняется строка за строкой.

Constexpr

В C++ есть два вида констант.

Константы r untime . Их значения определяются только во время выполнения (когда программа запущена). Переменные типа usersAge и myValue (в коде выше) — это константы runtime, так как компилятор не может определить их значения во время компиляции. usersAge зависит от пользовательского ввода (который можно получить только во время выполнения программы), а myValue зависит от значения, переданного в функцию (которое станет известным также во время выполнения программы).

Константы c ompile-time . Их значения определяются во время компиляции. Например, сила тяжести Земли – это константа compile-time, мы её определили сами в ходе написания программы.

В большинстве случаев, неважно какой тип константы: compile-time или runtime. Однако, есть все же несколько ситуаций, когда C++ может требовать константу compile-time вместо runtime (например, при определении длины массива фиксированного размера — мы рассмотрим это позже). Так как типов есть два, то компилятору нужно постоянно отслеживать, к какому из них относится какая переменная. Чтобы упростить это задание, в C++ 11 появляется ключевое слово constexpr , которое гарантирует, что тип константы — compile-time:

constexpr double gravity (9.8); // ок, значение определяется во время компиляции constexpr int sum = 4 + 5; // ок, значение 4 + 5 определяется во время компиляции std::cout << "Enter your age: "; int age; std::cin >> age; constexpr int myAge = age; // не ок, переменная age не определяется во время компиляции

Использовать вы его, скорее всего, не будете, но знать о нем не помешает.

Правило: Любая переменная, которая не должна изменять свое значение после инициализации — должна быть объявлена, как const (или как constexpr).

Имена констант

Некоторые программисты пишут имена констант заглавными буквами. Другие используют обычные имена, только с префиксом ‘k’. Мы же не будем их как-то выделять, так как константы – это те же обычные переменные, просто с фиксированными значениями, вот и всё. Особой причины, чтобы их выделять нет. Однако, это дело каждого лично.

Символьные константы

В предыдущем уроке , мы обсуждали «магические числа» – литералы, которые используются в программе как константы. Поскольку их использование является плохой практикой, тогда что использовать вместо них? Ответ: символьные константы. Символьная (или еще символическая ) константа – это тот же литерал (магическое число), только с идентификатором. Есть два способа объявления символических констант в C++. Один из них хороший, а один не очень. Рассмотрим оба.

Плохой способ: Использование макросов-объектов с текстом-заменой в качестве символьных констант

Раньше этот метод широко использовался, так что вы все еще можете увидеть его в старых кодах.

В уроке 22 о препроцессорах и директивах , мы говорили, что макросы-объекты имеют две формы – с текстом-заменой и без. Рассмотрим первый случай (с текстом-заменой). Он выглядит так:

#define identifier substitution_text

Как только препроцессор встретит эту директиву, все дальнейшие появления ‘identifier’ будет заменяться на ‘substitution_text’. Идентификатор обычно пишется заглавными буквами с нижним подчеркиванием вместо пробелов.

Например:

int max_students = numClassrooms * MAX_STUDENTS_PER_CLASS;

#define MAX_STUDENTS_PER_CLASS 30

Во время компиляции, препроцессор заменит все идентификаторы MAX_STUDENTS_PER_CLASS на литерал 30.

Согласитесь, это гораздо лучший вариант, чем использование магических чисел, как минимум по нескольким причинам. MAX_STUDENTS_PER_CLASS обеспечивает контекст того, что это за значение и зачем оно надо, даже без комментариев. Во-вторых, если число нужно будет изменить — достаточно будет сделать правки только в директиве #define, все остальные идентификаторы MAX_STUDENTS_PER_CLASS в программе будут автоматически заменены новым значением при повторной компиляции.

Рассмотрим еще один пример:

#define MAX_STUDENTS_PER_CLASS 30 #define MAX_NAME_LENGTH 30 int max_students = numClassrooms * MAX_STUDENTS_PER_CLASS; setMax(MAX_NAME_LENGTH);

#define MAX_STUDENTS_PER_CLASS 30

#define MAX_NAME_LENGTH 30

int max_students = numClassrooms * MAX_STUDENTS_PER_CLASS ;

setMax (MAX_NAME_LENGTH ) ;

Здесь ясно, что MAX_STUDENTS_PER_CLASS и MAX_NAME_LENGTH имеются в виду как разные объекты, даже если у них одни и те же значения (30).

Так почему же этот способ плохой? Есть две причины.

Во-первых, макросы обрабатываются препроцессором, который заменяет идентификаторы на определенные значения. Эти значения не будут отображаться в отладчике (который показывает ваш фактический код). При компиляции int max_students = numClassrooms * 30; в отладчике вы увидите int max_students = numClassrooms * MAX_STUDENTS_PER_CLASS; . А если нужно будет узнать значение MAX_STUDENTS_PER_CLASS? Вам придется самостоятельно найти его в коде. А это может занять некоторое время, в зависимости от размеров программы.

Во-вторых, эти директивы всегда имеют глобальную область видимости (о ней мы поговорим позже). Это означает, что значения #define в одной части кода могут конфликтовать со значениями #define в другой части кода.

Правило: Не используйте #define для создания символьных констант.

Хороший способ: Переменные const

Лучший способ создать символьную константу — использовать const:

const int maxStudentsPerClass { 30 }; const int maxNameLength { 30 };

const int maxStudentsPerClass { 30 } ;

const int maxNameLength { 30 } ;

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

Правило: Используйте const для создания символьных констант.

Использование символьных констант в программе

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

Как это осуществить? Очень просто:

  1. Создайте заголовочный файл для хранения констант.
  2. В заголовочном файле объявите пространство имен (