АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Многомерные символьные массивы

Читайте также:
  1. Динамические массивы
  2. Динамические массивы
  3. Массивы
  4. Массивы
  5. Открытые массивы
  6. Указатели и массивы
  7. Указатели и массивы

Общая форма записи многомерного массива:

тип имя_массива[размер1] [размер2]... [размерN];

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

При обращении к многомерным массивам компьютер много времени затрачивает на вычисление адреса, так как при этом приходится учитывать значение каждого индекса [6.2]. Поэтому доступ к элементам многомерного массива происходит значительно медленнее, чем к элементам одномерного. В связи с этим использование многомерных массивов встречается значительно реже, чем одномерных или двухмерных массивов.

Для многомерных массивов общий размер многомерного массива в байтах вычисляется по формуле:

всего байт = размер1 * размер2*... *размерN * размер типа в байтах

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

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

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

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

Указатели используются для динамического выделения памяти компьютера для хранения данных [9.1]. Динамическое распределение означает, что программа выделяет память для данных во время выполнения.

Память, выделяемая в С функциями динамического распределения данных, находится в так называемой динамически распределяемой области памяти (heap – куча) [9.1]. Динамически распределяемая область памяти – это свободная область памяти, не используемая программой, операционной системой или другими программами. Размер этой области памяти заранее неизвестен, но, как правило, в ней достаточно памяти для размещения данных программы. Хотя размер динамически распределяемой области памяти очень большой, все же она конечна и может быть исчерпана.

Основу системы динамического распределения памяти в С составляют библиотечные функции calloc(), malloc(), realloc() и free() [9.1].

Рассмотрим прототипы этих функций.

1. Функция calloc()

#include <stdlib.h>void *calloc(size_t num, size_t size);

Функция calloc() выделяет память, размер которой равен значению выражения num * size, т.е. память, достаточную для размещения массива, содержащего num объектов размером size [9.1]. Выделенная область памяти обнуляется. Функция calloc() возвращает указатель на первый байт выделенной области памяти для массива num объектов, каждый из которых имеет размер size или NULL, если запрос на память выполнить нельзя [9.2]. Если для удовлетворения запроса нет достаточного объема памяти, возвращается нулевой указатель. Перед попыткой использовать распределенную память важно проверить, что возвращаемое значение не равно нулю. Тип void может быть переопределен для требуемого типа, т.е. для char, int, float, double.

Пример фрагмента программного кода динамического распределения памяти для массивов заданного размера (например, вводится с клавиатуры):

double *ptr;ptr = (double *) (calloc(10, sizeof(double)));if (!ptr) // условие логического отрицания{printf("Out of memory\n"); exit(1);}

В приведенном примере число 10 – это размер одномерного массива с вещественными данными (типа double). В случае выделения памяти для двухмерного массива размера N*M строчка с функцией calloc() перепишется так:

ptr = (double *) (calloc(N*M, sizeof(double)));

При этом двухмерный массив рассматривается как аналог одномерного массива размера N*M.

Использование явного приведения типов (double) сделано для того, чтобы обеспечить переносимость программы, в первую очередь для обеспечения совместимости с языком программирования С++.

2. Функция malloc()

#include <stdlib.h>void *malloc(size_t size);

Функция malloc() возвращает указатель на первый байт области памяти размера size, которая была выделена из динамически распределяемой области памяти [9.3]. Если для удовлетворения запроса в динамически распределяемой области памяти нет достаточного объема памяти, возвращается нулевой указатель NULL. При этом следует иметь в виду, что попытка использовать нулевой указатель обычно приводит к полному отказу системы. Выделенная область памяти не инициализируется [9.2].

Приведем фрагмент программного кода динамического распределения памяти для массивов заданного размера:

double *ptr;ptr = (double *) (malloc(10*sizeof(double)));if (!ptr) // условие логического отрицания{ // выход за пределы памятиprintf("Out of memory. Press any key: "); _getch();exit(1);}

3. Функция realloc()

#include <stdlib.h>void *realloc(void *ptr, size_t size);

В стандарте С89 функция realloc() изменяет размер блока ранее выделенной памяти, адресуемой указателем *ptr в соответствии с заданным размером size [9.1]. Значение параметра size может быть больше или меньше, чем перераспределяемая область. Функция realloc() возвращает указатель на блок памяти, поскольку не исключена необходимость перемещения этого блока. В этом случае содержимое старого блока (до size байтов) копируется в новый блок. Если новый размер памяти больше старого, дополнительное пространство не инициализируется [9.2]. Если запрос невыполним, то функция распределения памяти realloc() возвращает нулевой указатель NULL. Функция realloc() позволяет перераспределить ранее выделенную память. При этом новый размер массива может быть как меньше предыду щего, так и больше его. Если система выделит память в новом месте, то все предыдущие значения, к которым программа обращалась по указателю *ptr, будут переписаны на новое место автоматически.

4. Функция free()

#include <stdlib.h>void free(void *ptr);

Функция free() возвращает в динамически распределяемую область памяти блок памяти, адресуемый указателем *ptr, после чего эта память становится доступной для выделения в будущем [9.1].

