Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Структура программы на языке С



Структура программы на языке С

 

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

Функция main() после запуска программы на исполнение начинает исполнятся первой.

 

Пример программы:

 

#include " stdafx.h"

#include < iostream> // подключение файла заголовка ввода\вывода

 

using namespace std; // указание н использование именованного пространства std

 

 

int _tmain(int argc, _TCHAR* argv[]) // заголовок функции main()

{

cout< < " Hello world! "; // вывод на экран строки " Hello world! "

 

return 0; // опереатор возврата управления с результатом 0

}

 

Комментарий к программе:

 

Строка #include < iostream> - это директива (команда) препроцессора, она указывает ему выполнить подключение файла заголовка iostream.h, в котором, в частности содержится объявление классов потокового ввода\вывода istream и ostream. Объекты этих классов cin (объект класса istream) и cout (объект класса ostream) используются соответственно для ввода вывода данных на консоль.

Консолью называется окно вывода информации на экране монитора, которое работает в текстовом режиме.

В строке cout< < " Hello world! "; пара символов < < это двух операндный оператор вывода:

cout – это первый операнд;

" Hello world! " – второй операнд.

 

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

 

cout< < " Hello world! " < < endl< < " End of program";

в которой в одном операторе выводится еще одна новая строка.

endl – это модификатор, которы используется для перехода на новую строку при выводе.

 

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

Многострочный комментарий задается символами:

 

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

*/ - конец комментария.

Все символы между началом и концом комментария – это комментарий.

 

Данные и операторы программы

 

Программа в ключает два элемента:

- данные, которые размещаются а различных местах оперативной памяти;

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

 

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

 

Переменные и типы

Переменная – это имя (идентификатор) области памяти, в которой хранятся данные этой переменной.

 

Данные могут быть разных типов (символьные, целые, вещественные и т.д.).

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

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

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

Эта проблема решается использование специальных операторов объявления переменных.

 

Пример оператора объявления:

 

int var;

 

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

 

int var1, var2, var3;

 

Пример программы, которая объявляет переменную, вводит в неё значение и выводит.

 

#include " stdafx.h"

#include < iostream>

 

using namespace std;

 

 

int _tmain(int argc, _TCHAR* argv[])

{

int var; // объвление переменной типа int

 

cout< < " Input value of int: ";

cin> > var; // ввод значения переменной

 

cout< < endl< < " var=" < < var;

 

return 0;

}

 

 

Понятие типа данных

 

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

1) формат представления данных в памяти (т.е. правила хранения данных этого типа в памяти);

2) диапазон допустимых значений этого типа, т.е. все возможные значения которые может принимать переменная этого типа (т.е. которые допускает формат представления данных этого типа);

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

 

Сообщение компилятору в программе в форме оператора объявления типа переменой позволяет компилятору правильно организовать хранение переменной и контролировать правильность её использования в действиях преобразования.

 

Основные элементарные типы данных

 

В языке С можно использовать различные типы данных: простые (элементарные), составные (сложные), пользовательские типы данных.

Ниже представлены основные элементарные типы данных.

 

тип Допустимые значения Длина в байтах
bool false (0) и true (1)
signed char -127...128
unsigned char 0...255
signed int -32768...32767
unsigned int 0...65535
signed short int -32768...32767
unsigned short int 0...65535
signed long int -2 147 483 648... 2 147 483 647
unsigned long int 0...4 294 967 295
float 3.4Е-38...3.4Е+38
double 1.7Е-308...1.7Е+308
long double 3.4Е-4932...3.4Е+4932

 

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

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

 

Вызов функции, например, sizeof(long double)вернет целое значение равное числу байт требуемых для размещения в памяти данных типа long double.

 

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

 

Объявление и определение переменных в программе

 

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

 

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

 

Определение – это указание компилятору о необходимости выделить область памяти для размещения данных переменной.

В языке С объявление переменной вида:

 

ТИП имя_переменной;

 

