在' \ 0'之后打印新行。 C中的字符

时间:2015-10-15 05:45:39

标签: c

我正在进行一项任务,我们将重新创建cat命令的三个开关,-n / -T / -E。我们要编译并输入两个参数,即开关和文件名。我将文本文件内容存储到缓冲区中。

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

int index = 0;
int number = 1;
int fd, n, e, t;
n = e = t = 0;
char command[5];

char buffer[BUFFERSIZE];

strcpy(command, argv[1]);
fd = open(argv[2], O_RDONLY);
if( fd == -1)
{
    perror(argv[2]);
    exit(1);
}

read(fd, buffer,BUFFERSIZE);

if( !strcmp("cat", command)){
    printf("%s\n", buffer);
}
else if( !strcmp("-n", command)){
    n = 1;
}
else if( !strcmp("-E", command)){
    e = 1;
}
else if( !strcmp("-T", command)){
    t = 1;
}
else if( !strcmp("-nE", command) || !strcmp("-En", command)){
    n = e = 1;
}
else if( !strcmp("-nT", command) || !strcmp("-Tn", command)){
    n = t = 1;
}
else if( !strcmp("-ET", command) || !strcmp("-TE", command)){
    t = e = 1;
}
else if( !strcmp("-nET", command) || !strcmp("-nTE", command) || 
      !strcmp("-TnE", command) || !strcmp("-EnT", command) || 
      !strcmp("-ETn", command) || !strcmp("-TEn", command)){
    n = e = t = 1;
}
else{
    printf("Invalid Switch Entry");
}

if(n){
    printf("%d  ", number++); 
}

while(buffer[index++] != '\0' && ( n || e || t)){
    if(buffer[index] == '\n' && e && n){
        printf("$\n%d  ", number++);
    }
    else if(buffer[index] == '\n' && e){
        printf("$\n");
    }
    else if(buffer[index] == '\t' && t){
        printf("^I");
    }
    else if(buffer[index] == '\n' && n){
        printf("\n%d  ", number++);
    }
    else {
        printf("%c", buffer[index]);
    }
}
printf("\n");
close(fd);
return 0;

}

除非我尝试使用-n命令,否则一切都很完美。它增加了一条额外的新线。我使用的文本文件

hello

 hello

   hello world! 

而不是

1 hello

2  hello

3    hello world!

它将打印出来:

1 hello

2  hello

3    hello world!

4

由于某种原因,它增加了世界之后的额外线!

  

我错过了一些简单的东西吗?

2 个答案:

答案 0 :(得分:1)

这可能无法解决您的问题,但我没有看到任何代码将终止空字符放在buffer中。尝试:

// Reserve one character for the null terminator.
ssize_t n = read(fd, buffer, BUFFERSIZE-1);
if ( n == -1  )
{
   // Deal with error.
   printf("Unable to read the contents of the file.\n");
   exit(1); //???
}

buffer[n] = '\0';

答案 1 :(得分:0)

您实施的三个cat选项具有不同的"模式":

  • -T替换一个字符(没有写标签);
  • -E预先添加一个带有附加输出的字符(仍然会写入换行符);
  • -n在每行前面加上额外的输出。

您可以直接处理前两种模式。第三种模式需要来自该字符的信息:在文件开头和读取换行字符后开始一个新行。所以你需要一个标志来跟踪它。

(您的代码在找到换行符之后打印一个行号。这意味着您必须明确地处理第一行,并在结尾处获得一行太多的行。毕竟,一个带{的文件{1}}行包含n个换行符,您可以打印n行号。)

其他问题:

  • 正如R Sahu指出的那样,您的输入不会以空值终止。这里你真的不需要一个空终止符:n + 1返回读取的字节数或错误代码。您可以将该号码用作read
  • 的限制
  • 您在index条件中包含index,这意味着您在循环中检查的字符后面查看字符,这可能是空字符。您还将错过文件中的第一个字符。
  • 事实上,你不需要缓冲区。当文件大于缓冲区时,将截断它。您可以在循环中调用while,直到您读取的字节数少于read,但在这种情况下最简单的方法是读取另一个字节并处理它。
  • 您使用过多的复合条件。这本身并不错,但它会使代码变得复杂。当实际上只有少数特殊情况需要处理时,你的主循环读起来就像一个大的BUFFERSIZE
  • 确定标志的方式既复杂又过于严格。你可以查看所有标志组合,对于给出所有标志的情况,这是6。如果添加另一个标志怎么办?你打算再写24 switch吗?查找减号作为第一个字符,然后逐个字母,设置标记并打印错误消息。
  • 您不需要将strcmps复制到argv[1];你只是检查它。而且你引入了一个错误来源:如果第二个参数超过4个字符,你将得到未定义的行为,很可能是崩溃。
  • 如果您不提供任何选项,则文件名应为command,而不是argv[1]

将此(无解析标记)付诸实践:

argv[2]

修改:如果您只能使用Unix FILE *f = fopen(argv[2], "r"); int newline = 1; // marker for line numbers // Error checking for (;;) { int c = fgetc(f); // read one character if (c == EOF) break; // terminate loop on end of file if (newline) { if (n) printf("%5d ", number++); newline = 0; } if (c == '\n') { newline = 1; if (e) putchar('$'); } if (c == '\t' && t) { putchar('^'); putchar('I'); } else { putchar(c); } } fclose(f); openclose,您仍然可以使用上述方法。您需要一个额外的循环,使用read读取特定大小的块。 read函数返回读取的字节值。如果小于要求的字节数,请停止循环。

下面的示例添加了一个允许连接多个文件的附加循环。

read