【问题标题】:Read 1 line per file descriptor using static nodes使用静态节点每个文件描述符读取 1 行
【发布时间】:2016-11-15 01:40:02
【问题描述】:

我正在尝试一次读取一行文件,具有不同的缓冲区长度。我将文件 desc 传递给 get_next_line 函数并将该行分配给指针。问题是当缓冲区长度很长时,有时它会打印文件的其余部分,当我传递 2 个不同的文件描述符时,我得到一个段错误。我认为这与将字符串保存在节点中并在 fd 相同时找到相同的节点有关。 我没有看到我在这里做错了什么。

get_next_line.c

#include "get_next_line.h"
#include <fcntl.h>
#include <stdio.h>

/*
 ** CREATE THE NEXT NODE TO ADD TO THE LINKEDLIST.
 **
 */
t_node *create_node(char *buffer, int fd)
{
    int i;
    t_node *new;

    i = 0;
    while (*buffer != '\n')
        buffer++;
    if (*buffer == EOF)
        return 0;
    ++buffer;
    new = malloc(sizeof(t_node));
    new->fd = fd;
    new->next = NULL;
    new->str = malloc(sizeof(char *));
    while (buffer[i] != '\n')
    {
        new->str[i] = (char)malloc(sizeof(char));
        new->str[i] = buffer[i];
        i++;
    }
    return (new);
}

/*
 ** SEARCH THE LIST FOR FD AND GET THE OVERFLAP STRING FROM
 ** LAST READ.
 */
char *get_overlap(t_node **root, int fd)
{
    t_node *conductor;

    if (*root == NULL)
        return (NULL);

    conductor = *root;
    while (conductor->fd != fd && conductor != 0)
        conductor = conductor->next;
    if (conductor == NULL)
        return (NULL);
    return (conductor->str);
}

/*
 ** CALL THE CREATE NODE FUNCTION AND ADD IT TO THE  LINKEDLIST.
 **
 */
void save_overlap(char buffer[], t_node **root, int fd)
{
    t_node **conductor;
    t_node *new;

    new = create_node(buffer, fd);
    if (*root == NULL)
        *root = new;
    else
    {
        conductor = root;
        while (*conductor != NULL)
        {
            if ((*conductor)->fd == fd)
            {
                (*conductor)->str = new->str;
                break;
            }
            if ((*conductor)->next == NULL)
            {
                (*conductor)->next = new;
                break;
            }
            *conductor = (*conductor)->next;
        }
    }
}

/*
 ** PREPEND THE PREVIOUS OVERLAP IN BUFFER TO LINE STRING.
 **
 */
void prepend_overlap(char *str, char ***line, int *i)
{
    int b = *i;
    while (str[b])
    {
        (**line)[b] = (char)malloc(sizeof(char));
        (**line)[b] = str[b];
        b++;
    }
    *i = b;
}


/*
 ** GET A SINGLE LINE AT A TIME FROM A FILE
 ** WHILE ALSO KEEPING TRACK OF THE FD.
 */
int get_next_line(const int fd, char **line)
{
    char buffer[BUFF_SIZE + 1];
    int i;
    int j;
    char *overlap_str;
    static t_node *root;

    i = 0;
    j = 0;
    overlap_str = get_overlap(&root, fd);
    if(overlap_str != NULL)
        prepend_overlap(overlap_str, &line, &i);
    read(fd, buffer, BUFF_SIZE);
    while (buffer[j] != '\n')
    {
        if (j == BUFF_SIZE)
        {
            (*line)[i] = (char)malloc(sizeof(char));
            (*line)[i] = buffer[j];
            j = 0;
            read(fd, buffer, BUFF_SIZE);
            continue;
        }
        (*line)[i] = (char)malloc(sizeof(char));
        (*line)[i] = buffer[j];
        i++;
        j++;
    }
    (*line)[i] = '\0';
    printf("%s\n", *line);
    save_overlap(buffer, &root, fd);
    return (0);
}

int main()
{
    int fd = open("test", O_RDONLY);
    //int fdt = open("test2", O_RDONLY);
    char *line;

    get_next_line(fd, &line);
    get_next_line(fd, &line);

}

get_next_line.h

#ifndef GET_NEXT_LINE_H
# define GET_NEXT_LINE_H

# define BUFF_SIZE 32
#include <fcntl.h>

int get_next_line(const int fd, char **line);

typedef struct s_node
{
    int fd;
    char *str;
    struct s_node *next;
}t_node;

#endif

它适用于单个文件描述符,例如,我可以只传递 fd 而不是 fdt,它会起作用,除非我将缓冲区大小设置为 120 或更大,例如,它会打印出我想要的更多。我只想要'\n'之前的那一行。

【问题讨论】:

    标签: c pointers linked-list file-descriptor


    【解决方案1】:
    new->str = malloc(sizeof(char *));
    ...
    new->str[i] = (char)malloc(sizeof(char));
    

    我不确定您要在这里做什么。 malloc(N * sizeof(char*)) 可用于创建指向“字符数组”的指针数组,大小为N。这基本上是“字符串数组”或“二维字符数组”。

    malloc(sizeof(char)) 只是malloc(1),或者只是一个字节。如果new-&gt;str 是一个字符数组,那么str[i] 已经是一个字节,不应该用malloc 设置

    这样做是为了分配一个字符数组:

    new->str = malloc(5);
    strcpy(new->str, "1234");
    

    这将为str分配5个字节,然后将“1234”复制到其中,并在末尾添加一个零,总共5个字节。

    你的链表也没有头。请尝试以下代码。

    #include <stdlib.h>//*** don't forget the right header files
    #include <stdio.h>
    #include <string.h>
    
    typedef struct s_node
    {
        char *str;
        struct s_node *next;
    }t_node;
    
    void insert_node(t_node** head, char* buf)
    {
        t_node *node = malloc(sizeof(t_node));
        node->next = 0;
    
        //allocate memory for string and copy
        node->str = malloc(strlen(buf) + 1); //+1 for nul-terminator
        strcpy(node->str, buf);
    
        if (*head == 0)
        {
            *head = node;
        }
        else
        {
            //find the end of the linked list
            t_node *tail = *head;
            while (tail->next)
                tail = tail->next;
    
            //make the end element point to new node
            tail->next = node;
        }
    }
    
    int main()
    {
        FILE *fd = fopen("test.txt", "r");
        if (!fd)
        {
            printf("file error\n");
            return 0;
        }
    
        //linked list identifier:
        t_node *head = 0;
    
        char buf[1000];
    
        //read the file line by line
        while(fscanf(fd, "%999s", buf) > 0)
        {
            //insert line in to linked list
            insert_node(&head, buf);
        }
    
        //show the result of the linked list:
        t_node *walk = head;
        while (walk)
        {
            printf("[%s]\n", walk->str);
            walk = walk->next;
        }
    
        return 0;
    }
    

    请注意,如果一行或多行的长度超过 1000 个字符,则上述代码将失败。您可以增加缓冲区长度,或者有一些方法可以解决这个问题,但我保留它是为了使示例简单。

    确保编译器警告级别为 4 或最高,并确保处理所有警告和错误。

    【讨论】:

    • 如果我用两个不同的 fd 调用 get_next_line 两次,我必须找到具有该 fd 的节点(如果存在)并替换 str。另外,我的最终解决方案应该有一个 main,除了文件描述符和 lline(string) 指针之外没有任何东西。
    • 看来你对我写的东西不感兴趣。而且你对编译器警告不感兴趣,上面写着“不要将void* 转换为char
    • 你使用什么编译器?您应该收到此演员表new-&gt;str[i] = (char)malloc(sizeof(char)) 的警告。按照我展示的方式使用malloc。您的链接列表也已损坏。
    • 我做到了,但这不是问题。您是否尝试过完全按照我的代码方式运行它,您更改了 main
    • 我试过你的代码,它在get_next_line 崩溃,这里是:(*line)[i] = (char)malloc(sizeof(char))。在其他地方,您的代码没有做任何事情,或者它只是错误的。一个链表必须有一个head。这不是可选的。我发布的代码中应该有一个head,比如t_node *head = 0;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多