将分隔的平面文件解析为双重链接的结构列表

时间:2017-09-27 21:41:30

标签: c

我试图编写一个C程序来读取一个文件,将输入标记为一个双向链表,并用它做一些事情,即:对它进行排序,走它,写它......等等。 p>

md@ubuntu:~/Documents/testproject$ cat test.txt
2017-07-25,14:50:02:477, 12104,932,HOST, log message 1111111111111111111111111111
2017-07-26,14:50:02:478, 12104,932,HOST, log message 22222222222222222222222222222222222222
2017-07-27,14:50:03:095, 12104,932,HOST, log message 3333333333333333
2017-07-28,14:50:04:587, 12104,932,HOST, log message 444444444444444444444444444444444444444444444
2017-07-29,14:50:04:587, 12104,932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr
junk to be parsed out
more junk 1234567

但是当我走过列表时,每个节点都包含最后一个条目。有什么迹象表明我在这里出错了吗?我在printf函数中添加了createnewnode(),似乎在struct节点中设置了正确的字符串。

md@ubuntu:~/Documents/testproject$ ./doubly test.txt
*****CREATE NODE*****(2017-07-25,14:50:02:477,932,HOST, log message 1111111111111111111111111111
*****CREATE NODE*****(2017-07-26,14:50:02:478,932,HOST, log message 22222222222222222222222222222222222222
*****CREATE NODE*****(2017-07-27,14:50:03:095,932,HOST, log message 3333333333333333
*****CREATE NODE*****(2017-07-28,14:50:04:587,932,HOST, log message 444444444444444444444444444444444444444444444
*****CREATE NODE*****(2017-07-29,14:50:04:587,932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr

*****PRINT LINKED LIST*****
0x557237b1a760 1986300429 2017-07-29 14:50:04:587 932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr
0x557237b1a720 1986300429 2017-07-29 14:50:04:587 932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr
0x557237b1a6e0 1986300429 2017-07-29 14:50:04:587 932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr
0x557237b1a6a0 1986300429 2017-07-29 14:50:04:587 932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr
0x557237b1a250 1986300429 2017-07-29 14:50:04:587 932,HOST, log message blah blah blahb 1234455e56456546 test test test ERrroRRRrrr$$4RRrr

代码:

/*
Parse a delimited log file and tokenized values in a doubly linked list. 
Do stuff with this doubly linked list of structures (ie: sort by time....etc)

*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h> 
#include <locale.h>
#include <errno.h>

#define __USE_XOPEN
#include <time.h> 
#include <sys/time.h>

#define LINESIZE 1024

//Linked List structure
struct node
{
    int jobid;   
    char* datestring;
    char* timestring;
    char* message;
    struct node *prev;  //previous node
    struct node *next; //next node 
};
typedef struct node node;

node *head = NULL;  //declar pointer beginning of linked list

//prototypes for linked list functions   
struct node* createnewnode(char* ds, char* ts, char* msg); //create a new node and return a pointer to it
void insert_at_head(char* ds, char* ts, char* msg);
void print_elements(); 
static void clean(); 
int parseFile(char* fname);
char **strsplit(const char* str, const char* delim, size_t* numtokens);
int lensum(char **input);


/* DOUBLY LINKED LISTS */


//Node Generator 
struct node* createnewnode(char* ds, char* ts, char* msg)
{
    node *newnode = malloc(sizeof(node));  //allocate memory on the heap and create a new node structure 

    //copy strings to local variables. Desperate hope to get this working, but probably not needed
    char tds[LINESIZE], tts[LINESIZE],tmsg[LINESIZE];

    strcpy(tds, ds); 
    strcpy(tts, ts); 
    strcpy(tmsg, msg); 

#ifdef DEBUG
    printf("*****CREATE NODE*****(%s,%s,%s\n",tds,tts,tmsg);
#endif  


    newnode->datestring = tds;
    newnode->timestring = tts;
    newnode->message = tmsg;

    srand(time(NULL));
    newnode->jobid = rand(); //set to random value to see if it changes between iterations

    newnode->prev = NULL;    
    newnode->next = NULL;   

    return newnode;
}


//Insert Node at the beginning of the list
void insert_at_head(char* ds, char* ts, char* msg)
{ 

    node *newnode = createnewnode(ds, ts, msg);

    //If this is the first element being added to the linked list 
    if (head == NULL)
    {
        head = newnode;
        return;
    }
    head->prev = newnode;
    newnode->next = head;
    head = newnode; 
}

//print_elements() in linked list from the head to the tail (end)
void print_elements() 
{
    node *ptmp = head; //beginning of the list 
    if (ptmp == NULL)
    {
        printf("Warning: No elements in this list\n");
        return;
    }

#ifdef DEBUG
    printf("\n*****PRINT LINKED LIST*****\n");
#endif

    while(ptmp != NULL)
    {
        printf("%p %d %s %s %s\n",ptmp, ptmp->jobid, ptmp->datestring, ptmp->timestring, ptmp->message );
        ptmp = ptmp->next; 
    }
    return; 
}


static void clean() 
{
    node *temp = NULL; 

    while(head != NULL) 
    {
        temp = head; 
        head = head->next; 
        free(temp);
    }
}



/* PARSE FILE */
int parseFile(char* fname)
{
    FILE *in = fopen(fname, "r");
    char line[LINESIZE];
    struct tm date;
    const char delim[] = ",";
    char *tok; 
    char dbuf[LINESIZE], tbuf[LINESIZE], mbuf[LINESIZE]; 

    while (fgets(line, sizeof(line), in) != NULL) {


     if ((void *)strptime(line,"%Y-%m-%d",&date) != NULL)
       {
           tok = strtok(line, delim);
           strcpy((char*)dbuf, tok);

           tok = strtok(NULL, delim);
           if (NULL != tok)
           {
                strcpy((char*)tbuf, tok);
                tok = strtok(NULL,delim);
           }
           tok = strtok(NULL,"\n"); 

           if (NULL != tok)
           {
                strcpy((char*)mbuf, tok);
           }

           insert_at_head(dbuf, tbuf, mbuf);

       }  

    }
    fclose(in); //close file pointer
    return 0;   
}



int main(int argc, char const *argv[])
{

    parseFile("test.txt"); 
    print_elements();   
    clean();         

    return 0;
}

1 个答案:

答案 0 :(得分:1)

您的错误在于函数struct node* createnewnode(char* ds, char* ts, char* msg)您在行

分配的内存
char tds[LINESIZE], tts[LINESIZE],tmsg[LINESIZE];

是函数的本地。离开函数时它会消失,所以后面的行

    newnode->datestring = tds;
    newnode->timestring = tts;
    newnode->message = tmsg;

不会做你想要的。

您可以在堆上保留一些内存,例如:

    //char tds[LINESIZE], tts[LINESIZE],tmsg[LINESIZE];

    char *tds = malloc(LINESIZE); // can be fixed if length is fixed
    char *tts = malloc(LINESIZE); // can be fixed if length is fixed
    char *tmsg = malloc(LINESIZE); // the message is probably variable, so measure it

但你必须在以后释放这段记忆。

或者通过更改struct例如:

来保留一些堆栈内存
struct node
{
   int jobid;   
   char datestring[100];
   char timestring[100];
   char message[256];
   struct node *prev;   //previous node
   struct node *next; //next node 
};

但是这会使struct的数量增加不小,而且灵活性会降低。例如,该消息可能需要超过256个字符。

或者使用混合方法并使用堆栈作为日期和时间字符串,如果它们总是具有相同的固定长度,则通过测量文件中条目的长度并相应地分配内存来获取消息的堆。清理时不要忘记释放堆内存!