Тема 4. Массивы и указатели. Работа с файлами.
Объявления массивов и указателей.
Массив представляет собой набор данных одного типа. Формат определения массива следующий:
тип_данных имя_массива[размер_массива];
Например, для представления данных о температуре можно воспользоваться следующим описанием:
int Temperatura[7];
Массив можно инициализировать во время определения:
int Temperatura[7]={ 20, 21, 17,16,27,22,19};
Если массив инициализируется, то его размер можно не указывать, например:
char Error[]=”Ошибка, файл не найден!”;
Многомерные массивы задаются указанием нескольких размеров, каждый из которых заключен в квадратные скобки:
double koordinate[8][2];
Такое описание определяет таблицу, содержащую два столбца и 8 строк.
При инициализации таких массивов можно не указывать только размер самого левого индекса:
int iarray[][3]={ {1,2,3},{9,11,4},{100,200,300}};
Многомерные массивы хранятся в памяти компьютера последовательно. Они группируются в порядке индексов, от правого к левому. В предыдущем примере элементы расположены следующим образом:
iarray[0][0],iarray[0][1],iarray[0][2],iarray[1][0],…,iarray[2][1],iarray[2][2].
Доступ к элементам массива.
Для доступа к элементу массива используется его имя, за которым следует номер элемента (индекс), заключенный в квадратные скобки, например:
for (int idx=0;idx<7;idx++)
s+=Temperatura[idx];
Нумерация элементов массива начинается с нуля. Т.е. индекс массива определяет смещение используемого элемента относительно начала массива.
|
|
Передача массивов функциям.
Массивы можно передавать функциям. Для этого необходимо в объявлении параметров функции после имени массива поставить пару квадратных скобок:
int function(double a[],int size);
Обратите внимание, что размерность массива в функцию автоматически не передается. Это можно сделать, используя второй параметр, как показано в предыдущем примере.
При вызове функции необходимо просто указать имя фактического параметра:
x=function(myarray,50);
Функция получает доступ ко всем элементам массива и может их изменять. Для запрета изменения можно добавить модификатор const:
int function(const double a[],int size);
Указатели.
Указатель является переменной, которая содержит адрес другой переменной или функции. Описание указателя определяет тип данных, на которые ссылается указатель, оно имеет вид:
тип_указываемых данных *имя_указателя;
Для доступа к объекту, на который ссылается указатель, используется имя указателя со звездочкой перед ним. Эта операция называется разыменовыванием указателя, она корректно выполняется только, если указатель был предварительно инициализирован:
int i=100;// определяется целая переменная
int *point_i;// определяется указатель на целую переменную
pointi=&i;// указатель инициализируется адресом переменной i
|
|
printf(“%i”,*pointi); // выводится значение переменной,
// определяемое указателем. Оно равно значению переменной i (100).
Обратите внимание на операцию определения адреса (&). Она является противоположной разыменованию.
Массивы и указатели тесно связаны друг с другом. Имя массива соответствует указателю на начало массива. Поэтом можно присваивать указателю адрес первого элемента массива, используя имя массива.
int array[10];
int *iptr=array;
С указателями можно выполнять целочисленные арифметические операции. При этом происходит вычисление адреса соответствующего элемента массива, а не адреса в памяти компьютера. Размер элемента определяется типом указателя. Для типа void соответственно никакие операции выполнять нельзя.
Указатель можно индексировать как массив. Следующие два оператора эквивалентны:
array[3]=10;
*(array+3)=10;
Указатели вместо массивов целесообразно использовать тогда, когда требуется последовательный доступ к элементам массива. Такая операция выполняется значительно быстрее, например:
int *ptemp=array;
for(int i=1;i<10;i++)
*(ptemp++)=0;
можно использовать для обнуления массива array.
Динамическое выделение и освобождение памяти.
|
|
При компиляции программы память компьютера разбивается на четыре области, содержащие код программы, глобальные данные, стек и динамически распределяемую память ( иногда ее называют heap - куча). Heap – это свободная память, с которой можно работать с помощью функций new и delete. Для new аргументом является выражение, определяющее размер выделяемого массива, а возвращаемое значение – это указатель на начало массива:
int *array=new int[10];
Если память не может быть выделена, то оператор new возвращает указатель NULL . После каждой операции выделения памяти обязательна проверка указателя на NULL:
if(array==NULL)
printf(“memory allocation error.”);
else
{
// действия при правильном выделении памяти
}
Выделенная динамически память автоматически не освобождается при выходе из блока или по завершению программы. Для ее освобождения обязательно необходимо выполнить команду delete[] имя_массива; (delete[] array; - для предыдущего случая).
Практическое задание.
Вариант1.
Вычислите скалярное произведение векторов и размерности n.
Размерность векторов и их координаты должны вводится с консоли.
Контрольные примеры:
|
|
Вариант 2.
Вычислите произведение матрицы на вектор.
Размерности вектора и матрицы A , координаты вектора и элементы матрицы должны вводится с консоли. Координаты вектора распечатайте на экране.
Контрольные примеры:
Вариант 3.
Вычислите сумму матриц. . Размерности матриц и их элементы введите с консоли. Элементы матрицы C выведите на экран.
Контрольные примеры:
Вариант 4.
Напишите процедуры умножения и сопряжения матриц и с их помощью вычислите
Размерности матриц и их элементы вводятся с консоли. Элементы матрицы C должны выводится на экран.
Контрольные примеры:
Тема 5. Ввод и вывод в языке С++.
В языке С имеется весьма развитая библиотека функций ввода-вывода. Однако в самом языке отсутствуют какие-либо предопределенные файловые структуры. Все данные обрабатываются как последовательность байт. Имеется три основных типа функций: потоковые, работающие с консолью и портами ввода-вывода и низкоуровневые.
Потоковые функции.
В потоковых функциях файлы данных рассматриваются как поток отдельных символов.
Когда программа открывает файл для ввода вывода при помощи потоковых функций, то открытый файл связывается с некоторой переменной типа FILE (определенной в stdio.h), содержащей базовую информацию об этом файле. После открытия потока с помощью функции fopen возвращается указатель на эту переменную. Этот указатель используется для ссылки к файлу при всех последующих операциях ввода-вывода и называется указателем потока.
Все потоковые функции обеспечивают буферизованный, форматированный или неформатированный ввод/вывод. Буферизация потока разгружает приложение. Однако следует иметь в виду, что при аварийном завершении программы содержимое буферов вывода может быть потеряно.
Аналогичным образом выглядят функции, работающие с консолью и портами. Они позволяют читать и писать на терминал или в порт ввода/вывода (например, в порт принтера). Функции портов ввода/вывода выполняют простое побайтное считывание или запись. Функции ввода/вывода на консоль обеспечивают несколько дополнительных возможностей, например можно определить момент, когда будет введен символ с консоли и т.п.
Для использования потоковых функций в программу должен быть включен заголовочный файл stdio.h. В нем содержатся описания прототипов функций ввода/вывода, а также - описания ряда констант. Константа EOF определяется как значение, возвращаемое при обнаружении конца файла, BUFSIZE - размер буферов потока, тип FILE определяет структуру, используемую для получения информации о потоке.
Поток открывается с помощью функций fopen(), fdopen() или freopen(). В момент открытия задаются режим файла и способ доступа. Эти функции возвращают указатель на переменную типа FILE, например
FILE *file1;
file1=fopen(“input.dat”,”r”);
открывает файл input.dat для чтения. Переменная file1 получает указатель на поток.
Возможные типы доступа:
“a” – запись в режиме добавления в конец файла,
”a+” –тоже, что и “a”, но возможно и чтение,
”r” – только для чтения,
”r+” – для чтения и записи,
”w” – открывается пустой файл для записи,
”w+” – открывается пустой файл для записи и чтения.
Когда начинается выполнение приложения, автоматически открывается следующие потоки: стандартное устройство ввода stdin, стандартное устройство вывода stdout, устройство сообщений об ошибках stderr, устройство печати stdprn и стандартное дополнительное устройство stdaux. Эти файловые указатели можно использовать во всех функциях ввода/вывода в качестве указателя на поток. Некоторые функции автоматически используют указатели на поток, например getchar() и putchar() используют stdin и stdout соответственно.
Для закрытия потоков используются функции fclose() и fcloseall(). Если программа не закрывает поток явно, то он закрывается автоматически по ее завершению.
Для перемещения по файлу можно использовать функции fseek(), ftell() и rewind().
Низкоуровневый ввод и вывод.
Функции низкоуровневого ввода-вывода не выполняю никакой буферизации и форматирования. Они непосредственно обращаются к средствам ввода/вывода операционной системы.
При открытии файла на этом уровне возвращается описатель файла (file handle), представляющий собой целое число, используемое затем для обращения к этому файлу при дальнейших операциях. Для открытия используется функция open(), для закрытия – функция close().
Функция read() читает данные в указанный массив, а write() – выводит данные из массива в файл, lseek() – используется для перемещения по файлу.
Низкоуровневые функции не требуют включения заголовочного файла stdio.h, вместо него используется файл io.h.
Низкоуровневая система ввода-вывода не вошла в стандарт ANSI C, поэтому ее не рекомендуют для дальнейшего использования.
Дата добавления: 2018-02-15; просмотров: 891; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!