Подсчет строк и аберрантные результаты - PullRequest
1 голос
/ 05 мая 2011

Я пишу утилиту для подсчета строк в данном файле через командную строку Unix. Обычно это было бы очень просто для меня, но, видимо, у меня был большой выходной. Цель этой программы - взять неизвестное количество файлов из командной строки, прочитать их в буфер и проверить наличие символа новой строки. Звучит просто?

int size= 4096;

int main(int argc, char *argv[]){
  int fd, i, j, c, fileLines, totalLines;
  char *buf= (char *)malloc(size); //read buffer

  for (i=2; i<argc; i++){ //get first file

    fileLines=1;    

    if ((fd=open(argv[i], O_RDONLY))!= -1){ //open, read, print file count, close
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){
                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;
    close(fd);

  }

  printf("%d lines were counted overall\n", totalLines);    
  return 0;
}

У меня две проблемы. Первый заключается в том, что первый оператор printf никогда не выполняется вне отладчика. Во-вторых, распечатка totalLines должна быть примерно 175K строк, но напечатанное значение примерно в 767 раз больше.

У меня возникают проблемы с пониманием этого, потому что все соответствующие переменные были объявлены вне области их изменения, но это все еще не объясняет, почему первое обновление состояния печати и счетчика строк игнорируется вне отладчика вместе с абсолютный результат totalLines

Любая помощь приветствуется.

1011 * ОТВЕТ *

Были предложены два изменения.
Первым было изменить j<size на j<c. Хотя это решение не требуется, оно следует хорошему соглашению о кодировании

Второй должен был изменить i=2 на i=1. Причиной, по которой у меня была исходная переменная start, был способ запуска исполняемого файла отладчика В командной строке GDB я ввел run lc1 f1.txt, чтобы запустить отладчик. Это привело к тому, что arglist имел три переменные, и я не знал, что run f1.txt идеально подходит, так как мой профессор познакомил нас с GDB с помощью первого примера.

Ответы [ 6 ]

3 голосов
/ 05 мая 2011

Вы не инициализируете totalLines.Вы увеличиваете его внутри цикла, но не устанавливаете его в 0 при первом объявлении.

Кроме того, почему вы начинаете с i=2?Это третий аргумент командной строки и второй параметр вашей программы.Это то, что вы намеревались, или вы хотели начать с первого параметра вашей программы?

И, как уже отмечали другие, вы должны иметь j < c вместо j < size.

2 голосов
/ 05 мая 2011

Ваш цикл неправильный.Это должно быть j=0; j<c; j++.Это, вероятно, не несет прямой ответственности за ошибки, которые вы видите, но определенно вызовет проблемы.

Вы пробовали пройти через код с помощью отладчика?

1 голос
/ 05 мая 2011

Во-первых, отличный вопрос.:) Весь необходимый код хорошо сформулирован, и очевидно, что вы сделали свою работу.:)

Как вы запускаете свою программу в отладчике?Я думаю, что отправная точка argv[2] может быть связана с не достижением printf(), но это будет зависеть от того, как вы начинаете.Подробнее см. Ниже.

Несколько комментариев:

int size= 4096;

Как правило, макросы препроцессора C используются для такого магического числа.Я знаю, что ваши учителя, вероятно, говорили, что никогда не используют препроцессор, но идиоматический C будет читать:

#define SIZE 4096
for (i=2; i<argc; i++){ //get first file

Попробуйте i=1 - argv[0] - это имяПрограмма, argv[1] будет первым аргументом командной строки - предположительно, если кто-то вызывает его через ./wc foo, вы хотите посчитать количество строк в файле foo.:) (Кроме того, вы хотите, чтобы цикл завершился. :) Конечно, если вы пытаетесь написать замену для wc -l, тогда ваш цикл в порядке, но не очень полезен, если кто-то облажает аргументы.Это можно безопасно сохранить как проект на будущее.(Если вам интересно, прочитайте справочную страницу getopt(3).:)

    if ((fd=open(argv[i], O_RDONLY))!= -1){
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){

Вы заканчиваете цикл на j<size - но вы читаете только c символов в последнем блоке,Вы читаете остатки мусора в последнем блоке.(Я не удивлюсь, если в /proc/ будут сгенерированы файлы, которые могут возвращать короткие чтения из-за удобства для программистов ядра.)

                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;

Это первый раз, когда вы назначаете totalLines.:) Может иметь начальное значение мусора.

    close(fd);

Возможно, вам следует переместить вызов close(fd); в блок if((fd=open()));если открытие не удалось, это вызовет close(-1);.Ничего страшного, но если вы проверяете возврат ошибки close(2) (всегда хорошая практика), она выдаст ненужную ошибку.

  }

Надеюсь, это поможет!

1 голос
/ 05 мая 2011

Обратите внимание: ./program file.txt

argv[0] is "program"
argv[1] is "file.txt"

, что означает, что ваш цикл for начинается с неверного индекса, и если вы пропускаете только 1 файл через строку cmd, ваш код никогда не будет введен в этот цикл!Он должен начинаться с индекса 1:

for (i=1; i<argc; i++){

Сделайте себе одолжение и инициализируйте все переменные при их объявлении.Это единственный способ убедиться, что в этих местах памяти не будет мусора.

0 голосов
/ 05 мая 2011

У вас есть логическая ошибка в цикле for (). Вы должны использовать «bytes read» вместо «read to», что я имею в виду в вашем коде, использовать «c» вместо «size» в for ()

0 голосов
/ 05 мая 2011

Вы, вероятно, знаете о wc , но я упомяну это на всякий случай.

Я знаю, что это не поможет вам напрямую отладить вашу конкретную проблему, но, возможно, выможет взглянуть на исходный код и / или использовать его, чтобы убедиться, что ваша программа работает.

...