Неочакван изход за K&R упражнение 1-18 (Езикът за програмиране C)

Аз съм доста нов в програмирането, така че моля, имайте търпение.

Ето подканата за упражнение 1-18: Напишете програма за премахване на завършващи празни места и раздели от всеки ред на въвеждане и за изтриване на изцяло празни редове.

И ето моят код:

#include <stdio.h>

#define MAXLINE 1000

int better_line_length(char line[], int lim);
void copy(char to[], char from[]);

int main(void)
{
    int len, a;
    char s[MAXLINE];
    char better_s[MAXLINE];

    while ((better_line_length(s, MAXLINE)) > 0) {
            copy(better_s, s);
            printf("%s\n", better_s);
        }

    return 0;
}

int better_line_length(char s[], int lim)
{
    int c, i, last_letter = 0;

    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {
        s[i] = c;
        if (c != ' ' && c != '\t')
            last_letter = i+1;
    }
    if (c == '\n' && s[0] == c)
        last_letter = 0;

    s[last_letter] = '\0';

    return last_letter;
}

void copy(char to[], char from[]) 
{
    int i = 0;

    while ((to[i] = from[i]) != '\0')
        ++i;
}

Моята програма не ми дава резултата, който очаквам. Той правилно премахва завършващите празни места и раздели при липса на празен ред, но нещата стават странни, когато има празен ред.

Например, ако въведеното ми е (където ▯▯▯ са интервали)

abcdefg▯▯▯▯▯▯▯▯▯▯▯▯
1234▯▯▯▯▯

Получавам очаквания резултат от

abcdefg
1234

Но ако моята информация е нещо подобно

abcdefg▯▯▯▯▯▯▯▯▯▯▯▯
1234▯▯▯▯▯

xyz▯▯▯▯▯▯
987▯▯▯▯▯

Получавам резултат от

abcdefg
1234

Но очаквам резултат от

abcdefg
1234
xyz
987

Изглежда като моят оператор while, while ((better_line_length(s, MAXLINE)) > 0) в main() спира да се изпълнява, когато срещне празен ред, вместо просто да го прескочи. Прекарах часове на това и все още не мога да разбера защо. Мислех, че настройката на better_line_length да връща 0, ако първият знак на ред е '\n' ще коригира кода, но това не променя нищо.

Защо срещам този неочакван изход и защо горната идея не коригира моята програма?

Моля, не забравяйте, че K&R не въвежда определени теми за напреднали до много след глава 1, така че указателите и някои други теми все още нямат смисъл за мен.

Благодаря!


person jhschwartz    schedule 23.11.2014    source източник


Отговори (2)


Виждам, че все още се опитвате да решите това упражнение. Браво на теб, не се предавай!

Що се отнася до проблемите с текущото ви решение: едно нещо, което можете да направите, е да промените функцията better_line_length(), за да върне нещо, което означава, че има празен ред и да пропуснете този ред в цикъла while ((len = better_line_length(s, MAXLINE)) > 0).

Например, можете да добавите следното в тялото на better_line_length(), точно след цикъла for:

if(i == 0 && c == '\n')
  return -1;

Тогава ще разберете, че това е линията, която трябва да пропуснете. Можете също така да добавите подобен код за връщане, което означава, че има край на файла/край на stdin.

Уведомете ме, ако имате нужда от още помощ.

person syntagma    schedule 23.11.2014
comment
Благодаря! Най-накрая го накарах да работи с ваша помощ, но не съм съвсем сигурен защо. Добавих вашето предложение след цикъла for и също така добавих условен оператор if (len > 0) { под моя while ((len = better_line_length(s, MAXLINE))) и програмата работи! Но не разбирам защо връщането на -1 работи, но връщането на 0 не. Тъй като цикълът изпълнява условието само когато better_line_length() е по-голямо от 0, не трябва ли да пропуска редове, когато функцията връща 0 или -1? - person jhschwartz; 24.11.2014
comment
Мисля, че не сте разбрали напълно while циклите. Изпълнява се, докато условието е вярно. Той само ще „пропусне“ редове, като прекрати цикъла и няма да обработва повече редове. - person Persixty; 24.11.2014
comment
Това, за което може да се объркате, е начинът, по който C обработва условията while/if: целите числа могат да се третират като булеви стойности: 0 (нула) винаги е невярно, а ненулевите (1, -1 и т.н.) винаги са верни. - person syntagma; 24.11.2014

Погледнете внимателно реда, който споменавате:

while ((better_line_length(s, MAXLINE)) > 0) {

Ако функцията better_line_length() върне 0, условието е невярно и цикълът завършва. Ето защо се отказва при първия празен ред.

Трябва да помислите за връщане на нещо различно, когато наистина сте достигнали края или просто празен ред.

Можете (например) да върнете -1, когато стигнете до края на въвеждането.

person Persixty    schedule 23.11.2014
comment
Но дори и да променя този ред на while (better_line_length(s, MAXLINE)) {, пак получавам същия резултат. - person jhschwartz; 24.11.2014
comment
Да, защото 0 е „false“, така че не сте променили нищо! Все още предлагам да върнете -1, ако прочетете EOF и дължината на реда е празна. След това използвате while ((better_line_length(s, MAXLINE))!=-1) { - person Persixty; 24.11.2014