Автоматически является и определением переменной.

 

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

 

Пример:

 

int int_var=7;

 

Этим оператором объявляется и определяется переменная int_var, которой так же устанавливается начальное значение 7.

 

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

 

int int_var;

int_var=7;

 

Константы

 

Константами называются данные, которые не могут быть изменены в программе.

 

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

Синтаксис (правила) объявления констант следующий:

 

const ТИП имя_константы=значение;

 

Пример:

 

const int const_int_var=7;

 

После такого обявления const_int_var – это константа, имеющая значение 7, которое в программе изменить не удасться.

Заметим, что инициализировать константу можно только во время ее объявления.

 

Операторы, операции и выражения

 

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

Оператор определяет операцию (действие преобразования данных). С помощью операторов строятся выражения, определяющие способ преобразования данных.

В языке С насчитывается более 40 операторов. Рассмотрим некоторые из них в их первоначальном смысле.

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

 

Арифметические операции используются для выполнения преобразований над числовыми данными. Они приведены в табл.1.

Таблица 1

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

Оператор Описание Применение
+ Суммирует два операнда A+B
- Вычитание из первого операнда второго A-B
* Умножение операндов A*B
/ Делит первый операнд на второй A/B
% Определяет остаток от деления первого операнда на второй A%B

 

Замечание:

1. все арифметические операторы являются бинарными.

2. *, /, % имеют более высокий приоритет чем + и -.

3. При одинаковом приоритете операторы выполняются в порядке слева направо.

4. Порядок выполнения операторов можно изменить используя скоюки.

 

Оператор присваивания

 

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

 

Пример:

 

int_var=7;

 

При выполнении операции присваивания левому операнду присваивается значение, определяемое операндом стоящим справа, т.е. оператор выполняется справа на лево.

 

Замечание:

 

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

 

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

Операторы отношения

 

Назначение этих операторов выполнять сравнение операндов. Результатом выполнения этих операндов является значение типа bool.

Операторы отношения приведены в табл.2.

Таблица 2

Операторы отношения

Оператор Описание Применение
== Формирует результат отношения равенства A==B
! = Формирует результат отношения не равенства A! =B
< Формирует результат отношения меньше A< B
> Формирует результат отношения больше A> B
< = Формирует результат отношения менше или равно A< =B
> = Формирует результат отношения більше или равно A> =B

 

Логические операторы

 

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

Логические операторы приведены в табл.3.

Таблица 3

Операторы отношения

Оператор Описание Применение
& & Операция логическое И A& & B
|| Операция логическое ИЛИ A||B
! Операция логического отрицания ! A

 

Тип результата в логических операциях – bool.

 

Оператор sizeof()

 

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

В качестве oper может использоваться переменная, идентификатор типа или выражение.

 

2.6.7. Операторы ++ и - -

 

Это унарные операторы, т.е. они выполняются на д одним операндом.

++ - опеределяет операцию инкремента, например, х++; равносилен x=x+1;

- - - определяет операцию декремента, например, х - -; равносилен x=x-1;

Различают следующие варианты этих операторов:

 

Префиксные:

 

++oper

- - oper

Постфтксные:

oper++

oper - -

 

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

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

 

Например:

 

Фрагмент кода:

int a=1, b=1;

int c;

 

c=++a+b--;

 

cout< < " a=" < < a< < endl;

cout< < " b=" < < b< < endl;

cout< < " c=" < < c< < endl;

 

Приведет к выводу на консоль:

a=2

b=0

c=3

 

т.е. операции выполняются в следующей последовательности:

++a - a=2

a+b - c=3

b-- - b=0

 

Операторы проверки условия

 

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

 

Оператор if

 

Организует условное выполнение оператора. Он имеет следующий синтаксис:

 

if(условие) оператор;

 

где:

 

условие – это логическое выражение;

оператор – это оператор, который будет выполняться, если результат выражения условия – true. Если результат условия false, то управление передается оператору, который записан после оператора if.

 