Вызов функции free() должен вызываться только с указателем, который был ранее получен в результате вызова одной из функций динамического распределения памяти. Использование недопустимого указателя при вызове, скорее всего, приведет к разрушению механизма управления памятью и, возможно, вызовет крах системы [9.1].

Файл – это именованный объект, хранящий данные (программа или любая другая информация) на каком-либо носителе (дискета, винчестер, CD) [12.1].

В языке С файлом может быть все что угодно, начиная с дискового файла и заканчивая терминалом или принтером [12.2]. Поток связывают с определенным файлом, выполняя операцию открытия. Как только файл открыт, можно проводить обмен информацией между ним и программой.

Не у всех файлов одинаковые возможности. Например, к дисковому файлу прямой доступ возможен, в то время как к некоторым принтерам – нет. В языке С все потоки одинаковы, а файлы – нет [12.2].

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

Файл отсоединяется от определенного потока (т.е. разрывается связь между файлом и потоком) с помощью операции закрытия. При закрытии файла, открытого с целью вывода, содержимое (если оно есть) связанного с ним потока записывается на внешнее устройство. Этот процесс, который обычно называют дозаписью потока, гарантирует, что никакая информация случайно не останется в буфере диска. Если программа завершает работу нормально, т.е. либо функция main() возвращает управление операционной системе, либо вызывается функция exit(), то все файлы закрываются автоматически. В случае аварийного завершения программы, например, в случае краха или завершения путем вызова функции abort(), файлы не закрываются [12.2].

Файловая системы языка С предназначена для работы с самыми разнообразными устройствами, в том числе терминалами, дисками и накопителями на магнитной ленте. Даже если какое-то устройство сильно отличается от других, буферизованная файловая система все равно представит его в виде логического устройства, которое называется потоком. Потоки бывают двух видов: текстовые и двоичные [12.2].

Текстовый поток – это последовательность символов. В стандарте С считается, что текстовый поток организован в виде строк, каждая из которых заканчивается символом новой строки. Однако в конце последней строки этот символ не является обязательным. В текстовом потоке по требованию базовой среды могут происходить определенные преобразования символов. Например, символ новой строки может быть заменен парой символов – возврата каретки (например, \r) и перевода строки (например, \n), т.е. \r\n.

Двоичные потоки – это последовательность байтов, которая взаимно однозначно соответствует байтам на внешнем устройстве, причем никакого преобразования символов не происходит [12.2]. Кроме того, количество тех байтов, которые пишутся (читаются), и тех, которые хранятся на внешнем устройстве, одинаково. Однако в конце двоичного потока может добавляться определяемое приложением количество нулевых байтов. Такие нулевые байты, например, могут использоваться для заполнения свободного места в блоке памяти незначащей информацией, чтобы она в точности заполнила сектор на диске.

Таблица 12.1.
Функции файловой системы языка С
№ п/п Имя функции Что делает
1. fopen() Открывает файл
2. fclose() Закрывает файл
3. putc() Записывает символ в файл
4. fputc() То же, что и putc()
5. getc() Читает символ из файла
6. fgetc() То же, что и getc()
7. fgets() Читает строку из файла
8. fputs() Записывает строку в файл
9. fseek() Устанавливает указатель текущей позиции на определенный байт файла
10. ftell() Возвращает текущее значение указателя текущей позиции в файле
11. fprintf() Для файла то же, что printf() для консоли
12. fscanf() Для файла то же, что scanf() для консоли
13. feof() Возвращает значение true (истина), если достигнут конец файла
14. ferror() Возвращает значение true (истина), если произошла ошибка
15. rewind() Устанавливает указатель текущей позиции в начало файла
16. remove() Стирает файл
17. fflush() Дозапись потока в файл

Структура – это совокупность нескольких переменных, часто различных типов [13.1]. В структурах совокупность переменных объединяют под одним именем. Переменные, из которых состоит структура, называются ее членами. Члены структуры еще называются элементами или полями [13.2].

С помощью структур удобно размещать в смежных полях связанные между собой элементы информации. В структуре могут быть собраны различные объекты – переменные, массивы, указатели, другие структуры и т.д., которые для удобства работы с ними сгруппированы под одним именем. Если в массиве собраны переменные одного типа (например, float), то в структуре могут быть переменные различных типов. Объявление структуры создает шаблон, который можно использовать для создания ее объектов (то есть экземпляров этой структуры) [13.2]. При объявлении структуры определяется агрегатный тип данных, но не переменная

Определение структуры состоит из двух шагов:

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

2. определение переменных типа объявленного шаблона [13.3].

Имена шаблонов должны быть уникальными в пределах их области определения, для того чтобы компилятор мог различать типы шаблонов. Задание шаблона осуществляется с помощью ключевого слова struct, за которым следует имя шаблона структуры и списка элементов, заключенных в фигурные скобки [13.3]. Имена элементов в одном шаблоне также должны быть уникальными. Задание только шаблона не влечет резервирования памяти компилятором. Шаблон предоставляет компилятору необходимую информацию об элементах структурной переменной для резервирования места в оперативной памяти и организации доступа к ней при определении структурной переменной и использовании ее отдельных элементов [13.3].

 


1 | 2 | 3 | 4 |

Поиск по сайту:



Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.005 сек.)