Пример 1. Рассмотрим задачу сортировки 3 чисел по возрастанию. Считаем числа с клавиатуры в переменные a, b и c, поменяем значения a, b, c между собой так, чтобы выполнялись неравенства a < b < c, а затем выведем числа a, b, c на экран.
#include <stdio.h>
int main(void) {
int a, b, c, buf;
scanf(“%d%d%d”, &a, &b, &c);
/* Поместим в a самое маленькое число */
if ((b < a) && (b < c)) {
buf = a; a = b; b = buf;
} else if ((c < a) && (c < a)) {
buf = a; a = c; c = buf;
}
/* Поместим в b самое маленькое из чисел b и c */
if (c < b) {
buf = b; b = c; c = buf;
}
printf(“%d %d %d\n”, a, b, c);
return 0;
}
Программа получилась довольно громоздкая и запутанная.
Теперь представим, что надо отсортировать 1000 чисел. Для того, чтобы прочитать эти числа с клавиатуры или из файла, необходимо завести 1000 переменных. А затем придется перебрать каждую из 999 переменных и сравнить их с оствшимися 999 переменными, чтобы проверить, не больше ли эта переменная всех остальных и не надо ли поместить ее значение в последнюю из переменных. И так 999 раз: для каждого из мест 2-1000.
Чтобы облегчить работу с большим количеством однотипных переменных, в языках высокого уровня имеется тип данных «таблица».
В языке C, как и в других языках высокого уровня, есть механизм создания таблиц (массивов, векторов), содержащих несколько переменных одного типа. Для этого нужно указать тип элементов, имя таблицы и количество элементов в таблице, причем количество элементов в таблице должно быть константой. Например :
int array[1000];
К переменным внутри таблицы можно обращаться, используя имя таблицы и индекс (номер) переменной — целое число, например, array[0] или array[n], где n – целая переменная.
Индексы переменных в таблице из N переменных — это числа в диапазоне от 0 до N-1.
Пример 2. Программа сортировки 1000 чисел методом поиска минимального элемента:
#include <stdio.h>
int main(void) {
int array[1000];
int buf;
int i;
for (i = 0; i < 1000; i++)
scanf(“%d “, &array[i]);
/* Для каждого элемента таблицы с индексом 0, …, 999 */
for (i = 0; i < 1000; i++) {
/* Находим индекс минимального элемента из элементов i, …, 1000 */
imin = i;
for (j = 0; j < 1000; j++) {
if (array[j] < array[imin]) {
imin = j;
}
}
/* Ставим минимальный элемент на i-ое место: меняем значения array[imin] и array[i] */
if (i != imin) {
buf = array[i];
array[i] = array[imin];
array[imin] = buf;
}
}
for (i = 0; i < 1000; i++)
printf(“%d “, array[i]);
printf(“\n”);
return 0;
}
Указатели в языке C обладают следующим свойством: при увеличении значения указателя на 1 адрес, который в нем содержится меняется не на 1 байт, а на то количество байтов, которое содержится в элементах того типа, на которые он указывает.
Таким образом, если указатель содержит адрес какой-то переменной, то при увеличении значения указателя на 1 он будет указывать на байт памяти, следующий за этой переменной.
Элементы таблицы (массива) расположены в оперативной памяти поряд.
Поэтому для «прохода » по массиву можно использовать указатели.
Так, если указатель содержит адрес какого-то элемента массива, то при увеличении значения указателя на 1 он будет указывать на следующий элемент массива.
Таким образом, присвоив указателю адрес первого элемента массива и последовательно увеличивая его значение на 1, можно «пробежать» этим указателем по всем элементам массива, как это делается в примере 4.
Адрес первого элемента массива можно получить, используя оператор &.
Например, для массива целых чисел array это получение выглядит так:
int *p = &array[0];
Другой способ:
int *p = array;
Второй способ возможен, так как имя массива является его адресом, а именно указателем на его первый элемент, то есть на элемент с индексом 0.
Пример 3. Программа подсчета количества отрицательных элементов в массиве.
#include <stdio.h>
int main(void) {
int array[1000];
int *p;
int i;
int res = 0;
for (i = 0; i < 1000; i++)
scanf(“%d “, &array[i]);
p = array;
for (i = 0; i < 1000; i++) {
if (*p < 0)
++res;
}
printf(“Num of negative numbers: %d “, res);
return 0;
}
Если количество чисел, которые надо поместить в массив, заранее неизвестно, то можно воспользоваться функцией malloc(), которая пытается захватить определенное количество байтов в оперативной памяти. В случае удачного захвата памяти (если функция malloc вернула не 0) можно разместить содержимое элементов массива в этой захваченной памяти.
Например, при заполнении массива числами, находящимися в файле, можно узнать количество этих чисел и захватить количество байтов памяти, достаточное для размещения элементов массива, а затем считать числа из файла в эту память.
Количество чисел можно узнать, прочитав файл.
Количество байтов, используемых для размещения в памяти одного числа, можно узнать при помощи оператора sizeof(), например, оператор sizeof(int) возвращает количество байтов в целом числе.
Функция malloc() возвращает абстрактный адрес (void*) , который перед присвоением адресу массива надо преобразовать в указатель на тип элементов, хранящихся в массиве. Преобразование типа любого выражения осуществляется помещением нового типа в круглых скобках перед этим выражением, например: (int*)malloc(num * sizeof(int));
После окончания работы с массивом захваченную память необходимо освободить при помощи функции free().
Функции malloc() и free() реализованы в стандартной библиотеке, подключаемой автоматически, а задекларированы в файле <stdlib.h>
Пример 4. Программа сортировки чисел, находящихся в файле «tmp.dat”. Отсортированные числы выводятся в файл «tmp.res”.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *IN, *OUT;
int *array;
int i;
int num = 0;
IN = fopen(“tmp.dat”, “r”);
if (IN == NULL) {
printf(“File not opened\n”);
return -1;
}
while (fscanf(IN, “%d”, &x) == 1)
++num;
fclose(IN);
if (num == 0) {
printf(“File tmp.dat is empty\n”);
return 0;
}
array = (int*)malloc(sizeof(int) * num);
IN = fopen(“tmp.dat”, “r”);
if (IN == NULL) {
printf(“File not opened\n”);
return -1;
}
for (i = 0; i < num; i++)
fscanf(IN, “%d “, &array[i]);
fclose(IN);
for (i = 0; i < 1000; i++) {
/* Находим индекс минимального элемента из элементов i, …, 1000 */
imin = i;
for (j = 0; j < 1000; j++) {
if (array[j] < array[imin]) {
imin = j;
}
}
/* Ставим минимальный элемент на i-ое место: меняем значения array[imin] и array[i] */
if (i != imin) {
buf = array[i];
array[i] = array[imin];
array[imin] = buf;
}
}
OUT = fopen(“tmp.res”, “w”);
if (OUT == NULL) {
printf(“File tmp.res not opened\n”);
return -1;
}
for (i = 0; i < 1000; i++)
fprintf(OUT, “%d\n“, array[i]);
fclose(OUT);
free(array);
return 0;
}