Есть ли ошибка в примере кода в главе 1.9 классической книги «Язык программирования Си»?

В главе 1.9 классической книги Брайана и Денниса о языке C "Язык программирования C" есть кусок кода о функции getline, которая используется для копирования следующей строки входного текста в строку типа char. и проверьте перелив. Я цитирую код ниже:

int getline(char line[], int maxline);
int getline(char s[], int limit)
{
    int c,i;
    for (i=0; i<limit-1 && (c=getchar())!=EOF && c!='\n'; ++i) /* ** */
        s[i]=c;
    if (c == '\n') {
        s[i]=c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

Вот проблема: параметр limit — это максимальная длина строки, поэтому массив s[] может содержать только набор элементов от s[0] до s[limit-1]. Если последним символом переменной c для getchar() является '\n', а индекс этого символа равен limit-1, то часть оценки в цикле for не будет выполнена из-за 'i==limit-1', но не 'c!='\n' (в порядке слева направо). Далее, если предложение будет работать из-за 'c=='\n'', тогда s[limit-1]=c, тогда ++i установит значение i в limit. s[i]='\0' будет переполнено, потому что s[limit] превышает лимит строки. Верен ли мой анализ или нет? Спасибо за любые полезные ответы.


person microbit    schedule 08.08.2014    source источник
comment
Если последним символом переменной c для getchar() является '\n', а индекс этого символа равен limit-1 - этот символ не читается, если i достигло limit-1. Короткий логический eval разорвет цикл до getchar() и последующего присваивания и дальнейшего сравнения.   -  person WhozCraig    schedule 08.08.2014
comment
Да, ты прав! Я пропустил этот момент. Спасибо.   -  person microbit    schedule 08.08.2014
comment
На самом деле есть два момента, когда это происходит.   -  person WhozCraig    schedule 08.08.2014


Ответы (2)


Ваш анализ неверен. Если i == limit-1, цикл прерывается без чтения в c из-за оценки короткого замыкания. Таким образом, вы никогда не вводите if (c == '\n'). i остается limit-1 и переполнения нет.

Концептуально условие цикла можно представить так: «Если i меньше, чем limit-1, прочитать символ, а если это не EOF или новая строка, ввести тело цикла». Таким образом, если i равно limit-1, вы никогда не читаете.

person Filipe Gonçalves    schedule 08.08.2014

В этом коде есть две короткозамкнутые точки оценки. Увидеть ниже

for (i=0; i<limit-1 && (c=getchar())!=EOF && c!='\n'; ++i)
//        (   A   )    (        B        )   (  C  )

Все разделены цепочкой &&. Когда этот код выполняется, все три должны быть истинными, иначе цикл разорвется. Но при оценке короткого замыкания происходит следующее:

  • Если A ложно, условие ложно, ни ни B, ни C не оцениваются.
  • В противном случае, если B ложно, условие ложно и C не оценивается.
  • В противном случае, если C ложно, условие ложно.

Следовательно...

  • если i<limit-1 ложно, ни getchar() и сравнение с EOF, ни сравнение с '\n' не выполняются.
  • иначе, если (c=getchar())!=EOF ложно, то сравнение с '\n' не выполняется.
  • в противном случае выполняется сравнение с '\n'.

я надеюсь, что это имело смысл.

person WhozCraig    schedule 08.08.2014