简体   繁体   English

如何使用 strtok() 和 getline() 将文件的行读入链表?

[英]How can I use strtok() and getline() to read the lines of a file into a linked list?

#define _GNU_SOURCE

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

struct node {
     char *name;
     struct node *next;
};

typedef struct node LINK;
struct node *head;
head = NULL;

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

    // struct node *head, *current;
    //open the file
    int size;

    //for the strtok()
    const char space[1] = " ";
    //char *name;
    char *code;
    
    
    //for the getline()
    char *line;
    line = (char *)malloc(size);
    
    //number of characters in each line of file
    int oneline;
    
    
    FILE *fO;
    fO = fopen("hw5.data", "r");

    //check if file is not opening
    if(fO == NULL){
        printf("********************************************\n"); 
        printf("You must include a filename to load.\n");
        printf("********************************************\n");
    }

    
    //read the file data into the linked list
    int x = 0;
    while(getline(&line, &size, fO) != -1){
        char *name = strtok(line, " ");
        strtok(NULL, " ");
        printf("Here is the name %s \n", name); 

        name = strtok(NULL, " ");
        printf("here's the code for name %s\n", name);

        x++;
        free(name);
    }

    free(line);
    //free(name);
    return 0;
}

I need to use strtok() and getline() to read a file with a format of a name, 1 space and a single character per line like "Edward a" or "Bella d".我需要使用strtok()getline()来读取格式为名称、1 个空格和每行一个字符的文件,例如“Edward a”或“Bella d”。 This program returns:该程序返回:

Heres the name Edward
here's the code for name (null)

instead of "(null)" I was hoping it would return 'a'.而不是“(null)”我希望它会返回'a'。

I have read the man page for strtok() and getline() ;我已经阅读了strtok()getline()的手册页; I am still confused about it.我仍然对此感到困惑。 Does anyone know what the problem is?有谁知道问题出在哪里? Sorry, I'm just required to use strtok() and getline() .抱歉,我只需要使用strtok()getline()


Here is the function I was talking about actually, I was trying to sort the linked list of strings with the strcmp(), to accordingly place the new string into the linked list.这是我实际上正在谈论的 function,我试图用 strcmp() 对字符串的链接列表进行排序,以相应地将新字符串放入链接列表中。 If the LinkedList was empty then Edward could be added.如果 LinkedList 为空,则可以添加 Edward。 Otherwise, I tried to compare the input char name[] to the existing strings to put it in its place in ascending order.否则,我尝试将输入的 char name[] 与现有字符串进行比较,以将其按升序放置到位。

//function to search list
int LIST_SEARCH(char name[], LINK *head) {
    LINK *current;
    current = head;
    while (current != NULL) {
       if (!strcmp(current->name, name)){
           current = current->next;
           printf(" here it is 1.\n");
           printf("\n");
           return 1;
       }
       
   }
   printf("Did not find it.\n");
   printf("\n");

   return 0;                        
}

LINK *LIST_INSERT(char name[], LINK *head) {
    LINK *current, *temp1;
    if (LIST_SEARCH(name, head) == 1){
        return head;
    }   
    
    temp1 = (LINK *)malloc(sizeof(LINK));
    strcpy(temp1->name, name);

    //test if the list is empty.
    if (head == NULL) {
        printf("empty\n");
        head = temp1; 
        temp1->next = NULL;
        return head;  
    } 
    
    //add the string to front of the list
    current = head;
    if(strcmp(current->name, name) > 0){
        printf("add name to front: %s\n", name);
        temp1->next  = current;
        head = temp1;
        return head;  
    } 
    //put the string at the back or middle of list
    current = head;
    while (current != NULL) {

       if (current->next == NULL || strcmp(current->next->name, name) > 0){
           printf("add name elsewhere: %s\n", name);
           temp1->next    = current->next;
           current->next = temp1;
           return head;  
       }
        //iterate 
       current = current->next;
    }
}

The function seemed to have added the first name. function好像加了名字。 However, for the rest of the names, it does not execute the print statements and the program does not finish.但是对于rest这个名字,它并没有执行打印语句,程序也没有结束。 It does not give errors either.它也不会给出错误。

You have the code:你有代码:

char *name = strtok(line, " ");
strtok(NULL, " ");

You can't afford to discard the result of the second call to strtok() like that — it contains the pointer to the code.您不能像那样丢弃第二次调用strtok()的结果——它包含指向代码的指针。 Remove that line!删除那条线!

