![](/user_photo/2706_HbeT2.jpg)
- •Отличия между доступом по имени массива и по указателю
- •Int const *(cptr_a);
- •Int main()
- •Int* V[10]; // массив указателей
- •Int (*p)[10]; // указатель массива
- •Int I: // целая переменная
- •Int * pi: // указатель на целую переменную
- •Void* ptr;
- •Int main(){
- •Классы памяти и динамическое выделение памяти
- •Динамические объекты в с
- •Рекомендации по использованию указателей и динамического распределения памяти
- •Void main()
- •Int n; // Порядок матрицы
- •Vveditre poriadok matrizi: 5
- •Int *pmin, I; // Рабочий указатель, содержащий результат
- •Void main() {
Динамические объекты в с
Указатели используются при создании и обработке динамических объектов. Заранее определяемые объекты создаются с помощью определений. Динамические объекты, в отличие от заранее определяемых, создаются динамически и явно в процессе выполнения программы. Для создания динамических объектов служат функции malloc и calloc. В отличие от заранее определенных объектов, число динамических объектов не фиксировано тем, что записано в тексте программы, - по желанию динамические объекты могут создаваться и уничтожаться в процессе ее выполнения. Динамические объекты, в отличие от заранее определенных, не имеют имен, и ссылка на них выполняется с помощью указателей.
Значение 0 может быть присвоено указателям любого типа. Это значение показывает, что данный указатель не содержит ссылки на какой-либо объект. Попытка использовать это значение для обращения к объекту может привести к ошибке, но только в операционных системах с защитой памяти. По соглашению, для обозначения константы с нулевым значением используется идентификатор NULL, описание которого находится в библиотеке stddef.h и является системозависимым.
Создание динамических объектов
По стандарту аргументы функций malloc, calloc имеют тип возвращаемого объекта void*.
char s = (char*)malloc(size);
unsigned size; /* объем памяти, который необходимо выделить */
char *s = (char *)calloc(nelem,elsize);
unsigned nelem; /* число элементов, для которых нужно выделить память */
unsigned elsize; /* объем памяти, который необходимо выделить для каждого элемента */
/* либо просто заменив char* на void*
void* calloc(nelem, elsize);
unsigned nelem;
unsigned elsize;
*/
Обе функции возвращают знаковый указатель, указывающий на выделенную память. Для определения необходимого объема памяти можно использовать оператор sizeof:
sizeof (выражение)
Объем памяти, необходимый для хранения выражения:
sizeof(T)
Объем памяти, необходимый для хранения значений типа T.
Функции malloc и calloc возвращают указатель на созданный динамический объект. Фактически функции возвращают знаковые указатели, которые могут быть явно преобразованы к подходящему типу указателя. Значения, возвращенные функциями распределения памяти, используются для ссылок на динамические объекты. Например, с помощью оператора
pi = (int *) malloc(sizeof(int));
выделяется память для одного целого значения. Адрес этой области памяти присваивается переменной pi после его преобразования из типа char * (указатель на знак), с которым он возвращается функцией malloc, к типу int * (указатель на целое), т.е. типу переменной pi.
Доступ к динамическим объектам
Присваивание значения объекту, ссылка на который задана указателем pi, выполняется с помощью имени указателя *pi, например:
*pi = 55;
Одно и то же значение может быть присвоено более чем одной переменной-указателю. Таким образом, можно ссылаться на динамический объект с помощью более одного указателя. Про объект, к которому можно обращаться с использованием более чем одного указателя, говорят, что он имеет псевдоимена (alias). Например, в результате присваивания
qi = pi;
и qi, и pi указывают на один и тот же объект, т.е. они являются псевдоименами. Неуправляемое использование псевдоимен может нанести ущерб пониманию текста программы, так как возможность доступа к одному и тому же объекту и его модификация с помощью различных псевдоимен не всегда очевидны при анализе части программы.
Время жизни динамического объекта
Память, занимаемая динамическими объектами, если она необходима для других целей, должна быть освобождена явным указанием. В противном случае эта память может быть потеряна, т.е. станет невозможным ее повторное использование. Явное освобождение выполняется использованием функции free, которая имеет следующую спецификацию:
free(ptr)
char *ptr;
Необходимо предпринимать меры предосторожности для избежания ошибок, связанных со ссылками на объект, память для которого уже освобождена - проблема висящей.
Если реализация языка обеспечивает сборку мусора, то память, занимаемая объектами, к которым невозможен доступ, может быть автоматически подготовлена для повторного использования. Однако в языке Си, в отличие от языков Лисп и Снобол, такая возможность отсутствует.