Прочитать из файла строку информации и отсортировать по результату int - PullRequest
0 голосов
/ 01 января 2019

Я пытаюсь создать топ-5 программ по программированию на Си.Информация хранится в обычном текстовом файле.

Я хочу отсортировать информацию в файле history.txt по результату%: интервалы 1-3 - это тип теста, выполненного пользователем.

26%       User1           1       01/01/2019
100%      User2           3       01/01/2019
73%       User3           1       01/01/2019
52%       User4           1       01/01/2019
75%       User5           2       01/01/2019
60%       User6           1       01/01/2019

Теперь я ошибся в своем коде, но сейчас просто хожу по кругу.это проверка символов [50];Это не массив, но я не знаю, как его решить, чтобы остаться вместе с результатом в%.Я на данный момент решил сортировку результата.Но остальная часть текста - это просто повторяющийся беспорядок.

// Отображение 5-го наилучшего результата (это в функции)

fp = fopen("history.txt", "r");
int ch=0;
int lines=0;
while(!feof(fp))
{
    ch = fgetc(fp);
    if(ch == '\n')
    {
        lines++;
    }
}
fclose(fp);

fp = fopen("history.txt", "r");

int i =0, temp, swapped;
int topResult[lines];
char testTy[50];

char singelLine[100];
while(!feof(fp))
{
    fgets(singelLine, 100, fp);
    sscanf(singelLine, "%d%[^'\n']s",&topResult[i], testTy);
    i++;
}

fclose(fp);
while(1)
{
    swapped = 0;

    for( i= 0; i <lines-1; i++)
    {
        if(topResult[i]<topResult[i+1])
        {
            int temp = topResult[i];
            topResult[i] = topResult[i+1];
            topResult[i+1] = temp;
            swapped = 1;
        }
    }
    if(swapped == 0)
    {
        break;
    }
}

printf("Result:   User:      Test type:      Date:\n");
for (i = 0; i < 5; i++)
{
    printf("\n%d%25s", topResult[i], testTy);
}
printf("\n\n");
return;

Результат, который я хочу получить, выглядит следующим образом:

100%     user2  3 01/01/2019
75%      user5  2 01/01/2019
73%      user3  1 01/01/2019
60%      user6  1 01/01/2019
52%      user4  1 01/01/2019

Мой вывод:

100%     user1  1 01/01/2019
75%      user1  1 01/01/2019
73%      user1  1 01/01/2019
60%      user1  1 01/01/2019
52%      user1  1 01/01/2019

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Ваша непосредственная проблема была отмечена в комментарии, и вы были направлены на Почему while (! Feof (file)) всегда неверно? .Всегда проверяйте цикл чтения на самой функции чтения или выполняйте цикл постоянно и проверяйте возвращение функции чтения внутри цикла и break; цикла, когда произошло успешное чтение и все ограничения выполнены.

fp = fopen("history.txt", "r");

Не кодируйте имена файлов жестко и не используйте magic-numbers в вашем коде.Для имен файлов либо передайте имя файла для чтения в качестве аргумента вашей программе (для этого argv), либо запросите его ввод.(желательно передать это в качестве аргумента).Если вам нужны константы в вашем коде, #define один (или более) или используйте глобальный enum для достижения той же цели.

Теперь суть вашей проблемы.В любое время, когда вам приходится обрабатывать различные типы значений как одну запись или объект, вы должны подумать об использовании структуры для координации различных типов как одного объекта.Здесь вы можете объявить struct с int членами для хранения значений процента и типа теста и char[] (или char* и выделить) для хранения информации об имени и дате.Затем вы можете просто объявить массив struct для хранения всех значений, прочитанных из вашего history.txt файла, который можно легко отсортировать с помощью qsort на любом из выбранных вами членов.

Сначала, объявите простую структуру,Например,

