如何从C中的只读FIFO读取一行?

时间:2013-11-09 17:10:20

标签: c fifo

我从只读FIFO读取几行时遇到问题。特别是,我必须阅读两行 - 一个数字n,然后是\n和一个字符串str - 我的C程序应该写一个str只有n次的FIFO。这是我的尝试。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

char *readline(int fd);

int main(int  argc, char** argv) {
    int in = open(argv[1], O_RDONLY);
    mkfifo(argv[2], 0666);
    int out = open(argv[2] ,O_WRONLY);
    char *line = (char *) malloc(50);
    int n;

    while (1) {
        sscanf(readline(in), "%d", &n);
        strcpy(line, readline(in));

        int i;
        for (i = 0; i < n; i++) {
            write(out, line, strlen(line));
            write(out, "\n", 1);
        }
    }

    close(in);
    close(out);
    return 0;
}

char *readline(int fd) {
    char *c = (char *) malloc(1);
    char line[50];

    while (read(fd, c, 1) != 0) {
        if (strcmp(c, "\n") == 0) { 
            break;
        }
        strcat(line, c);
    }
    return line;
}

代码工作正常,但在最后一次重复字符串后,它会随机放置一些新行。此外,此数字在每次执行时都会更改。

有人可以帮我一下吗?

3 个答案:

答案 0 :(得分:1)

除了明智地阅读字符并使用“字符串”比较比较两个字符的事实之外,两者都远没有效率,readline()返回指向readline()本地声明的内存的指针,即{ {1}}只要line[50]返回就会释放内存,因此之后访问它会调用undefine行为。

解决这个问题的一种可能性是声明缓冲区将行读入外部readline()并将引用传递给它,如下所示:

readline()

然后像这样称呼它:

char * readline(int fd, char * line, size_t size) 
{
  if ((NULL != line) && (0 < size))
  {
    char c = 0;
    size_t i = 0;
    while (read(fd, &c, 1) >0) 
    {
      if ('\n' == c) or (size < i) { 
        break;
      }
      line[i] = c;
      ++i;
    }
    line [i] = 0;
  }

  return line;
}

答案 1 :(得分:0)

我没有尝试运行您的代码,但在readline函数中,您没有使用null(line)字符终止'\0'。一旦你点击'\n'字符,你就会打破while循环并返回字符串line。在从函数'\0'返回之前尝试添加readline字符。

点击here了解详情。

答案 2 :(得分:-1)

你的代码在我的机器上不起作用,我说你很幸运能得到任何有意义的结果。

以下是一些需要考虑的问题:

  • readline返回一个本地定义的静态字符缓冲区(line),当函数结束时它将被销毁,它曾经占用的内存可以被其他操作覆盖。
  • 如果line在分配时未设置为空字节,strcat会将其垃圾值视为字符,并可能在其结束后尝试写入。
  • 我怀疑你分配一个1字节的缓冲区(c)只是因为你需要read中的char *。这是不必要的(参见下面的代码)。更糟糕的是,你不会在readline退出之前解除分配,所以它会泄漏内存。
  • while(1)循环将重新读取文件并将其重新打印到输出fifo,直到时间结束。
  • 你正在使用一些“重型火炮” - 即strcat和记忆分配 - 这里有更简单的方法。
  • 最后,某些C标准版本可能要求您在使用之前声明所有变量。见this question

以下是我修改代码的方法。请注意,如果第二行超过50个字符,则此代码也可能表现不佳。缓冲区限制有一些技术,但我在这个例子中没有使用任何技术:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

char *readline(int fd, char * buffer);

int main(int  argc, char** argv) {
    int in = open(argv[1], O_RDONLY);
    int out;
    int n;
    int i;
    char line[50];

    memset(line, 0, 50);
    mkfifo(argv[2], 0666);
    out = open(argv[2] ,O_WRONLY);

    sscanf(readline(in, line), "%d", &n);
    strcpy(line, readline(in, line));

    for (i = 0; i < n; i++) {
        write(out, line, strlen(line));
        write(out, "\n", 1);
    }

    close(in);
    close(out);
    return 0;
}

char *readline(int fd, char * buffer) {
    char c;
    int counter = 0;
    while (read(fd, &c, 1) != 0) {
        if (c == '\n') {
            break;
        }
        buffer[counter++] = c;
    }
    return buffer;
}

如您所述,这可以在我的盒子上使用。用GCC 4.8.2编译。