Арифметика указателей и массивы

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

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

int mas[3] = {1, 2, 3};

int* pVal;

pVal = mas; // тождественно pVal = &mas[0] printf("%d ", *pVal);

Для указателей определены арифметические операции. Таким образом, к указателям можно добавлять или отнимать целые значения. Так операция «++», примененная к указателю, изменяет адрес, хранящийся в указателе на число байт, соответствующее размеру одной переменной типа указателя. Иначе говоря, если у нас имеется указатель на тип int, занимающий 4 байта, то операции «++» сместит указатель в памяти на 4 байта.

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

int mas[10], і; int* pMas;

for(і = 0, pMas = mas; і < 10; i++) printf("%d ", *(pMas+i));

Динамическая память. Массивы

До сих пор все массивы данных у нас были строго определенного размера. В некоторых задачах это бывает неудобно. Например, требуется, чтобы пользователь задал некий массив данных, при этом на этапе написания программы его размер неизвестен. Можно, конечно, заранее выделить под массив 100 МБайт памяти и считать, что этого всегда хватит. Но возможны два варианта:

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

мают 101 Мбайт;

• для конкретной задачи достаточно 10 элементов по 4 КБайт.

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

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

int* pArr;

int Count;

int і;

int Sum = 0;

double Avg;

printf("Input elements count: ");

scant("%d", &Count);

pArr = malloc(sizeof(int)*Count);

if (pArr == NULL)

{

Printf("Can't allocate memory!");

}

for(i =0; і < Count; i++) scanf("%d”, (pArr+i));

for(i =0; і < Count; i++) Sum += *(pArr+i);

Avg = (double)Sum/Count;

printf("Sum = %d ", Sum);

printf("Avg = %f ", Avg);

free(pArr);

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

В случае если программа по каким-то причинам не может выделить указанный вами объем памяти, функция malloc () вернет NULL. Поэтому для обеспечения корректной работы программы необходимо всегда выполнять проверку значения, которое вернула функция malloc ().

 
Посмотреть оригинал
< Пред   СОДЕРЖАНИЕ   ОРИГИНАЛ   След >