struct users {     /* simple struct to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
};

Затем вы можете просто объявить массив с помощью struct users array[50];. Однако вы можете упростить свою жизнь и избежать необходимости вводить struct users ... снова и снова, создавая typedef.В C вы даже можете удалить метку struct users и добавить метку typedef в конце, например,

typedef struct {    /* simple struct w/typedef to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
} userhist_t;

Теперь вы можете просто создать массив struct с помощью userhist_t array[50]; (решать вамвы используете typedef или нет, это не требуется, это просто экономит набор текста)

Если вы сортируете значения в C, сделайте одолжение и научитесь писать сравнить функции для qsort.Это швейцарский армейский нож для сортировки в C. (он также довольно эффективен и намного лучше проверен, чем все, что вы будете катать самостоятельно).Нет ничего сложного в написании функции сравнения.Прототип:

int compare (const void *a, const void *b);

Где a и b - это просто указатели на смежные элементы в передаваемом вами массиве, и вы возвращаете -1, если a сортирует перед b, 0 если они одинаковые, или 1, если b сортирует до a - точно так же, как strcmp.Для этого вы просто приводите a и b к типу элемента для вашего массива, а затем сравниваете значения, возвращая соответствующее значение.Например:

/* qsort compare function sorting array of struct by percent (descending) */
int compare_pct (const void *a, const void *b)
{
    const userhist_t    *as = a,    /* cast the pointers to correct type */
                        *bs = b;

    /* return descending sort (conditionals avoids potential overflow)
     * for ascending sort use (as > bs) - (as < bs)
     */
    return (as->pct < bs->pct) - (as->pct > bs->pct);
}

Выше указатели a и b приводятся как указатель на вашу структуру (я только что пометил s для структуры, чтобы создать разные имена переменных, например as и bs, вы можете назвать их как угодно).

Хотя вы можете просто вернуть bs->pct - as->pct, существует риск переполнения, если значения превышают то, что может быть возвращено как int (например, оба больших отрицательных значения, которые при вычитании будут меньше * 1066)*. Вместо этого условные выражения используются для нормализации возврата к -1, 0, 1, просто используя результат условных выражений.

(продумайте его, если (as->pct < bs->pct), результат оценивается как 1 и (as->pct > bs->pct) оценивается как 0, что дает 1 - 0 = 1 (поэтому b сортирует до a в порядке убывания))

Чтобы отсортировать массив, вы просто вызываете:

qsort (array, nelements, sizeof element, compare);

Теперь перейдем к чтению / заполнению массива структуры. Итак, давайте объявим наши константы, у вас есть структура выше, давайте объявим массив структуры, а затем прочитаем значения из файла в массив, например,

/* global enum defining constants for use in code */
enum { MAXDT = 12, MAXNM = 16, MAXS = 64 };
...
    userhist_t user[MAXS] = {{ .pct = 0 }};   /* array of struct */
    size_t n = 0;
    ...
    /* read/fill up to MAXS struct from file */
    while (n < MAXS && fscanf (fp, "%d%% %s %d %s", &user[n].pct,
            user[n].name, &user[n].test, user[n].date) == 4)
        n++;

Хотя вы можете использовать fgets и sscanf, чтобы прочитать строку и затем проанализировать значения по отдельности, fscanf выполнит оба примера для примера. Ключом является проверка возврата к страхованию 4-conversionsуспешно, и вход или совпадение сбой не произошел.

В целом, передавая имя файла в качестве 1-го аргумента программе (или читая из stdin по умолчанию, если аргумент не указан), обрабатывая объявления, чтение, сортировку с qsort и вывод,Вы можете сделать что-то похожее на следующее:

#include <stdio.h>
#include <stdlib.h>

/* global enum defining constants for use in code */
enum { MAXDT = 12, MAXNM = 16, MAXS = 64 };

typedef struct {    /* simple struct to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
} userhist_t;

/* qsort compare function sorting array of struct by percent (descending) */
int compare_pct (const void *a, const void *b)
{
    const userhist_t    *as = a,    /* cast the pointers to correct type */
                        *bs = b;

    /* return descending sort (conditionals avoids potential overflow)
     * for ascending sort use (as > bs) - (as < bs)
     */
    return (as->pct < bs->pct) - (as->pct > bs->pct);
}

int main (int argc, char **argv) {

    userhist_t user[MAXS] = {{ .pct = 0 }};   /* array of struct */
    size_t n = 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;
    }

    /* read/fill up to MAXS struct from file */
    while (n < MAXS && fscanf (fp, "%d%% %s %d %s", &user[n].pct,
            user[n].name, &user[n].test, user[n].date) == 4)
        n++;
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    /* sort by calling compare_pct to sort by percent (descending order) */
    qsort (user, n, sizeof *user, compare_pct);

    for (size_t i = 0; i < n; i++)  /* output sorted results */
        printf ("%3d%%      %-8s    %2d     %s\n", 
                user[i].pct, user[i].name, user[i].test, user[i].date);

    return 0;
}

Пример входного файла

$ cat dat/history.txt
26%       User1           1       01/01/2019
100%      User2           3       01/01/2019
73%       User3           1       01/01/2019
52%       User4           1       01/01/2019
75%       User5           2       01/01/2019
60%       User6           1       01/01/2019

Пример использования / Вывод

Использование вашего входного файла приведет к сортировке, которую вы описываете:

$ ./bin/userhistsort dat/history.txt
100%      User2        3     01/01/2019
 75%      User5        2     01/01/2019
 73%      User3        1     01/01/2019
 60%      User6        1     01/01/2019
 52%      User4        1     01/01/2019
 26%      User1        1     01/01/2019

Если вы хотите сохранить результаты в новый файл, просто перенаправьте вывод, например,

$ ./bin/userhistsort dat/history.txt > sortedfile.txt

(или вы можете открыть новый поток файлов в вашем коде и вывести туда информацию)

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

0 голосов
/ 02 января 2019

Я думаю, проблема в том, что testTy не является массивом.Вы разделяете входные данные на две переменные:

  • topResult: массив с сортируемыми значениями
  • testTy: остальная часть строки

Когда вы печатаете результат, переменная testTy всегда будет иметь одинаковый вывод.

...