Пример программы с использованием двумерных массивов

Имеется молекула, состоящая из n атомов. Геометрическая конфигурация этой молекулы характеризуется положением в пространстве каждого из атомов. Так как атомы — протяженные объекты, а их границы не имеют четкого определения, то на практике под положением атома понимают положение его ядра. Итак, геометрическая конфигурация молекулы задана декартовыми координатами ядер атомов xi, yi, zi (i = 1, 2, ¼, n). Помимо координат, указаны символы химических элементов. Например, данные о геометрической конфигурации молекулы ацетальдегида CH3CHO записаны в файле acetald.dat в следующем виде:

C -0.0789455 -0.4488120 0.0000000

C 1.2834071 0.1812646 0.0000000

O -1.2036536 0.2344798 0.0000000

H -0.1310309 -1.5615937 0.0000000

H 1.2042458 1.2643756 0.0000000

H 1.8441620 -0.1192523 -0.8801361

H 1.8441620 -0.1192523 0.8801361

В первой строке указано количество атомов в молекуле (7), затем для каждого атома записан химический символ и три координаты ядра (x, y, z), выраженные в ангстремах[1].

Требуется написать программу, которая читает из файла данные о молекуле и сообщает наименьшее и наибольшее межъядерные расстояния (с указанием атомов, к которым эти расстояния относятся).

Координаты точки в пространстве (в нашем случае — координаты ядра атома) удобно хранить в виде массива из трех элементов. Совокупность координат всех атомов молекулы — это массив координат точек (ядер), т.е. массив массивов (или двумерный массив).

Химические символы записываются одной или двумя буквами, т.е. в общем случае для их представления нужны строки символов (букв) максимальной длины 2. В языке C строки символов — это массивы элементов типа char. В частности, "hello!" — тоже массив (хотя и константный), причем его длина на единицу больше, чем число символов между кавычками, т.е. "hello!" имеет размер 7 элементов (7 байтов). Дело в том, что конец строки принято отмечать специальным символом с кодом 0 (обозначается '\0'). Функции стандартной библиотеки C, имеющие дело со строками, предполагают, что конец строки помечен именно таким способом. Это касается, в частности, ввода и вывода строк с помощью scanf, printf и других подобных функций. Поэтому размер массива для хранения строки длиной 2 символа должен быть не менее 3 элементов, т.е. один химический символ можно разместить в массиве

char s[3];

а для хранения символов всех атомов молекулы понадобится массив строк, т.е. опять-таки массив массивов (с элементами типа char).

Вычисление расстояния между двумя точками (ядрами атомов) имеет смысл выделить в отдельную функцию (назовем ее dist от слова distance — расстояние). Аргументами функции будут два трехэлементных массива координат. Такую функцию можно использовать не только в этой задаче, но и в любой другой, где требуется вычислять расстояния между точками 3-мерного пространства.

Текст программы приведен ниже:

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#define MAXAT 20 /* макс. количество атомов в молекуле */

/* Функция dist вычисляет расстояние между точками p1 и p2 */

double dist (double p1[3], double p2[3])

{

int i;

double d, s = 0.0;

for (i = 0; i < 3; i++)

s += (d = p2[i] - p1[i], d*d);

return sqrt(s);

}

/* Главная программа */

void main (int nargs, char *arg[])

{

static double at[MAXAT][3]; /* массив координат атомов */

static char sym[MAXAT][3]; /* массив хим. символов */

int n; /* число атомов в молекуле */

int imin, jmin; /* номера пары самых близких атомов */

int imax, jmax; /* номера пары наиболее удаленных атомов */

double d, dmin, dmax; /* текущее, наименьшее и наибольшее расстояния */

int i, j; /* переменные циклов для перебора пар атомов */

FILE *f = stdin; /* файл, из которого вводятся данные */

/* Если файл указан в командной строке, открыть его;

иначе использовать стандартный поток ввода (stdin) */

if (nargs > 1) {

f = fopen (arg[1], "r");

if (f == NULL) {

perror (arg[1]);

exit (1);

}

}

/* Ввод исходных данных */

fscanf (f, "%d", &n);

for (i = 0; i < n; i++)

fscanf(f,"%2s%lf%lf%lf", sym[i], &at[i][0], &at[i][1], &at[i][2]);

fclose (f);

/* Поиск минимального и максимального расстояний */

dmin = 1e38;

dmax = 0.0;

for (i = 0; i < n-1; i++)

for (j = i+1; j < n; j++) {

d = dist (at[i], at[j]);

if (d < dmin) {

dmin = d;

imin = i;

jmin = j;

}

if (d > dmax) {

dmax = d;

imax = i;

jmax = j;

}

}

/* Вывод результатов */

printf ("Dmin = %8.5f %d(%s) - %d(%s)\n",

dmin, imin+1, sym[imin], jmin+1, sym[jmin]);

printf ("Dmax = %8.5f %d(%s) - %d(%s)\n",

dmax, imax+1, sym[imax], jmax+1, sym[jmax]);

}

В случае приведенных выше данных для молекулы ацетальдегида программа выводит такой результат:

Dmin = 1.08600 2(C) - 5(H)

Dmax = 3.19201 3(O) - 6(H)

Обратите внимание на то, как используются элементы-массивы двумерных массивов at и sym при обращении к функции dist и при вводе/выводе химических символов атомов.

Название файла, где содержатся исходные данные, программа получает в виде первого параметра командной строки (функция main может получить доступ к командной строке через свои аргументы — подробнее см. книгу Кернигана и Ритчи, гл. 5, п. 5.10). Если же программу запустили без параметров, то данные будут вводиться из стандартного потока ввода (stdin), который указан в качестве начального значения переменной f. Пусть исполняемый файл, полученный в результате компиляции и компоновки приведенной программы, называется prog.exe. Тогда запустить программу можно тремя разными способами:

1. Файл с данными указывается как параметр командной строки:

prog acetald.dat

2. Командная строка без параметров:

prog

После запуска программа начнет читать данные из стандартного потока ввода, т.е. ввод с клавиатуры.

3. Стандартный поток ввода переадресуется на файл с помощью символа < в командной строке:

prog <acetald.dat

Так же, как и в предыдущем случае, данные читаются из потока stdin (программа не заметит никакой разницы между этими вариантами). Однако операционная система будет посылать данные в поток stdin не с клавиатуры, а из файла acetald.dat.


[1] Данные получены в результате квантовохимического расчета молекулы ацетальдегида.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: