количество символов с использованием C (несоответствие между cli-tools и моим файлом)

#c #bash

#c #bash

Вопрос:

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

 #include <stdio.h>
#include <time.h>

#define BUF 100

int main(){
        FILE *fp = fopen("my_huge_file.txt","r");
        char str[BUF];
        int count=0;
        while( (fgets(str, BUF, fp)) != NULL ){
                for (int i = 0; i<BUF;i  ){
                        if (str[i] == 'A')
                                count  ;
                }
        }

        printf("We had %d 'A'sn",count);

}
 

Запуск этого с помощью time ./a.out печати:

 We had 420538682 'A's

real  0m31.267s
user  0m28.590s
sys   0m2.531s
 

Затем я использовал time tr -cd A < my_huge_file.txt | wc -c и вернулся:

 420538233

real  0m13.611s
user  0m10.688s
sys   0m3.297s
 

Я также использовал метод подсчета python time count.py :

 c = 0
with open("my_huge_file.txt", 'r') as fp:
    for line in fp:
        c  = line.count('A')


print(c)
 
 420538233

real  0m33.073s
user  0m30.232s
sys   0m2.650s
 

Я не уверен, как расследовать это несоответствие. количество tr и python возвращает 420538233. Функция C возвращает 420538682.

Комментарии:

1. Вы используете fgets для чтения строки, но не соблюдаете границы строки при подсчете. В этой проблеме нет ничего ориентированного на строку. Вместо fgets этого используйте fgetc . Это упрощает логику и устраняет текущую ошибку.

Ответ №1:

Попробуйте изменить:

         for (int i = 0; i<BUF;i  ){
 

Для

     for (int i = 0; i<BUF amp;amp; str[i] ;i  ){
 

Посмотрите, получите ли вы другой результат….

Комментарии:

1. Это сработало! 420538233 Я предполагаю, что из предыдущих циклов for были добавлены непустые символы?

2. скорее всего; кроме того, обычно вы должны читать в буфер LINE_MAX (из limits.h).

Ответ №2:

Нет причин усложнять ваш код fgets . (Проблема, с которой вы сталкиваетесь, заключается в том, что fgets считывает строку и заполняет только часть вашего буфера, но вы считаете все в буфере, включая значения, которые не были получены из входных данных.) Просто считывайте по одному символу за раз:

 #include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
        int c;
        int count=0;
        FILE *fp = argc > 1 ? fopen(argv[1], "r") : stdin;
        if( fp == NULL ){
                perror(argv[1]);
                exit(EXIT_FAILURE);
        }
        while( (c = fgetc(fp)) != EOF ){
                if( c == 'A' ){
                        count  = 1;
                }
        }

        printf("We had %d 'A'sn", count);
        return 0;
}
 

Комментарии:

1. Спасибо! Разве fgets не будет буферизировать ввод-вывод и работать быстрее?

2. Оба fgets и fgetc буфер ввода-вывода. Такое же количество read системных вызовов будет (почти наверняка) выполнено. Если вас это беспокоит, используйте fread вместо этого. Но вряд ли это будет значительным улучшением. Вы getc также можете попробовать, но, опять же, разница вряд ли будет существенной.