Язык C позволяет создавать многомерные массивы. Например, двумерную матрицу размером 100 строк на 200 столбцов можно описать следующим образом:
double matr[100][200];
Обращаться к элементу матрицы с индексами (i,j) можно используя два индекса, каждый в отдельных квадратных скобках:
matr[i][j] = 0;
x = matr[i][j];
Удобно считать, что индекс в первых квадратных скобках — номер строки, а во вторых — номер столбца. Таким образом, matr[i][j] – элемент матрицы на пересечении i-й строки и j-го столбца.
Программа печати содержимого матрицы 100x200: печатаем 100 строк по 200 элементов в каждой
double matr[100][200];
int i, j;
… /* инициализация матрицы */
for (i = 0; i < 100; i++) {
for (j = 0; j < 200; j++) {
printf(“%lf “, matr[i][j]);
}
printf(“\n”);
}
Программа перемножения двух матриц 100x200 и 200x150, результат — матрица 100x150:
double m1[100][200], m2[200][150], m3[100][150];
int i, j, k;
… /* инициализация m1 и m2 */
for (i = 0; i < 100; i++) {
for (j = 0; j < 150; j++) {
m3[i][j] = 0;
for (k = 0; k < 200; k++) {
m3[i][j] += m1[i][k]*m2[k][j];
}
}
}
Часто размер матрицы неизвестен в момент написания программы. В этом случае удобно выделять память под матрицу в тот момент, когда ее размер становится известным. Это делается при помощи известной нам функции malloc().
Память, выделяемая динамически, линейна, то есть представляет собой одномерный массив. Программист, используя ее для хранения многомерных массивов, сам отвечает за размещение элементов матрицы в этом одномерном массиве, то есть устанавливает соответствие между двумя индексами элемента в матрице и одним индексом элемента в одномеерном массиве. Матрицу удобно хранить в одномерном массиве в виде последовательности строк.
Программа, считывающая размер матрицы и ее элементы с клавиатуры и выводящая матрицу на экран:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double *matr;
int n, k, i, j;
scanf(“%d%d”, &n, &k);
if ((n <= 0) || (k <= 0)) {
printf(“Wrong size\n”);
return -1;
}
matr = (double*)malloc(n*k*sizeof(double));
for (j = 0; j < k; j++) {
for (i = 0; i < n; i++)
scanf(“%lf”, &matr[i + j*n]);
}
for (j = 0; j < k; j++) {
for (i = 0; i < n; i++)
printf(“%lf ”, matr[i + j*n]);
printf(“\n”);
}
free(matr);
return 0;
}
Для отладки программы можно использовать не только дополнительную печать состояния программы, называемую отладочной, но и специальные средства.
В ОС Линукс имеется отладчик GDB, позволяющий выполнять программу по шагам или непрерывно до определенной точки, называемой breakpoint, отслеживать текущее состояние переменных и стека вызова функций.
Для полноценной работы отладчика с программой ее загрузочный код должен содержать отладочную информмацию. Это достигается добавлением опции “-g” в команде компиляции, например:
gcc tmp.c -g
Результат такой компиляции загрузочный файл a.out содержит отладочную информацию.
Для выполнения загрузочного файла в режиме отладки надо при его загрузке добавить перед его именем имя отладчика:
gdb ./a.out
Отладчик gdb работает в командном режиме, то есть команды пользователя набираются в командной строке.
Самые главные команды в отладчике — run и quit. Первая выполняет программу, вторая позволяет закончить отладку.
Если программа в процессе выполнения «упала», то помогут команды bt и frame. Первая покажет стек вызовов функций в момент «падения» с именами и номерами функций, вторая поможет выбрать интересующую функцию в этом стеке по ее номеру:
bt
frame 1
Чтобы разобраться, почему программа «упала», полезно применить команду print, которая выводит на экран значения переменных в момент падения:
print matr[0][0]
print i
print j
Если указанные команды не помогли, то можно воспользоваться возможностью выполнения программы до определенной точки, например:
break main
run
А затем выполнять программу по шагам при помощи команд next (выполняет очередную инструкцию) и step («проваливается» в вызов функции).