2.7.2. Оператор if…else

 

if(условие)

оператор1;

else

оператор2;

 

где:

 

условие – это логическое выражение;

оператор1 – это оператор, который будет выполняться, если результат выражения условия – true;

Оператор2 – это оператор, который будет выполняться, если результат выражения условия – false.

 

Оператор switch

Реализует много альтернативный if. Имеет следующий синтаксис:

 

switch(выражение)

{

case конст_выражение1: оператор1;

break;

case конст_выражение2: оператор2;

break;

 

case конст_выражениеN: операторN;

break;

 

default: оператор_default;

};

 

Логика, которую реализует этот оператор следующая.

Сначала вычисляется значение выражения в скобках. Это значение сравнивается с константными выражениями, указанными после case. Если значение выражения совпало с конст_выражениеK, то выполняется операторК, после чего, если стоит оператор break управление передается на оператор, который записан после оператора switch.

 

2.7.4. Оператор перехода на метку

 

В программе можно явно указать переход на желаемый исполняемый оператор. Для этого предусмотрены такие операторы как метка и оператор перехода на метку.

 

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

metka: k=k+1;

 

 

Для передачи управления на метку используется оператор goto, например:

 

goto metka;

 

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

 

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

В языке С используются следующие операторы циклов.

 

2.8.1. Цикл while

 

Синтаксиc:

 

while(выражение)

оператор;

 

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

 

1) вычисляется выражение

2) если результат выражения true, то выполняется оператор,

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

3) выполняется переход к 1)

 

2.8.2 Цикл do while

 

Синтаксиc:

 

do

оператор;

while(выражение)

 

Оператор do while выполняется следующим образом:

 

1) выполняется оператор

2) вычисляется выражение

3) если результат выражения true, то выполняется выполняется переход к 1),

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

 

2.8.3. Цикл for

 

Синтаксис:

 

for(выражение_1; выражение_2; выражение_3)

оператор;

 

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

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

Выражение_1 может быть опущено, но разделитель -; должен присутствовать.

2) выполняется проверка условия выполнения цикла, для чего вычисляется выражение_2. Если его значение true, то выполняется оператор, пределяющий тело цикла, иначе управление передается на оператор следующий за оператором цикла.

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

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

 

Выражение_3 также может быть опущено.

Если в операторе цикла опущены сразу все три выражения, то пулучаем так называемый вечны цикл:

 

for(; ; )

оператор;

 

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

 

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

Но для циклов специально были предложены операторы continue и break.

 

Оператор continue возвращает управление к первому оператору тела цикла.

 

Оператор break передает управление на оператор за оператором цикла, т.е. приводит к завершению цикла.

 

Составной оператор

 

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

Для этого служит так называемый составной оператор или блок операторов. Он может объединять в себе целую группу операторов и использоваться там где по синтаксису можно использовать только один оператор. Блок операторов обозначается фигурными скобками. Например:

if(a< 0)

{ // начало составного оператора

c=a+b;

d+=c;

} // конец составного оператора

 

Оператор запятая

 

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

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

 

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

a[i]=b[j];

 

Сокращенный оператор

 

Синтаксис:

 

условие? выражение_1: выражение_2;

 

Оператор предполагает следующий порядок выполнения:

 

1) вычисляется значение выражения условие

2) если результат – true, то выполняется выражение_1, вычисленное значение которого является результатом оператора в целом.

3) Если результат – false, то выполняется выражение_2, вычисленное значение которого является результатом оператора в целом.

 

Эта форма условного оператора обычно используется, если невозможно по синтаксису применить обычный if. Например: i=a< b? 0: 1;

 

Тип указателя

Во время выполнения программы обрабатываемые данные размещаются в оперативной памяти.

Память представляет собой последовательность байт с номерами от 0 до не которого Аmax.

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

 

