Удовлетворяет ли эта небольшая C программа K & R? - PullRequest
5 голосов
/ 12 августа 2010

Я приступаю к упражнению K & R 1-18

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

Это то, что я до сих пор придумал

#include <stdio.h>

#define MAXLINE 1000

int getline(char line[], int maxline);
void copy(char to[], char from[]);

int main () {

    int len;
    char line[MAXLINE];

    while (getline(line, MAXLINE) > 0) {
            printf("%s", line);
    }
    return 0;
}


int getline(char s[], int lim) {
    int c, i, lastNonBlankIndex;
    lastNonBlankIndex = 0;

    for (i=0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {

        if (c != ' ' && c != '\t') {
            lastNonBlankIndex = i + 1;

        } 

        s[i] = c;
    }

    if (i != lastNonBlankIndex) {
        i = lastNonBlankIndex;
        c = '\n';
    }

    if (c == '\n') {
        s[i] = c;   
        ++i;
    }
    s[i] = '\0';
    return i;
}

Вторая часть звучала жестко, так как я не был уверен, что я должен вернуть, если в строке есть только пробелы или табуляции.В конце концов, если я верну 0, это остановит вызов getline().Будет ли это где я должен установить #define, такой как ALL_BLANKS.

В любом случае, к актуальному основному вопросу, является ли это правильным способом удаления конечных пробелов и табуляций из строк?Я пропустил несколько входов, и, похоже, сработало.Тем не менее, если я скопирую и вставлю текст с символами новой строки в CL, он все будет соединен.И когда я набираю строку в CL и нажимаю ввод, она автоматически печатает ее.Должен ли я создавать массив строк, а затем перебирать и печатать их, когда закончите?

Ответы [ 5 ]

5 голосов
/ 12 августа 2010

Ваш код выглядит правильно, но я думаю, что было бы лучше, если бы вы отделили операции чтения строки из stdin и удаления строки конечного пробела (развязки). Тогда вы можете использовать неизмененный getline из книги (повторное использование кода), и у вас не будет проблем с остановкой при возврате 0.

А если вас интересуют другие решения, в CLC-wiki есть почти полный список решений K & R2 .

#include <stdio.h>
#define MAXLINE 1024

int getline(char s[], int lim);

main()
{
    int i, len;
    char line[MAXLINE];

    while ((len = getline(line, MAXLINE)) > 0) {
        i = len - 2;
        while (i >= 0 && (line[i] == ' ' || line[i] == '\t'))
            --i;
        if (i >= 0) {
            line[i+1] = '\n';
            line[i+2] = '\0';
            printf("%s", line);
        }
    }
    return 0;
}

Это решение категории 1, которое я написал некоторое время назад. getline, как на странице 28 книги. Возможно, было бы лучше поместить удаление пробелов в отдельную функцию rstrip, но я оставляю это как упражнение для читателя.

0 голосов
/ 23 апреля 2015

Вот как я это сделал.

#include <stdio.h>
#define MAXLINE 1000

#define IN 1
#define OUT 0

int state = OUT;

int getline(char s[], int lim);
void copy(char to[], char from[]);

int main(void)
{
int lenght;
int max = 0;
char line[MAXLINE];
char longest[MAXLINE];

while ((lenght = getline(line, MAXLINE)) > 0)
    if (lenght > max)
    {
        max = lenght;
        copy(longest, line);
    }
if (max > 0)
    printf("\n%s\n", longest);

    return 0;

    }
   int getline(char s[], int lim)
   {
   int i, c;
   for (i = 0; i < lim - 1 && ((c = getchar()) != EOF) && (c != '\n'); i++)
   {


    if (state == IN && c != ' ' && c != '\t')
    {
        s[i] = ' ';
        i++;
        state = OUT;
    }
    if (s[0] == ' ')
    {
        s[0] = '\b';
    }


    s[i] = c;


    if (c == ' ' || c == '\t')
    {
        i--;
        state = IN;
    }
}
if (c == '\n')
{
    s[i] = c;
    i++;
}
s[i] = '\0';

return i;
 }

void copy(char to[], char from[])
{
int i = 0;
while ((to[i] = from[i]) != '\0')
    i++;
}
0 голосов
/ 12 августа 2010

getline должно возвращать -1 (отрицательное значение в целом), если есть ошибка или если достигнут EOF.Тогда ваш условный цикл может проверить, что он возвращает что-то >= 0 и по-прежнему допускает строки длины 0.

for (i=0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {

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

int i = 0;

while (i < lim) {
   c = getchar();
   if (c == EOF || c == '\n') {
       break;
   }
   line[i] = (char)c;
   i++;
}
line[i] = '\0'; // Null terminate the string

Этот код должен читаться в строке для вас.Я бы отделил чтение строки от удаления пробела.Вы можете очень легко работать в обратном направлении от конца строки, чтобы удалить пробелы в месте, где я завершил строку нулем, поскольку после прочтения строки вы теперь знаете ее длину.По сути, вы выращиваете нить, а затем обрезаете ее вниз после того, как она закончила расти.

0 голосов
/ 12 августа 2010
#include <stdio.h>

#define MAXLINE 1000

size_t getline(char *s,size_t lim)
{
  if( fgets(s,lim,stdin) )
  {
    while( *s && strchr(" \t\n",s[strlen(s)-1]) )
      s[strlen(s)-1]=0;
    return strlen(s);
  }
  return 0;
}

main()
{
    int len;
    char line[MAXLINE];

    while (getline(line,sizeof line)) {
            printf("%s", line);
    }
    return 0;
}
0 голосов
/ 12 августа 2010

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

ТамЭто небольшая проблема с вашим кодом: он не реализует вторую часть вопроса («удалить полностью пустую строку»).Это потому, что вы всегда ставите '\n' в конце строки.Это легко исправить, но помните, что вы должны возвращать ненулевое значение вызывающей стороне, поскольку пустая строка не указывает на конец файла.

...