为什么要打印以前的输出?

时间:2019-04-06 22:39:03

标签: c file-io stdin

我正在研究cat linux命令的实现。目前,当命令后没有传递任何参数时,它可以从标准输入中读取,并依次从多个文件中读取;但是当传递“-”作为参数时,它将打印先前的输出,而不是在某些情况下从标准输入中读取之前的输出。 。

例如,如果您传递-file1.txt-file2.txt-作为参数,那么一切都会按预期进行。它从标准输入中读取,输出file1.txt的内容,再次从stdin中读取,依此类推。但是,如果我删除了第一个'-',换句话说,如果第一个参数是文件,它将输出file1.txt的内容,然后从stdin读取,然后打印第二个文件的内容,然后而不是读取像以前一样从stdin中读取,第一次从stdin中读取时,它再次输出第二个文件的内容,然后输入内容,之后才开始正常运行。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1024

void readStdin(){
  char buffer[BUF_SIZE];
  while(fgets(buffer, BUF_SIZE, stdin)){ //reads from the standard input and prints the input
    char *content = malloc(sizeof(char*)*BUF_SIZE);
    if(content == NULL){ //failed to allocate memory
      exit(1);
    }
    strcat(content, buffer);
    //printf("buffer: %s", buffer);
    //printf("content: %s", content);
    printf(content);

    memset(&content[0], 0, sizeof(*content));
    free(content);

    //printf("bufferEND: %s", buffer);
    //printf("contentEND: %s", content);
  }
}

void readArgs(int argc, char* argv[]){
  FILE* fp;
  char ch;
  for (int i=1; i<argc; i++){
    if (*argv[i] == '-'){
      readStdin();
      clearerr(stdin);
    }

    //else if ()
    else {
      fp = fopen(argv[i], "r");
      if (fp==NULL){ //in case the file doesn't exist
        printf("%s: No such file or directory\n", argv[i]);
        exit(1);
      }
      while ((ch=fgetc(fp)) != EOF){
        putchar(ch);
      }
  //    fflush(stdin);

      fclose(fp);
    }
  }
}

int main(int argc, char* argv[]){
  if (argc<2){
    readStdin();
    return 0;
  }
  readArgs(argc, argv);
  return 0;
}

有任何提示吗?

编辑:如果我以上述错误的方式从stdin读取后,如果我传递另一个文件后接另一个'-',则它不仅表现出相同的特征,而且不打印先前输出的第一个字符

2 个答案:

答案 0 :(得分:0)

您的代码在这里以'-'作为参数

dls = "https://github.com/ItsMeLarry/Coursera_Capstone/raw/master/tl_2010_25 009_tract00.zip"
print('Downloading shapefile...')
r = requests.get(dls)
z = zipfile.ZipFile(io.BytesIO(r.content))
print("Done")
z.extractall(path='tmp/') # extract to folder
filenames = [y for y in sorted(z.namelist()) for ending in ['dbf', 
'prj', 'shp', 'shx'] if y.endswith(ending)] 
print(filenames)
dbf, prj, shp, shx = [filename for filename in filenames]
print(shp)
lynnmap = gpd.read_file(shp)

您的程序仅在接收到'-'作为参数时才调用if (*argv[i] == '-'){ readStdin(); clearerr(stdin); } ,否则将输出参数文件。

当您传递readStdin()时,这是5个参数(包括程序名称在内的6个参数)告诉您的程序“读取,输出file1.txt,读取,输出file2.txt,读取”
因此,当您删除第一个- file1.txt - file2.txt -时,您还将删除第一个“读取”,而是告诉程序“输出file1.txt,读取,输出file2.txt,读取”

答案 1 :(得分:0)

按照该站点名称的优良传统,我怀疑您正在覆盖堆栈。使用malloc()分配内存时,该内存未初始化,这意味着它可以包含任何内容。结果,当您执行strcat(content,buffer)时,它将在content []的最后一个非空字符之后附加buffer []的内容,但是无法知道最后一个非空字符将在哪里是。它很容易超出content []的最后一个字节。欢迎来到C的世界。

  

在反思时,content []在堆上,因此您毕竟不会覆盖堆栈,但是我将此处保留在此处,因为您确实应该按照使用content []的方式修复它们。

此代码还有其他一些问题,可能是因为您习惯于使用其他语言。例如,printf(content)不是一个好主意,因为printf()的第一个参数被解释为格式字符串。如果它们在文件中的数据包含“%X”之类的内容,其中X是printf格式说明符,则printf()会将其解释为其格式语言的一部分。这可能会导致崩溃,并且也是安全漏洞的常见来源,因为任何人编写输入内容的人都可以使用格式说明符来读取/写入内存中的任意位置。

通常在C语言中,奇怪的或不确定的行为是由于内存处理错误引起的。您可能需要安装“ valgrind”工具,该工具可以帮助您找到这些东西。

我也看不出为什么要遍历整个带有内容[]的malloc / strcat / memset / free。直接打印buffer []会更简单,但是也许您对数据的将来有一些计划?