Введение |
Операторы |
Операции |
Переменные и типы |
Пояснения к курсовой работе |
Препроцессор |
Работа с файлами |
Стандарты безопасного кодирования |
Указатели и динамическая память |
Функции и модули |
Ввод-вывод |
Если несколько переменных имеют одинаковое назначение в программе, с ними производятся одинаковые действия (семь козлят или семь гномов в сказках), то вместо задания каждой переменной уникального имени мы указываем имя для всего набора таких переменных и их количество:
тип имя [
количество ];
Для доступа к элементам такого набора используется операция индексации: имя[номер], где номер принимает значения от 0 до (количество-1).
Набор из элементов одинакового типа, обращение к которым идет по их порядковому номеру (индексу), называется массив. Аналогом массива в математике является последовательность, но массив всегда имеет ограниченный размер, а последовательность в математике часто является бесконечной.
Для заполнения и обработки массивов используются циклы. Так как операция индексации в языке С не проверяет выход номера за границы, рекомендуется самостоятельно проверять, что первое и последнее значение переменной цикла не приводит в операции индексации к получению значения меньше 0 или больше (количество-1).
#include <stdio.h>
// Факториалы целых чисел
int main()
{ int f[13];
f[0]=1;
for(int i=1; i<13; ++i)
f[i]=i*f[i-1];
for(int i=0; i<13; ++i)
printf("%d! = %d\n",i,f[i]);
}
В программе несколько раз повторяется число 13. При изменении размера массива придется изменить эти константы на другое значение столько же раз. Для упрощения таких изменений можно
sizeof
, которая возвращает размер в байтах своего аргумента – для получения количества элементов в массиве f
нужно написать sizeof(f)/sizeof(f[0])
#define
имя значениеИмя такой константы рекомендуется писать прописными буквами.
#include <stdio.h>
// Решето Эратосфена для простых чисел
#define N 1000000
char p[N+1];
int main()
{ p[0]=p[1]=1; // 0 и 1 не являются простыми
for(int i=2; i*i<=N; ++i)
if(!p[i]) { // не вычеркнуто
for(int j=i*i; j<=N; j+=i)
p[j]=1; // вычеркнуть числа, кратные i
}
int k=0;
for(int i=1; i<=N; ++i)
if(!p[i]) ++k;
printf("Количество простых чисел от 1 до %d равно %d\n",N,k);
}
Без инициализации элементы массива, определяемого в стековой памяти, имеют неопределенное значение, в статической – 0.
Можно указать начальные значения элементам массива, количество элементов которого задано константой. Список начальных значений указывается в {}
через запятую, начиная с нулевого. Можно явно указать, какому элементу присваивается значение: [номер]=выражение. Если значение какого-либо элемента явно не указано, то он получает значение 0. Если количество элементов в массиве определяется списком инициализации, количество можно не указывать:
int a[]={1,2,3,4,5};
#include <stdio.h>
int a[10]; // статическая память, все элементы 0
int main()
{ int b[10]; // стековая память, неопределенное значение
int c[10]={1,2,7,[7]=100, [9]=101}; // стековая память,
// элементы с номерами 0,1,2,7,9 заданы явно, остальные - 0
for(int i=0; i<10; ++i)
printf("%d: %d %d %d\n",i,a[i],b[i],c[i]);
}
Типовые примеры обработки массивов:
// ввод размера массива, создание массива и ввод его элементов
int n;
scanf("%d",&n);
double a[n];
for(int i=0; i<n; ++i)
scanf("%lf",&a[i]);
// вывод элементов массива на 1 строке
for(int i=0; i<n; ++i)
printf("%lf%c",&a[i], i<n-1?' ':'\n'); // разделяем пробелами, после (n-1)-го переход на новую строку
// поиск индекса максимального элемента в массиве
int imax=0; // предполагаем, что максимальный имеет индекс 0
for(int i=1; i<n; ++i) // проверяем с 0
if(a[i]>a[imax]) imax=i; // нашли лучше
printf("%d %lf\n", imax, a[imax]); // печать индекса и значение максимума
// поиск индекса первого элемента, который дает минимум некоторого выражения, например, sin(a[i])+cos(a[i])
int imin;
double fmin;
for(int i=0; i<n; ++i) {
f=sin(a[i])+cos(a[i]); // вычисляем выражение
if(i==0 || f<fmin) { // первый элемент или нашли лучше
imin=i; // запоминаем индекс
fmin=f; // и сам минимум
}
}
printf("%d %lf\n", imin, fmin); // печать индекса и значение минимума
Для копирования элементов массива вместо цикла можно использовать функции memcpy
и memmove
, объявленные в <string.h>
. memcpy
позволяет скопировать один массив в другой (массивы должны быть одинакового типа и размера), memmove
используется для копирования части массива, в том числе в пределах одного массива. Чтобы указать в качестве начальной позиции части массива k-й элемент, используется запись (имя_массива+k), а выражение имя_массива означает весь массив с 0-го элемента соответственно. В качестве аргумента можно указать массив-значение: (спецификаторы тип[ ]){список_значений}
#include <stdio.h>
#include <string.h>
int main()
{ int a[10]={1,2,3,4,5,6,7,8,9,10},
b[10];
memcpy(b,a,sizeof(a)); // b <- весь a
for(int i=0; i<10; ++i)
printf("%d%c",b[i],i<9?' ':'\n'); // вывод массива b
memmove(b+4,b+6,sizeof(b[0])*3); // b[4],b[5],b[6] <- b[6],b[7],b[8]
memmove(b+1,(const int[]){-3,-2,-1},sizeof(b[0])*3); // b[1],b[2],b[3] <- -3,-2,-1
for(int i=0; i<10; ++i)
printf("%d%c",b[i],i<9?' ':'\n');
}
В качестве элементов массива могут выступать другие массивы, все массивы-элементы должны иметь одинаковый размер:
double uravn[2][3]; // коэффициенты системы из 2 линейных уравнений - матрица 2 x 3
a[i][j]
– обращение к элементу в i-й строке, j-м столбце
#include <stdio.h>
int main()
{ int n;
scanf("%d",&n);
double a[n][n],c[n][n];
// ввод матрицы
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
scanf("%lg",&a[i][j]);
// вычисление квадрата матрицы
for(int i=0;i<n;++i)
for(int j=0;j<n;++j) {
c[i][j]=0;
for(int k=0;k<n;++k)
c[i][j]+=a[i][k]*a[k][j];
}
// вывод матрицы
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
printf("%lg%c",c[i][j],j==n-1?'\n':' ');
}