Создание двусвязного списка из текстового файла на C

Мне нужно сделать двусвязный список из текстового файла, в котором каждая строка имеет время и температуру. Например, каждая строка выглядит так: 12:48 23,69.

Поэтому у меня возникли проблемы с помещением данных в двусвязный список. Я не знаю, как это реализовать. Итак, я сделал массив элементов структуры typedef и надеялся, что смогу начать с первого элемента массива и указать следующий на второй элемент массива. Вот что у меня есть...

Итак, вот мой заголовочный файл для двусвязного списка:

#include<stdio.h>
typedef struct tempdata_{

    int *hour;
    int *min;
    int *temp;
    struct tempdata_ *next;
    struct tempdata_ *prev;
}tempdata;

teypdef struct templist_{

    tempdata *head;
    tempdata *tail;
    int size;
}templist;

`

Вот мой основной файл:

 #include <stdio.h>
 #include "linkedlist.h"


int main ( int argc, char *argv[] )
 {
    FILE *ifp, *ofp;
    //char outputFilename[] = argv[2];
    int SIZE = 1;
    tempdata tempdata1[100];
    tempdata *temp, *current = NULL;

    if ( argc != 2 ) /* argc should be 3 for correct execution */
    {
        /* We print argv[0] assuming it is the program name */
        printf( "usage: %s filename", argv[0] );
    }
    else 
    {
        // We assume argv[1] is a filename to open
        ifp = fopen( argv[1], "r" );

        /* fopen returns 0, the NULL pointer, on failure */
        if ( ifp == 0 )
        {
             printf( "Could not open file\n" );
        }
        else 
        {
            //ofp = fopen(outputFilename, "w");

            /* reads the hours, min, tempeture integers and temperature decimals and
            prints them out on the screen and on the output file that is given.
            we dont need this printing function but I just left to have the       function do something*/

            while (fscanf(ifp, "%d:%d %d.%d ", &tempdata1[SIZE].hour, &tempdata1[SIZE].min, &tempdata1[SIZE].tempI, &tempdata1[SIZE].tempD) != EOF) {
                 printf("the tempeture is  %d.%d at %d:%d\n", tempdata1[SIZE].tempI, tempdata1[SIZE].tempD, tempdata1[SIZE].hour, tempdata1[SIZE].min);

                    /*fprintf(ofp, "the tempeture is  %d.%d at %d:%d\n", tempdata1[SIZE].tempI, tempdata1[SIZE].tempD, tempdata1[SIZE].hour, tempdata1[SIZE].min);*/
                SIZE++;
 }

 fclose(ifp);
 //fclose(ofp);


        }
    }
    getchar();
 }

person dwong    schedule 07.10.2012    source источник


Ответы (1)


Вам нужно int, а не int * в вашей структуре данных, а температура должна быть float или double, а не int (что значительно упрощает ввод; в противном случае правильная обработка как 26,09, так и 26,9 довольно сложна, когда вы используете два целых числа для ввода температура).

typedef struct tempdata tempdata;

struct tempdata
{
    int       hour;
    int       min;
    float     temp;
    tempdata *next;
    tempdata *prev;
};

Ваш заголовок был бы более убедительным без опечатки:

typedef struct templist templist;

struct templist
{
    tempdata *head;
    tempdata *tail;
    int size;
} templist;

Наличие массива структур tempdata на самом деле более разумно, чем двусвязный список, но, боюсь, это лишает цели упражнения. Вероятно, вам следует динамически распределять структуры по мере необходимости. Я бы использовал fgets() плюс sscanf(), но вы проверяете результат из fscanf() — это хорошо — но вы можете застрять, если данные искажены, потому что файл не находится в EOF, но не содержит цифры, которая нужна fscanf(). Вы должны проверить, что возвращаемое значение равно 3 (по одному для каждого преобразованного поля), а если нет, разорвать цикл.

Чтобы создать список, вам понадобится где-нибудь переменная типа templist, соответствующим образом инициализированная.

Я собрал программу ниже из вашего плана. Учитывая файл данных:

12:29 26.34
13:32 28.23
14:20 28.56
15:30 29.10
16:18 30.45
17:20 28.12
18:20 26.98
19:35 24.12

Результат, который я получил, был:

Data: 12:29  26.34
Data: 13:32  28.23
Data: 14:20  28.56
Data: 15:30  29.10
Data: 16:18  30.45
Data: 17:20  28.12
Data: 18:20  26.98
Data: 19:35  24.12

Data entry complete:
Head: 0x102800BB0, Tail: 0x102800C90, Size: 8
Temp: 0x102800BB0: 12:29  26.34
Temp: 0x102800BD0: 13:32  28.23
Temp: 0x102800BF0: 14:20  28.56
Temp: 0x102800C10: 15:30  29.10
Temp: 0x102800C30: 16:18  30.45
Temp: 0x102800C50: 17:20  28.12
Temp: 0x102800C70: 18:20  26.98
Temp: 0x102800C90: 19:35  24.12

Код

#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct tempdata tempdata;

struct tempdata
{
    int       hour;
    int       min;
    float     temp;
    tempdata *next;
    tempdata *prev;
};

typedef struct templist templist;

struct templist
{
    tempdata *head;
    tempdata *tail;
    int size;
};

static void add_to_list(templist *list, tempdata *new_temp)
{
    assert(list != 0);
    assert(list->size >= 0);
    assert((list->head == 0 && list->tail == 0 && list->size == 0) ||
           (list->head != 0 && list->tail != 0 && list->size != 0));
    new_temp->prev = list->tail;
    new_temp->next = 0;
    list->size++;
    if (list->head == 0)
        list->head = new_temp;          /* New list */
    else
        list->tail->next = new_temp;    /* Add to tail of list */
    list->tail = new_temp;
}

static void print_temp(const tempdata *data)
{
    printf("%d:%d %6.2f\n", data->hour, data->min, data->temp);
}

static void print_list(const templist *list)
{
    const tempdata *data;
    assert(list != 0);
    assert(list->size >= 0);
    assert((list->head == 0 && list->tail == 0 && list->size == 0) ||
           (list->head != 0 && list->tail != 0 && list->size != 0));
    printf("Head: 0x%" PRIXPTR ", Tail: 0x%" PRIXPTR ", Size: %d\n",
            (uintptr_t)list->head, (uintptr_t)list->tail, list->size);
    for (data = list->head; data != 0; data = data->next)
    {
        printf("Temp: 0x%" PRIXPTR ": ", (uintptr_t)data);
        print_temp(data);
    }
}

int main(int argc, char **argv)
{
    FILE *ifp;
    templist list = { NULL, NULL, 0 };
    char line[2048];

    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        return(EXIT_FAILURE);
    }

    ifp = fopen(argv[1], "r");

    if (ifp == 0)
    {
        fprintf(stderr, "%s: could not open file %s (%d: %s)\n", argv[0], argv[1], errno, strerror(errno));
        return(EXIT_FAILURE);
    }

    while (fgets(line, sizeof(line), ifp) != 0)
    {
        tempdata  temp_val;
        tempdata *new_temp;

        if (sscanf(line, "%d:%d %f", &temp_val.hour, &temp_val.min, &temp_val.temp) != 3)
        {
            fprintf(stderr, "%s: failed to scan line - %s", argv[0], line);
            return(EXIT_FAILURE);
        }
        printf("Data: ");
        print_temp(&temp_val);
        if ((new_temp = malloc(sizeof(*new_temp))) == 0)
        {
            fprintf(stderr, "%s: failed to allocate memory (%zu bytes)\n", argv[0], sizeof(*new_temp));
            return(EXIT_FAILURE);
        }
        new_temp->hour = temp_val.hour;
        new_temp->min  = temp_val.min;
        new_temp->temp = temp_val.temp;
        new_temp->next = 0;
        new_temp->prev = 0;
        add_to_list(&list, new_temp);
        /*print_list(&list);*/
    }
    fclose(ifp);

    printf("\nData entry complete:\n");

    print_list(&list);
    return(EXIT_SUCCESS);
}
person Jonathan Leffler    schedule 07.10.2012
comment
Да, массив определенно проще, но присваивание использует двусвязный список. Исправлен заголовочный файл. У меня возникают проблемы с тем, сканируют ли первый набор данных в элемент, а затем, находясь в цикле while, проходят через связанный список. Поэтому, вероятно, установка временных данных tempdata: tempdata *temporary, а затем установка первого элемента для этого, а в конце цикла while: временно->следующий = временный. Я думаю, что это заставит первый элемент (head) указывать на temp, а следующий элемент будет сканироваться как temp->next. Но я не уверен - person dwong; 07.10.2012