Переменная – это область памяти, где располагается данное. Для идентификации этой области памяти, а значит и данного используется идентификатор переменной (имя переменной). Таким образом, с идентификатором переменной фактически связан адрес этой области в памяти, а её длина определяется типом переменной.

 

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

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

Для этого в языке существует специальный тип данных – тип указателя.

 

Указателем – в языке С называют переменную, в которой хранится адрес размещения объекта в памяти.

 

Правила работы с указателями:

 

1) Объявление указателей

Для возможности использования переменной-указателя она должна быть объявлена:

 

ТИП *имя_указателя;

 

ТИП – определяет тип данных, адреса размещения которых будет хранить переменная имя_указателя.

 

Символ * объявляет следующую за ним переменную как указатель.

Пример:

 

int *pint; // переменная указатель на данные типа int

 

2) Инициализация указателя

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

Инициализацию можно выполнить следующими способами:

 

(1) присвоением адреса существующего объекта

 

Пример:

 

int var; // переменная целого типа

int *pint; // переменная указатель

 

pint=& var; // взятие адреса переменной и присвоение указателю

 

& - это оператор взятия адреса переменной.

Замечание:

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

 

(2) присвоением инициализированного указателя

 

int var; // переменная целого типа

int *pint1; // переменная указатель

 

pint1=& var; // взятие адреса переменной и присвоение указателю

 

 

int *pint2=pint1; // присвоение инициализированного указателя

(3) присвоения идентификатора массива

 

int mas[10]; // маccив из 10 элементов типа int

 

int *pint=mas; // имя массива в языке С трактуется как адрес 0 го

// элемента массива в памяти

 

 

(4) присвоением NULL указателя

 

NULL (константа NULL-указатель) определяет значение адреса памяти 0. Если указатель не инициализирован, то он содержит неопределенное значение, обращение к памяти по котрому может привести к ошибке.

Такой указатель рекомендуется инициализировать значением NULL.

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

 

3) Доступ (обращение) к переменной по указателю

 

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

 

Пример:

 

int var; // переменная целого типа

int *pint1; // переменная указатель

 

pint1=& var; // взятие адреса переменной и присвоение указателю

 

 

*pint1=10; // записать по адресу, хранимому в указателе pint1 значение 10

// т.е. записать по сути в переменную var значение 10

 

4) работа с динамической памятью

 

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

 

Выделения памяти может быть выделено с использованием функции malloc() или оператора new, а овсвобождение с помощью функции free() или оператора delete.

 

1) выделение памяти с помощью функции malloc().

 

Функция имеет прототип (в alloc.h или stdlib.h):

 

void* malloc(size_t size);

 

тип size_t объявляется как typedef unsigned int size_t;

 

malloc() возвращает void* указатель на выделенную динамическую память размером size байт.

Указатель должен быть приведен к необходимому типу указателя.

 

2) выделение памяти с помощью оператора new для одной переменной.

 

Оператор вида

 

указатель=new ТИП;

 

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

 

3) выделение памяти с помощью оператора new для массива переменных.

 

Оператор вида

 

указатель=new ТИП [число_элементов];

 

выделяет динамическую память для размещения массива типа ТИП раз мера число_элементов.

 

4) Освобождение памяти с помощью функции free().

 

Функция имеет прототип (в alloc.h или stdlib.h):

 

void* free(void* ptr);

 

освободить память по указателю ptr.

5) Освободить память оператором delete от скалярной переменной.

 

Оператор вида

 

delete указатель;

 

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

 

6) Освободить память оператором delete от массива переменных

 

Оператор вида

 

delete [] указатель;

 

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

 

Пример:

 

#include " stdafx.h"

#include < iostream>

#include < stdlib.h>

 

using namespace std;

 

 

int _tmain(int argc, _TCHAR* argv[])