There are other problems too.还有其他问题。 You don't initialize size ;你没有初始化size it should be of type size_t anyway.无论如何,它应该是size_t类型。 You have unused extraneous code in the question too.您在问题中也有未使用的无关代码。 You check whether the file was opened (though the message is a bit odd);您检查文件是否已打开(尽管消息有点奇怪); that's good.那挺好的。 However, you continue to use the unopened file;但是,您继续使用未打开的文件; that's bad.那很糟。 You should report the error on standard error, not standard output. It would be good to include the file name in the message.您应该在标准错误上报告错误,而不是标准错误 output。最好在消息中包含文件名。 It would be a good idea to zap the newline after reading the line.阅读该行后切换换行符是个好主意。 You should not call free(name) .你不应该打电话给free(name) The space allocated by getline() is pointed at by line , and you should (and do) call free(line) when the input loop completes. getline()分配的空间由line指向,您应该(并且确实)在输入循环完成时调用free(line) The value returned by strtok() should not be freed; strtok()返回的值不应该被释放; it does not allocate space, and the pointer returned is not guaranteed to the pointer returned by malloc() .它不分配空间,并且返回的指针不保证为malloc()返回的指针。

Here's working code:这是工作代码:

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

int main(void)
{
    size_t size = 0;
    char *line = 0;
    const char *filename = "hw5.data";
    FILE *fO = fopen(filename, "r");

    if (fO == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        exit(EXIT_FAILURE);
    }

    while (getline(&line, &size, fO) != -1)
    {
        line[strcspn(line, "\n\r")] = '\0';
        char *name = strtok(line, " ");
        char *code = strtok(NULL, " ");
        printf("Here is the name '%s'\n", name);
        printf("here's the code for name '%s'\n", code);
    }

    free(line);
    return 0;
}

For the described input, it yields:对于所描述的输入,它产生:

Here is the name 'Edward'
here's the code for name 'a'
Here is the name 'Bella'
here's the code for name 'd'

Note that when you get around to adding the data to your linked list, you'll need to duplicate the strings found — use strdup() .请注意,当您开始将数据添加到链接列表时,您需要复制找到的字符串 — 使用strdup()


Here is some code which creates, prints and releases a linked list using strdup() to copy the name.下面是一些代码,它使用strdup()复制名称来创建、打印和发布链表。 Since the structure in the question has no place for storing the code, the code is printed while reading the data but otherwise ignored.由于问题中的结构没有存储代码的地方,因此在读取数据时会打印代码,否则会被忽略。 Note that I renamed the structure tag to Node , and used the tag as the typedef name too.请注意,我将结构标记重命名为Node ,并将该标记也用作 typedef 名称。 Also, note that there are no global (file scope) variables;另外,请注意没有全局(文件范围)变量; you should avoid them as often as possible, which is most of the time.您应该尽可能多地避免使用它们,这是大多数时候。

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

typedef struct Node Node;
struct Node
{
    char *name;
    Node *next;
};

static Node *new_node(Node *head, const char *name)
{
    Node *np = malloc(sizeof(*np));
    if (np == NULL)
    {
        fprintf(stderr, "Failed to allocate %zu bytes of memory\n", sizeof(*np));
        exit(EXIT_FAILURE);
    }
    np->name = strdup(name);
    if (np->name == NULL)
    {
        fprintf(stderr, "Failed to allocate %zu bytes of memory\n", strlen(name) + 1);
        exit(EXIT_FAILURE);
    }
    np->next = head;
    return np;
}

static void print_list(const Node *head)
{
    const Node *curr = head;
    size_t count = 0;
    while (curr != NULL)
    {
        printf("%zu: [%s]\n", ++count, curr->name);
        curr = curr->next;
    }
}

static void free_list(Node *head)
{
    Node *curr = head;
    while (curr != NULL)
    {
        Node *next = curr->next;
        free(curr->name);
        free(curr);
        curr = next;
    }
}

int main(void)
{
    const char *filename = "hw5.data";
    FILE *fO = fopen(filename, "r");

    if (fO == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        exit(EXIT_FAILURE);
    }

    Node *head = NULL;

    size_t size = 0;
    char *line = NULL;
    while (getline(&line, &size, fO) != -1)
    {
        line[strcspn(line, "\n\r")] = '\0';
        char *name = strtok(line, " ");
        char *code = strtok(NULL, " ");
        printf("Here is the name '%s'\n", name);
        printf("Here is the code '%s'\n", code);
        head = new_node(head, name);
    }
    free(line);

    print_list(head);
    free_list(head);

    return 0;
}

I used this as the data file hw5.data :我将其用作数据文件hw5.data

Edward a
Bella d
Jacob a
Renesmee b
Jasper c
Rosalie b
Alice a
Carlisle a

The output from the program is then:程序中的 output 是:

Here is the name 'Edward'
Here is the code 'a'
Here is the name 'Bella'
Here is the code 'd'
Here is the name 'Jacob'
Here is the code 'a'
Here is the name 'Renesmee'
Here is the code 'b'
Here is the name 'Jasper'
Here is the code 'c'
Here is the name 'Rosalie'
Here is the code 'b'
Here is the name 'Alice'
Here is the code 'a'
Here is the name 'Carlisle'
Here is the code 'a'
1: [Carlisle]
2: [Alice]
3: [Rosalie]
4: [Jasper]
5: [Renesmee]
6: [Jacob]
7: [Bella]
8: [Edward]

I use quotes and square brackets around the names to demonstrate that there are no extraneous characters.我在名称周围使用引号和方括号来证明没有多余的字符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM