Почему эта печать является предыдущим выводом? - PullRequest
0 голосов
/ 07 апреля 2019

Я работаю над реализацией команды 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 голосов
/ 07 апреля 2019

В хорошей традиции названия этого сайта, я подозреваю, что вы перезаписываете стек. Когда вы выделяете память с помощью malloc (), она неинициализируется, что означает, что она может содержать что угодно. В результате, когда вы делаете strcat (content, buffer), он будет добавлять содержимое buffer [] после последнего ненулевого символа в content [], но нет способа узнать, где будет последний ненулевой символ быть. Это может легко быть за пределами последнего байта содержимого []. Добро пожаловать в мир C.

Если подумать, содержимое [] находится в куче, так что вам не придется перезаписывать стек в конце концов, но я оставляю текст здесь, потому что вам действительно нужно исправить их так, как вы работаете с контентом [].

Есть другие проблемы с этим кодом, возможно, потому что вы привыкли работать на других языках. Например, printf (content) не очень хорошая идея, потому что первый аргумент printf () интерпретируется как строка формата. Если данные в файле содержат что-то вроде «% X», где X - спецификатор формата printf, printf () интерпретирует его как часть языка форматирования. Это может привести к сбою, а также является распространенным источником уязвимостей безопасности, поскольку тот, кто обрабатывает ввод, может использовать спецификаторы формата для чтения / записи произвольных мест в памяти.

Обычно в C странное или недетерминированное поведение связано с ошибками обработки памяти. Возможно, вы захотите установить инструмент valgrind, который поможет вам найти такие вещи.

Также я не понимаю, почему вы просматриваете весь контент malloc / strcat / memset / free с контентом []. Было бы проще просто напечатать буфер [] напрямую, но, возможно, у вас есть планы на будущее, что вы хотите сделать с данными?

0 голосов
/ 07 апреля 2019

Ваш код ожидает «-» в качестве аргумента

if (*argv[i] == '-'){
  readStdin();
  clearerr(stdin);
}

Ваша программа вызывает readStdin() только когда получает «-» в качестве аргумента и в противном случае выводит файл аргумента.

Когда вы передаете - file1.txt - file2.txt -, это 5 аргументов (6, включая имя программы), говорящих вашей программе «чтение, вывод file1.txt, чтение, вывод file2.txt, чтение»
Таким образом, когда вы удаляете первое -, вы также удаляете первое «чтение», и вместо этого вы указываете своей программе «выводить file1.txt, читать, выводить файл2.txt, читать»

...