- •Фрагмент, запрашивающий у пользователя 10 целых чисел,
- •Доступ к элементам многомерного массива в
- •Типичные ошибки программирования
- •скалярные производные типы, в том числе:
- •Признак переменной-указателя для компилятора -
- •Указатели при их описании могут, как и обычные
- •Оператор присваивания
- •Существуют ограничения и на использование
- •Сам указатель-переменная тоже имеет адрес.
- •во всех случаях использования указателя,
- •Для указателей-переменных разрешены следующие
- •Использование механизма указателей - один из
- •Использование указателей дает несколько более
- •Элементы массива - любой тип, в том числе и
- •Преимущества использования массивов - появляется
- •Структурирование обработки данных: Составной
- •Каждая инициализация auto или register переменных
- •Макросы – символическое имя некоторых операций,
- •Функции - программные блоки, которые могут
- •Определение переменной в дополнении к ее имени и
- •Перед использованием функцию надо определить, задав
- •Список параметров, заключаемый в скобки, в
- •имя_функции(список_фактических_параметров)
- •вызов. . . ф-и
- •Уже знаете, что существуют функции, не требующие для
- •Как правило (хотя формально не обязательно), кроме
- •Передача в функцию параметров
- •По адресу, когда в функцию передается не
- •void Unit(int*,int); /*Прототип функции Unit()*/
- •В примере - в функцию передаются данные – адрес и
- •По ссылке, когда в функцию также передается
- •Сравнение методов передачи в функцию параметра по адресу и по ссылке
- •Типичные ошибки программирования
- •Типичные ошибки программирования
- •Параметры со значениями по умолчанию
Фрагмент, запрашивающий у пользователя 10 целых чисел, |
|
и вычисляющий их сумму |
|
. . . |
|
int A[10]; // объявляем массив из 10 целых |
|
for(int i=0; i<10; i++)// организуем цикл по i от 0 до 9 |
|
{ |
// приглашение |
printf(“\n A[%d]=“, i); |
|
scanf(“%d”,&(A[i])); |
// вводим A[i] |
} |
|
int sum = 0;// объявляем переменную |
|
for(int i=0; i<10; i++) // организуем цикл |
|
sum = sum + A[i]; |
// в цикле суммируем элементы |
. . . |
|
использование итерационных циклов for. С их помощью организуется выполнение однотипных операций со всеми элементами массива, в частности, поэлементный ввод-вывод, поэлементные арифметические операции и др.
Массивы в программах C++ могут быть не только
линейными. Довольно частым является использование двух - (и более) -мерных структур. К примеру, прямоугольная матрица – типичная структура, представимая с помощью двумерного массива; а 3D- тензор может быть записан как соответствующий трехмерный массив.
«массиваG[0][0] |
5 |
21 |
0 |
12 |
G[0][3] |
|
тип |
G[1][0] |
8 |
-3 |
14 |
23 |
|
Здесь |
|
|||||
|
|
55 |
-1 |
0 |
78 |
|
44 4 0 9
G[4][0] |
33 |
0 |
-2 |
0 |
G[4][3] |
|
|
|
|
|
|
Доступ к элементам многомерного массива в
программе производится так же, как и в одномерном случае, то есть путем указания имени массива и набора индексов в квадратных скобках.
G[4][3] = 0.
При работе с многомерными массивами удобно испо- льзовать вложенные циклы for. С их помощью можно выполнить заданное действие с каждым из элемен-тов массива путем перебора всех значений индексов.
типизированные константы - для указания размеров массива. Так же, как и переменная, имеет уникальное имя и тип, однако ее значение не может быть изменено по ходу выполнения программы - можно использовать ее в объявлении массива.
должна быть объявлена с ключевым словом const, вслед за которым указывается ее тип (int, float, double, char, и т.д.), далее, через пробел, – ее имя и инициализирующее выражение
const тип имя = выражение;
|
Произведение 2х квадратных матриц |
|
|
|
const int N = 3;// используем константу N=3 |
|
|
. . . |
}; |
||
тип |
|
float A[N][N] = { {1, 1, 1}, |
|
float |
{2, 2, 2}, |
|
|
{3, 3, 3} }; // исходная матрица A |
|
||
int |
|
float B[N][N] = { {1, 2, 3}, |
|
|
{1, 2, 3}, |
|
|
|
|
{1, 2, 3} }; // исходная матрица B |
|
float C[N][N]; // матрица произведения С
for(int i=0; i<N; i++) // цикл по строкам С
{
for(int j=0; j<N; j++) // цикл по столбцам С
{
float s = 0.0; // вспомогательная переменная
for(int k=0; k<N; k++) |
// цикл суммирования по k |
s += A[i][k]*B[k][j]; |
// добавляем к s новое слаг-ое |
C[i][j] = s; // записываем s в C[i][j]
}
} . . .
Типичные ошибки программирования
1.Выход за пределы массива в цикле for. Возникает при обращении к несуществующему элементу (с отрицательным индексом или индексом, большим настоящего размера массива минус 1). Не определяется компилятором. Может иметь разнообразные последствия – от некорректных результатов работы программы до зависания ПК.
2.Для размера статического массива вместо константного выражения используется имя переменной. Сопровождается сообщением “Error: Constant expression required”.
3.Неправильное объявление двумерного массива m[x][y] как m[x,y]. Аналогичная ошибка – ссылка на элемент m[x,y]. Вызывают сообщения: “Error: Array bounds missing ]” и “Error: Illegal use of …”. 4.Количество начальных значений в списке инициализации массива превышает его размер. Ошибка распознается на этапе компиляции и сопровождается сообщением “Error: Too many initializers”. 5.Попытка изменить значение типизированной константы после ее объявления. Приводит к сообщению “Error: Cannot modify a const object ”.
скалярные производные типы, в том числе:
Вязыке С (С++) - 2 способа доступа к переменной: 1)обращение к переменной по имени; 2)использование механизма указателей. Указатель-переменная (или просто указатель) – это переменная, предназначенная для хранения адреса в памяти. Указатель-константа – это значение адреса оперативной памяти.
Вязыке С (С++) определены 2 специальные операции для доступа к переменным через указатели:
1) & (взятие адреса) - результатом операции & явля-ется адрес объекта, к которому операция приме-няется (&varl дает адрес, по которому varl хранится в памяти - точнее, адрес первого байта varl).
2) * (разыменование) – операция обращения к содер- жимому памяти по адресу, хранимому в перемен-ной-
Признак переменной-указателя для компилятора -
наличие в описании переменной двух компонентов:
1)типа объекта данных, для доступа к которому используется указатель (или, как часто говорят, на который ссылается указатель);
2)символа * перед именем переменной.
В совокупности тип и * воспринимаются компилятором как особый тип данных – "указатель на что-либо".
int var1, *ptr; переменная varl типа int и указатель-переменная ptr типа int *
Переменная varl будет занимать 2 (или …) байта памяти. Указатель ptr имеет тип int *, т. е. тип "указатель на целое". Место, выделяемое под такой тип компилятором, зависит от модели памяти. Указатели в х86– near (ближний)– быстрый доступ, но ограничен областью указывания в 64 кБ памяти, far (дальний) – до 1 МБ, huge (большой) – дальше 1 МБ.
Указатели при их описании могут, как и обычные
переменные, получать начальное значение.
int var1, *ptr1 = (int *) 200, *ptr2 = &var1;
Здесь описаны две переменные-указателя ptr1 и ptr2; ptr1 получает начальное значение 200, а ptr2 в качестве начального значения - адрес, по которому в памяти хранится varl.
При инициализации указателя ptr1 константой выполняется явное приведение к типу "указатель на целое". Так избавитесь от предупреждения о немобильности инициализации.
Операцию * можно заменить фразой "взять содержимое по адресу, равному значению указателя".
Оператор присваивания
*ptr1=*ptr2+4;
можно интерпретировать так: взять содержимое памяти по адресу, равному значению указателя ptr2, прибавить к этому содержимому 4, а результат поместить по адресу, равному значению указателя ptr1.
Число байт, извлекаемых из памяти и участвующих в операции, определяется компилятором исходя из типа, на который указатель "указывает".
В то же время будет ошибкой запись типа *234=var1;
так как в левой части оператора присваивания записывается адрес константы. Но константа в С(С+ +) не имеет адреса в памяти.
Существуют ограничения и на использование
операции взятия адреса &:
1)нельзя определить адрес константы, например, некорректным является выражение
var1=&0xff00;
2)нельзя определить адрес значения, получаемого при выполнении арифметического выражения, включающего знаки +, -, /, * и т. п. Например, некорректным является выражение
int var1, *ptr; pt=&( var1 *3);
3)нельзя определить адрес переменной, описанной как register. Например, будет ошибкой попытка определить адрес varl:
unsigned register var1; unsigned int * ptr; ptr=&var1;