{

int *mas1, *mas2;

 

// выделить память под 10 элементов целого типа

mas1=(int*)malloc(10*sizeof(int));

mas2=new int [10];

 

for(int i=0; i< 10; i++)

mas1[i]=i+1;

 

cout< < " mas1[]: ";

for(int i=0; i< 10; i++)

cout< < mas1[i]< < " ";

 

// копируем єлементы из mas1 в mas2 в обратном порядке

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

mas2[i]=mas1[j];

 

cout< < endl< < " mas2[]: ";

for(int i=0; i< 10; i++)

cout< < mas2[i]< < " ";

 

// освободить память

free(mas1);

delete [] mas2;

 

return 0;

}

 

7) Рекомендации при работе с динамической памятью

 

(1) переменная указатель всегда должна быть явно инициализирована либо адресом существующей переменной либо NULL-указателем.

(2) Освобождение памяти и обращение к памяти для не инициализированного указателя так же как и к NULL-указателю приводит к сбою во время работы.

(3) Перед выделением и освобождением памяти анализируйте текущее состояние переменной указателя, для которой вы собираетесь выполнять действие.

(4) Операция вида x=y, если x и y – это переменные указатели допустима, но если x хранит указатель на неосвобожденную память, то она будет потеряна.

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

 

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

Пусть:

 

pe - выражение типа „указатель на Т”;

pv – переменная типа „указатель на Т”;

ie – выражение типа «целое»,

тогда:

 

val(pe+ie)ó val(pe)+val(ie)*sizeof(T)

val(pv+ie)ó pv+val(ie)*sizeof(T)

val(pe-ie)ó val(pe)-val(ie)*sizeof(T)

val(pv-ie)ó pv-val(ie)*sizeof(T)

val(++pv)ó val(pv++)ó pv+sizeof(T)

val(--pv)ó val(pv--)ó pv-sizeof(T)

pv+=ieó pv+val(ie)*sizeof(T)

pv-=ieó pv-val(ie)*sizeof(T)

 

где val() обозначает вычисление значения операции.

 

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

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

Если к указателю на определенный тип Т прибавляется или отнимается некоторая целая константа, то значение указателя изменяется на величину этой константы, умноженную на sizeof(T).

При вычитании указателей:

 

Val(pe1-pe2) ó (val(pe1) – val(pe2))/sizeof(T)

 

И по смыслу означает целое число объектов типа Т, которые можно разместить в памяти начиная с адреса val(pe1) и до адреса val(pe2)

 

Над парой указателей можно выполнять операции отношения:

 

- pe1 Op pe2, где Op є {==,! =, <, >, < =, > =}

- операцию доступа по индексу pe[ie] ó *(pe+ie) и имеет результат типа Т.

При этом если pe – это сложное выражение не обходимо писать (pe)[ie], поскольку операция [] имеет более вісокий приоритет.

 

Тип ссылки

(не давать)

Функции

 

Программа на языке С состоит из одной или нескольких фунций.

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

 

Составные типы данных

 

Для решения сложных задач, с которыми обачно сталкивается человек

рассмотренных выше элементарных типов недостаточно. Они очень просты (элементарны) по сравнению с объектами реального мира.

Поэтому эти типы используются как базовые типы данных, на основе которых могут быть организованы более сложные, которые так и называют –

сложные типы данных.

К сложным типам данных относятся:

- массивы;

- строки;

- структуры;

- классы.

Язык С++ позволяет использовать эти типы для организации своих пользовательских типов.

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

 

Одномерные массивы

 

Массив — это набор данных одного типа, которые в памяти размещаются последовательно.

Как работать с массивами, что можно что нельзя:

1. Определение количества элементов массива.

 

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

Пример:

#include " stdafx.h"

#include < iostream>

using namespace std;

 

 

int _tmain(int argc, _TCHAR* argv[])

{

float float_array[]={ 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };

 

// определение кол-ва элементов массива

int num=sizeof(float_array)/sizeof(float);

 

// sizeof(float_array) возвращает кол-во байт памяти, связанное с массивом

cout< < " sizeof(float_array)=" < < sizeof(float_array)< < endl;

 

// sizeof(float) возвращает кол-во байт памяти, используемое для

// представления в памяти данного типа float

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

 

cout< < " num=" < < num< < endl;

 

// используем значение num для распечатки элементов массива

for(int i=0; i< num; i++)

cout< < " float_array[" < < i< < " ]=" < < float_array[i]< < endl;

 

return 0;

}

Обычные массивы для работы предоставляют ограниченный набор средств:

- нельзя присвоить одну переменную-массив другой;

- недопустимо сравнивать массивы;

- нельзя складывать, умножать и т. д.

Единственное, что можно делать с массивами — передавать их функции как аргумент.

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

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

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

Если float float_array[10]; - это массив, то float_array[i] – это склаярная величина, т.е. элементарное данное, с которой можно все делать, что допустимо в данном случае на переменной типа float.

Т.е. допустимы, например, такие действия как:

float_array[i]=20.7;

float_array[i+2]= float_array[i]*10;

С++ интерпретирует квадратные скобки [] - как операцию, а не

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

Она называется операцией доступа по индексу.

Слева от неё стоит операнд – имя массива, а в скобках операнд – индекс массива, к которому осуществляется доступ.

В качестве индекса может применяться любое числовое выражение целого типа. Программист не может произвольно выбирать диапазон значений индексов массивов. В С++ индекс массива может лежать от значения 0 до значение nun-1, если num – это количество элементов в массиве.

Но, необходимо помнить, что проверка индекса на допустимость в операции доступа по индексу не осуществляется ни на этапе компиляции, ни на этапе выполнения.

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

Если программа написана так, что индекс при обращении к массиву всегда имеет допустимоё значение, то проверка не нужна.

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

Пример:

#include " stdafx.h"

#include < iostream>

using namespace std;

 

 

int _tmain(int argc, _TCHAR* argv[])

{// как работать с массивами

 

float float_array[]={ 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };

 

float new_array[10];

 

// копируем массив float_array в new_array

 

for(int i=0; i< 10; i++) //ошибка-кол-во элементов в мас. float_array =5

new_array[i]=float_array[i];

 

// выводим новый массив

for(int i=0; i< 10; i++)

cout< < " new_array[" < < i< < " ]=" < < new_array[i]< < endl;

 

return 0;

}

Вот что выведет программа.

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

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

В этом случае правильным решением будет, например такое:

#include " stdafx.h"

#include < iostream>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{// как работать с массивами

 

float float_array[]={ 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };

float new_array[10];

 

// копируем массив float_array в new_array

for(int i=0; i< 10; i++)

if (i< sizeof(float_array)/sizeof(float))

new_array[i]=float_array[i];

else

new_array[i]=0;

// выводим новый массив

for(int i=0; i< 10; i++)

cout< < " new_array[" < < i< < " ]=" < < new_array[i]< < endl;

 

return 0;

}

 

 

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

 

Пример 1:

Работа с указателем: инициализация указателя адресом, обращение по указателю.

// pointers1.cpp

#include " stdafx.h"

#include < iostream>

 

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

int x=5;

 

// инициализация указателя адресом переменной x

int *y = & x;

 

// обращение к переменной по указателю *y

cout< < " Znachenie po ukazatelu: " < < *y< < endl;

 

cout< < " adress peremennoi: " < < y< < endl;

 

return 0;

}

Пример 2:

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

#include " stdafx.h"

#include < iostream>

 

using namespace std;

 

 

int _tmain(int argc, _TCHAR* argv[])

{

// указатель на переменную целого типа

int *y;

// выделение участка динамической памяти размером sizeof(int)

y = new int;

// присвоение значения переменной по указателю

*y=10;

 

cout< < " y= " < < y< < endl;

cout< < " *y= " < < *y< < endl;

 


Поделиться:



Последнее изменение этой страницы: 2017-03-14; Просмотров: 463; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.412 с.)
Главная | Случайная страница | Обратная связь