Я все еще не уверен, почему вы хотите использовать scanf()
в main()
. Предположительно, это означало бы изменение интерфейса stemfile()
(включая имя, поскольку он больше не будет обрабатывать файл), чтобы в качестве входных данных принималась строка символов. И scanf()
усложнит жизнь; он будет читать строки, разделенные пробелами, которые могут быть частью его привлекательности, но он будет включать в себя любые знаки препинания, включенные в «слово».
Как заметил Рэндалл, код в существующей функции немного очевиден; Я думаю, что это может быть написано более просто следующим образом:
#include <stdio.h>
#include <ctype.h>
#define LETTER(x) isalpha(x)
extern int stem(char *s, int lo, int hi);
static void stemfile(FILE * f)
{
int ch;
while ((ch = getc(f)) != EOF)
{
if (LETTER(ch))
{
char s[1024];
int i = 0;
s[i++] = ch;
while ((ch = getc(f)) != EOF && LETTER(ch))
s[i++] = ch;
if (ch != EOF)
ungetc(ch, f);
s[i] = '\0';
s[stem(s, 0, i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("%s", s);
}
else
putchar(ch);
}
}
Я немного упростил вещи, превратив s
в простую локальную переменную (похоже, она была глобальной, как и imax
), удалив imax
и функцию increase_s()
. Они во многом связаны с функционированием функции.
Если вы хотите, чтобы вместо этого обрабатывалась строка с нулевым символом в конце, то:
static void stemstring(const char *src)
{
char ch;
while ((ch = *src++) != '\0')
{
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
if (ch != '\0')
src--;
s[i-1] = '\0';
s[stem(s,0,i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("%s",s);
}
else
putchar(ch);
}
}
Это систематически меняет getc(f)
на *src++
, EOF
на \0
и ungetc()
на src--
. Также (безопасно) изменяет тип ch
с int
(необходим для ввода / вывода) на char
. Если вы беспокоитесь о переполнении буфера, вам придется немного поработать в функции, но на практике немногие слова будут даже 1024 байта (и вы можете использовать 4096 так же легко, как 1024, с соответственно меньшим - бесконечно малым - шансом реальных данных) переполнение буфера. Вам необходимо определить, является ли это «реальным» риском для вас.
Основной программой может стать довольно просто:
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
Очевидно, что из-за '1023' в формате это никогда не будет переполнять внутренний буфер. (Примечание: в первой версии этого ответа удалено .
из "%.1023s"
; scanf()
отличается от printf()
!).
Вызов: это работает?
Да - этот код ниже (добавление фиктивной stem()
функции и незначительное изменение печати) работает для меня достаточно хорошо:
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#define LETTER(x) isalpha(x)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
static int stem(const char *s, int begin, int end)
{
assert(s != 0);
return MAX(end - begin - 3, 3);
}
static void stemstring(const char *src)
{
char ch;
while ((ch = *src++) != '\0')
{
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
if (ch != '\0')
src--;
s[i-1] = '\0';
s[stem(s,0,i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("<<%s>>\n",s);
}
else
putchar(ch);
}
putchar('\n');
}
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
Пример диалога
H: assda23
C: <<assd>>
C: 23
H: 3423///asdrrrf12312
C: 3423///<<asdr>>
C: 12312
H: 12//as//12
C: 12//<<a>>
C: //12
Строки, помеченные H:
, представляют собой вводимые человеком данные (H:
не был частью ввода); строки, помеченные C:
, являются выходными данными компьютера.
Следующая попытка
Проблема с концентрацией на гротескно длинных словах (1023 символа и более) состоит в том, что вы можете упустить простое. С scanf()
чтением данных вы автоматически получаете одиночные «слова» без пробелов в качестве ввода. Вот отлаженная версия stemstring()
с отладочным кодом печати на месте. Проблема была в двух ошибках. Один был в задании s[i-1] = '\0';
, где -1
не был нужен. Другой был в обработке конца цепочки писем; функция while ((ch = *src++) != '\0') left
src one place too far, which led to interesting effects with short words entered after long words (when the difference in length was 2 or more). There's a fairly detailed trace of the test case I devised, using words such as 'great' and 'book' which you diagnosed (correctly) as being mishandled. The
stem () `здесь просто печатает свои входы и выходы и возвращает всю длину строки (так что не происходит никаких основ).
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#define LETTER(x) isalpha(x)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
static int stem(const char *s, int begin, int end)
{
int len = end - begin + 1;
assert(s != 0);
printf("ST (%d,%d) <<%*.*s>> RV %d\n", begin, end, len, len, s, len);
// return MAX(end - begin - 3, 3);
return len;
}
static void stemstring(const char *src)
{
char ch;
printf("-->> stemstring: <<%s>>\n", src);
while ((ch = *src++) != '\0')
{
if (ch != '\0')
printf("LP <<%c%s>>\n", ch, src);
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
src--;
s[i] = '\0';
printf("RD (%d) <<%s>>\n", i, s);
s[stem(s, 0, i-1)+1] = '\0';
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("RS <<%s>>\n", s);
}
else
printf("NL <<%c>>\n", ch);
}
//putchar('\n');
printf("<<-- stemstring\n");
}
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
Отображается вывод с отладкой (первая строка - типизированный ввод; остальные - вывод программы):
what a great book this is! What.hast.thou.done?
-->> stemstring: <<what>>
LP <<what>>
RD (4) <<what>>
ST (0,3) <<what>> RV 4
RS <<what>>
<<-- stemstring
-->> stemstring: <<a>>
LP <<a>>
RD (1) <<a>>
ST (0,0) <<a>> RV 1
RS <<a>>
<<-- stemstring
-->> stemstring: <<great>>
LP <<great>>
RD (5) <<great>>
ST (0,4) <<great>> RV 5
RS <<great>>
<<-- stemstring
-->> stemstring: <<book>>
LP <<book>>
RD (4) <<book>>
ST (0,3) <<book>> RV 4
RS <<book>>
<<-- stemstring
-->> stemstring: <<this>>
LP <<this>>
RD (4) <<this>>
ST (0,3) <<this>> RV 4
RS <<this>>
<<-- stemstring
-->> stemstring: <<is!>>
LP <<is!>>
RD (2) <<is>>
ST (0,1) <<is>> RV 2
RS <<is>>
LP <<!>>
NL <<!>>
<<-- stemstring
-->> stemstring: <<What.hast.thou.done?>>
LP <<What.hast.thou.done?>>
RD (4) <<What>>
ST (0,3) <<What>> RV 4
RS <<What>>
LP <<.hast.thou.done?>>
NL <<.>>
LP <<hast.thou.done?>>
RD (4) <<hast>>
ST (0,3) <<hast>> RV 4
RS <<hast>>
LP <<.thou.done?>>
NL <<.>>
LP <<thou.done?>>
RD (4) <<thou>>
ST (0,3) <<thou>> RV 4
RS <<thou>>
LP <<.done?>>
NL <<.>>
LP <<done?>>
RD (4) <<done>>
ST (0,3) <<done>> RV 4
RS <<done>>
LP <<?>>
NL <<?>>
<<-- stemstring
Показанные методы - печать диагностической информации в ключевых точках программы - это один из способов отладки такой программы, как эта. Альтернативой является пошаговое выполнение кода с помощью отладчика исходного кода - gdb
или его эквивалента. Я, вероятно, чаще использую операторы печати, но я старый хрен, который считает IDE слишком сложным для использования (потому что они не ведут себя так, как я привык к командной строке).
Конечно, это уже не ваш код, но я думаю, что вы должны были выполнить большую часть отладки самостоятельно. Я благодарен, что вы сообщили о проблеме с моим кодом. Однако вам также необходимо научиться диагностировать проблемы в коде других людей; как его инструментировать; как охарактеризовать и найти проблемы. Затем вы можете сообщить о проблеме с точностью - «вы обидели ваше условие конца слова и ...».