Есть ряд областей, в которых вы можете «отрегулировать» вещи, чтобы сделать ваше чтение позиций и массы более надежными.Однако, прежде чем рассматривать какие-либо особенности, давайте начнем с:
void main()
Подходящими объявлениями для main
являются int main (void)
и int main (int argc, char **argv)
(которые вы увидите написанными с эквивалентом char *argv[]
). примечание: main
является функцией type int
и возвращает значение.См .: Стандарт C11 §5.1.2.2.1 Запуск программы p1 (черновик n1570) .См. Также: См. Что должно возвращать main () в C и C ++?
Теперь поговорим о специфике.Вы определяете struct и объявляете глобальный массив struct (MAX
из них) с именем masses
с:
struct cg {
// structure to hold x and y co-ordinates and mass
float x, y, mass;
}masses[MAX];
( note: для любых вычислений, которые вам понадобятсяизмените float
на double
, чтобы воспользоваться повышенной точностью и минимизировать ошибку округления.)
При правильном определении и объявлении избегайте использования глобальных переменных.Они не нужны во всех, кроме очень немногих случаев.Вместо этого просто объявите ваш struct cg
, а затем объявите ваш массив в main()
и передайте массив в качестве параметра каждой функции, которая в этом нуждается.У вас правильно определен глобальный MAX
, поэтому все, что вам нужно передать в функцию для заполнения, это массив, объявленный в main()
(желательно вместе с дескриптором открытого файла)
Зачем открывать файл в main()
до звонка readin()
?Очевидно, что если вы попытаетесь открыть файл, но он не получится, вам не нужно будет вызывать readin()
.Таким образом, в общем, откройте файл в вызывающей программе, проверьте, открыт ли файл, перед тем, как передать открытый указатель потока FILE*
на функцию для чтения - в противном случае нет необходимости вызывать функцию.Например,
int main (int argc, char **argv)
{
int number;
struct cg masses[MAX] = {{ .x = 0.0 }};
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if ((number = readin (masses, fp)) > 0) {
printf ("\n%d objects read:\n\n", number);
computecg (masses, number);
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Таким образом, ваш readin()
уменьшается до:
int readin (struct cg *masses, FILE *fp)
{
int n = 0;
while (n < MAX && fscanf (fp, "%lf %lf %lf",
&masses[n].x, &masses[n].y, &masses[n].mass) == 3)
n++;
return n;
}
( примечание: как if (n < MAX && ...
в вашем звонке fscanf
защищает границы вашего массива, отказываясь читать более MAX
значений. Всегда защищайте свои границы массива везде, где есть вероятность, что ваш код может прочитать больше значений, чем у вас есть пробелы для ...)
он должен был сделать readin()
значения позиции и массы из открытого файла и вернуть номер объекта, для которого была прочитана позиция и масса.
Вы просто передаете заполненный массив вместе с номером объектадля которых значения хранятся в вашем массиве.Например, просто напечатав содержимое в вашем массиве masses
в функции computecg()
, вы можете сделать:
void computecg (struct cg *masses, int n_masses)
{
/* Write this function to compute the C of G */
/* and print the result */
for (int i = 0; i < n_masses; i++)
printf ("%6.2f %6.2f %6.2f\n",
masses[i].x, masses[i].y, masses[i].mass);
}
В целом, например, будет:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct cg { /* define struct, declare instance in main() */
double x, y, mass; /* (a typedef will make things convenient) */
};
int readin (struct cg *masses, FILE *fp)
{
int n = 0;
while (n < MAX && fscanf (fp, "%lf %lf %lf",
&masses[n].x, &masses[n].y, &masses[n].mass) == 3)
n++;
return n;
}
void computecg (struct cg *masses, int n_masses)
{
/* Write this function to compute the C of G */
/* and print the result */
for (int i = 0; i < n_masses; i++)
printf ("%6.2f %6.2f %6.2f\n",
masses[i].x, masses[i].y, masses[i].mass);
}
int main (int argc, char **argv)
{
int number;
struct cg masses[MAX] = {{ .x = 0.0 }};
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if ((number = readin (masses, fp)) > 0) {
printf ("\n%d objects read:\n\n", number);
computecg (masses, number);
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
return 0;
}
( примечание: #if defined (_WIN32) || defined (_WIN64)
просто используется, чтобы проверить, компилируется ли программа в Windows - так как нет необходимости держать терминал открытым с getchar();
в противном случае)
Пример входного файла
$ cat dat/cgmasses.txt
1.37 1.37 713.54
3.00 3.00 189.55
1.05 1.05 276.15
2.57 2.57 238.94
2.17 2.17 189.03
6.73 6.73 263.26
3.26 3.26 795.61
9.41 9.41 283.92
1.60 1.60 279.72
1.70 1.70 719.12
Пример Использование / Вывод
$ ./bin/cgmasses_read <dat/cgmasses.txt
10 objects read:
1.37 1.37 713.54
3.00 3.00 189.55
1.05 1.05 276.15
2.57 2.57 238.94
2.17 2.17 189.03
6.73 6.73 263.26
3.26 3.26 795.61
9.41 9.41 283.92
1.60 1.60 279.72
1.70 1.70 719.12
Вычисление cg оставлено на ваше усмотрение.Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.