Скопируйте файл в массив (структуру), используя fscanf c - PullRequest
0 голосов
/ 20 ноября 2018

Я пытаюсь написать функцию, которая будет копировать float из файла с помощью fscanf и помещать их в массив. Мне также нужно вернуть количество поплавков в файле. Вот что у меня сейчас есть:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX 100


struct cg {
    // structure to hold x and y co-ordinates and mass
    float x, y, mass;
}masses[MAX];


int readin(void)
{
    FILE *fp;
    masses cg;
//Error saying cg is an undeclared identifier.
    fp = fopen("m.txt", "rb");
    int n = 0;

    if (fp == NULL) {
        printf("Cannot find file.");
        return 0;
    }
    else {
        fscanf(fp, "%f" &cg.x, &cg.y, &cg.mass);
//Error here too
            n++;
            fclose(fp);
            getchar();
            return n;

    }

    }
    /* Write this function to read in the data from a file */
    /* into the array masses */
    /* note that this function should return the number of */
    /* masses read in from the file */


void computecg(int n_masses)
{
    /* Write this function to compute the C of G */
    /* and print the result */
}
void main(void)
{
    int number;
    if ((number = readin()) > 0) {
        computecg(number);
    }
}

Это мой первый год обучения c, и мой преподаватель ужасен, и помощь очень ценится!

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Есть ряд областей, в которых вы можете «отрегулировать» вещи, чтобы сделать ваше чтение позиций и массы более надежными.Однако, прежде чем рассматривать какие-либо особенности, давайте начнем с:

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 оставлено на ваше усмотрение.Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 20 ноября 2018

Определите вашу структуру cg и объявите обе переменные struct cg cg и масс следующим образом: while (n < MAX){ fscanf("%f %f %f", &cg.x, &cg.y, &cg.mass); masses[n] = cg; ++n;} return n;

struct cg {
    float x, y, mass;
}cg, masses[MAX];

Затем в функции readin вы должны прокомментировать строку, содержащую массы cg , а в блоке else вы можете написать блок while, например: следующее:

while (n < MAX){
    fscanf("%f %f %f", &cg.x, &cg.y, &cg.mass);
    masses[n] = cg;
    ++n;
}
return n;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...