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

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

return i;
}

この例は、C に関する K&R の本、配列に関する 1.9 章からのものです。私が理解していないのは、なぜ++i内部if声明を受け入れなければならないのですか? それを外側に書いても同じ仕事をするはずです。

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

プログラムを受け入れる場合はi意図したとおりに動作しますが、2番目のケース(私の意見では同じ動作をするはずであり、これがその部分を編集した理由です)では動作しません。デバッガーで実行しi、どちらの場合も正しく計算されて返されることを確認しました。しかし、プログラムは を受け入れないと機能しません++i。print fromprintfステートメントが表示されず、ターミナルまたは XTerm (CodeBlocks を使用) で Ctrl+D が機能しません。理由がわかりません。ヒントをお願いします。論理的なステップが欠けていますか?完全なコードは次のとおりです。

//Program that reads lines and prints the longest
/*----------------------------------------------------------------------------*/

#include <stdio.h>
#define MAXLINE 1000

int getline(char currentline[], int maxlinelenght);
void copy(char saveto[], char copyfrom[]);
/*----------------------------------------------------------------------------*/

int main(void)
{
    int len, max;
    char line[MAXLINE], longest[MAXLINE];

    max = 0;
    while( (len = getline(line, MAXLINE)) > 0 )
        if(len > max){
            max = len;
            copy(longest, line);
        }
    if(max > 0)
        printf("StrLength:%d\nString:%s", max, longest);

return 0;
}
/*----------------------------------------------------------------------------*/

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

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

return i;
}
/*----------------------------------------------------------------------------*/

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

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

5 に答える 5

2


if(c == '\n') は次と同等です
if(c != EOF)

それは抱擁が起こる理由を説明するのに役立ちますか?

于 2013-04-22T03:43:53.890 に答える
1

現在のインデックスに文字を配置しない場合はインクリメントしたくないため++i、ステートメント内にあります。その結果、入力の最後の文字と文字列の末尾の間にインデックスが残ります。ifi\n\0

于 2013-04-22T03:41:27.713 に答える
1

そこにはロジックがあります:

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

これは、追加の改行を読み取る場合にのみi、文字のスペースを確保するためにもう 1 つインクリメントする必要があることを意味します\0。ブロック++iの外側に置く場合。がなくても常に増加 するifことを意味します。この場合、は で既にインクリメントされているため、 のためのスペースが既にあるため、再び間違っています。の値を印刷して、それがどのように機能するかを確認できます。i1newline inputifor loop\0++ii

于 2013-04-22T03:41:46.877 に答える
1

で指定されたインデックスiは、行の入力がなくなったときに終端の null を配置する場所です。インデックスの直前の位置にiは、文字列内の最後の有効な文字が含まれています。

データを読み取るループは、文字stdinの読み取り以外の理由で終了する可能性があることに注意してください。\n

このコンストラクトがある場合:

if(c=='\n')
    s[i] = c;
++i;

次に、読み取った最後の文字がstdin改行でなかった場合は、事前にインクリメントされた の値で指定された場所に何も書き込まずに、インデックスを 1 つインクリメントしますi。結果に未指定の文字を効果的に追加することになります。

さらに悪いことに (?)、条件forのためにループi<lim-1が終了した場合、配列の指定された末尾の後に終端の null 文字を書き込むことになり、未定義の動作 (メモリの破損) が発生します。

于 2013-04-22T06:22:08.163 に答える
0

for ループは、次の 3 つの条件で終了する可能性があります。

最初のケースでは、文字列 s に Null を格納する必要があります。これは、i が最後に読み取られた有効な文字の次の位置を指しているため、i をインクリメントする必要がないためです。しかし、2 番目のケースでは、i は最後に読み取った有効な文字の次の位置を指しているため、その位置に改行を格納し、NULL 文字を格納するために i をインクリメントします。

そのため、1 番目のケースではなく 2 番目のケースで i をインクリメントする必要があります。

 if(c=='\n'){
            s[i] = c;
            ++i;
        }
于 2013-04-22T03:46:20.863 に答える