Поиск строк с завершением NULL в файле, где они не завершаются NULL

Я пишу программу, которая открывает два файла для чтения: первый файл содержит 20 имен, которые я храню в массиве вида Names[0] = John\0. Второй файл представляет собой большой текстовый файл, содержащий множество вхождений каждого из 20 имен.

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

Вот мой цикл, который ищет и подсчитывает количество вхождений имени:

char LineOfText[85];
char *TempName;    

while(fgets(LineOfText, sizeof(LineOfText), fpn)){
    for(a = 0; a<NumOfNames; a++){
        TempName = strstr(LineOfText, Names[a]);
        if(TempName != NULL){
            Count++;
        }
    }
}

Что бы я ни делал, этот цикл не работает так, как я ожидал, но я обнаружил, что не так (я думаю!). Моя проблема в том, что каждое имя в массиве завершается NULL, но когда имя появляется в текстовом файле, оно не завершается NULL, если только оно не встречается как последнее слово строки. Таким образом, этот цикл while подсчитывает только количество появлений любого из имен в конце строки, а не количество появлений любого из имен в любом месте текстового файла. Как я могу настроить этот цикл для борьбы с этой проблемой?

Спасибо за любой совет заранее.


person KOB    schedule 05.05.2015    source источник
comment
со страницы руководства....The terminating null bytes ('\0') are not compared.   -  person Sourav Ghosh    schedule 05.05.2015
comment
Как насчет того, чтобы оставить нулевой терминатор вне сравнения?   -  person Uwe Allner    schedule 05.05.2015
comment
Или, может быть, strstr просто дает вам информацию, если в этой строке есть хотя бы один, а не фактическое число, поэтому вы увеличиваете только один раз для строки, содержащей John дважды   -  person Eregrith    schedule 05.05.2015
comment
а еще покажи нам Names[a]   -  person Sourav Ghosh    schedule 05.05.2015
comment
Вы пробовали его отлаживать? Например, с отладчиком или даже с отладкой printf?   -  person Jabberwocky    schedule 05.05.2015
comment
Я использовал отладчик printf. У меня есть еще одна переменная, в которой хранится номер строки, когда fgets перемещается по файлу. Я печатал этот номер строки каждый раз TempName != NULL, а затем просматривал каждую из этих строк в файле. Все они содержали имя в самом конце. Вот ссылка на текстовый файл, чтобы вы могли увидеть, как он отформатирован: drive.google.com/file/d/0B7qDUDai7YloOU9lQlA1QTNqOHM/   -  person KOB    schedule 05.05.2015


Ответы (2)


Проблема здесь, вероятно, в том, что вы используете fgets, который не обрезает новую строку из строки, которую он читает.

Если вы создаете свой массив names, читая строки с fgets, то все имена будут заканчиваться символом новой строки. Строки в файле, который читается с помощью fgets, также будут заканчиваться символом новой строки, поэтому имена будут совпадать только в конце строк.

strstr по понятным причинам не сравнивает байт NUL, который завершает строку шаблона. Если бы это было так, то он бы соответствовал только строкам суффиксов, что сделало бы его совершенно другой функцией.

Кроме того, вы найдете не более одного экземпляра каждого имени в каждой строке. Если вы считаете, что имя может появляться более одного раза в одной строке, вы должны заменить:

 TempName = strstr(LineOfText, Names[a]);
 if(TempName != NULL){
    Count++;
 }

с чем-то вроде:

 for (TempName = LineOfText;
      (TempName = strstr(TempName, Names[a]);
     ++Count, ++TempName) {
 }

Для справки, вот определение fgets из стандарта C (выделение добавлено):

Функция fgets считывает максимум на один символ меньше, чем количество символов, указанное n, из потока, на который указывает stream, в массив, на который указывает s. Никакие дополнительные символы не читаются после символа новой строки (который сохраняется) или после конца файла. Нулевой символ записывается сразу после последнего символа, считанного в массив.

Это отличается от gets, который не сохраняет символ новой строки.

person rici    schedule 05.05.2015
comment
Это звучит разумно. - person Jabberwocky; 05.05.2015

Я думаю, что NULL-завершение массива имен не является проблемой (см. справочник по функциям strstr ). Функция strstr не будет сравнивать терминатор. У вас есть возможность пропустить дополнительные имена в каждой строке. См. приведенную ниже настройку для примера того, как можно подсчитать несколько имен в каждой строке.

char LineOfText[85];
char *TempName;    

while(fgets(LineOfText, sizeof(LineOfText), fpn)){
    for(a = 0; a<NumOfNames; a++){
        TempName = strstr(LineOfText, Names[a]);

        /* Iterate through line for multiple occurrences of each name */
        while(TempName != NULL){
            Count++;

            /* Get next occurrence of name on line. fgets is going to
               leave a newline at the end of the LineOfText string so
               unless some of your names contain a newline, it shouldn't
               move past the end of the buffer */
            TempName = strstr(TempName + 1, Names[a]);
        }
    }
}
person Cole Cameron    schedule 05.05.2015