3

プログラミングの勉強を始めたばかりです。これは私の最初の投稿です。Kernighan と Ritchie による「C プログラミング言語」という本を読んでいて、理解できない例に出くわしました (セクション 1.9、p 30)。

このプログラムは、テキストを入力として受け取り、最も長い行を決定して、それを出力します。Char 配列 line[MAXLINE] が宣言されています。MAXLINE は 1000 です。これは、この配列の最後の要素が MAXLINE-1 のインデックス (999) を持っていることを意味します。しかし、関数 getline を見ると、line[ が渡されています。 ] 配列を引数として (そして MAXLINE を lim として) 使用すると、ユーザー入力が MAXLINE よりも 1 行長い場合、i = lim、つまり i = MAXLINE になるまで i がインクリメントされるように見えます。したがって、ステートメント line[i] = '\0' は line[MAXLINE] = '\0' になります。

これは私には間違っているように見えます.line[]のサイズがMAXLINEの場合、line[MAXLINE]の場所にどのように書き込むことができますか. 配列の外側の場所に書き込んでいませんか?

私が思いつく唯一の説明は、char 配列 [サイズ] を宣言すると、C 言語が実際に char 配列 [サイズ + 1] 配列を作成し、最後の要素が NULL 文字用に予約されているということです。もしそうなら、これはかなり紛らわしく、本では言及されていません。誰でもこれを確認したり、何が起こっているのか説明できますか?

#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */
main()
{
    int len;                           /* current line length */
    int max;                          /* maximum length seen so far */
    char line[MAXLINE];          /* current input line */
    char longest[MAXLINE];     /* longest line saved here */

    max = 0;

    while ((len = getline(line, MAXLINE)) > 0)
           if (len > max) {
           max = len;
           copy(longest, line);
           }
    if (max > 0) /* there was a line */
           printf("%s", longest);

return 0;
}

/* getline: read a line into s, return length */
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;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
    int i;
    i = 0;

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

4 に答える 4

3

このforループは で読み取りを行っているようですgetline:

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

iに達するまでインクリメントされているように見えますがlim - 1、そうではありませんlim(あなたが話していた場合、limここでは に等しい)。MAXLINEしたがって、行が よりも長い場合MAXLINE、文字を読み取った後に停止し、期待どおりに最後にMAXLINE-1タックします。'\0'

于 2013-08-27T17:54:09.777 に答える
1

一般的な答え

割り当てられたメモリ外での読み取り/書き込みは未定義の動作です。

多くの場合、それは恐ろしいことにつながりSegmentation faultます。

場合によっては、完全に運が良ければ回避できることもあります (たとえば、アクセスした実際のメモリが物理的/論理的に存在し、それ以外では使用されていないため)。

簡単な答えは次のとおりです。これをしないでください!! 範囲外のメモリへのアクセスからコードを保護します。

n+1C は、実際にはバイトの割り当てのみを要求したときにバイトを割り当てるなど、魔法を行いませんn

あなたの具体例については

for (i=0; i < lim-1 /* ... */ ; ++i)

これは、が よりも小さいことを条件が確認するiため、実際には まで増加しません。したがって、到達するとすぐに(これは 内の有効なインデックスです)、ループを停止します。limilim-1lim-1s[]for

于 2013-08-27T17:54:02.827 に答える