Newbie C Array вопрос о функциях - PullRequest
0 голосов
/ 26 января 2010

Я купил книгу на языке C под названием "ЯЗЫК ПРОГРАММИРОВАНИЯ C (ANSI C)", чтобы попытаться научить себя, ну, в общем, C. Во всяком случае, книга включает в себя множество примеров и практик, которым нужно следовать по всем главам, что приятно.

Во всяком случае, приведенный ниже код является моим ответом на книги «посчитайте самую длинную строку программы», авторы используют цикл for в функции getLine(char s[], int lim). Что позволяет правильно отображать строку line внутри функции main(). Однако использование while не сработает - по неизвестной мне причине, возможно, кто-то может пролить свет на ситуацию с моей ошибкой.

РЕДАКТИРОВАТЬ: Подводя итог выше. printf("%s\n", line); ничего не отобразит.

благодарен за любую помощь.

#include <stdio.h>
#define MAXLINE 1024

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

    while((c = getchar()) != EOF && c != '\n' && i < lim) {
        s[++i] = c;
    }

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

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

    while((len = getLine(line,MAXLINE)) > 0) {
        if(len > max) {
            max = len;
            printf("%s\n", line);
        }
    }
    return 0;
}

Ответы [ 5 ]

1 голос
/ 26 января 2010

У вас есть ряд серьезных ошибок. Вот те, которые я нашел и как их исправить.

измените свой код на postincrement i, чтобы не оставлять первый элемент массива неинициализированным, а также чтобы избежать двойной печати последнего символа:

s[++i] = c;
...
s[++i] = c;
s[++i] = '\0';

до

s[i++] = c;
...
// s[++i] = c; see below
...
s[i++] = '\0'; 

и исправьте ошибку EOF:

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

до

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

Теория

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

Случаи, которые вам нужно пройти через это:

  • пара общих случаев
  • все крайние случаи

В этом случае ваши крайние случаи:

  • первый символ в истории EOF
  • первый символ 'x', второй символ EOF
  • первый символ '\ n', второй символ EOF
  • первый символ «x», второй символ «\ n», третий символ EOF

  • строка содержит символы lim

  • строка содержит на один символ меньше чем
  • строка содержит на один больше чем lim символов

Образец кромочного футляра

первый символ 'x', второй символ '\ n', третий символ EOF

getLine(line[MAXLINE],MAXLINE])
(s := line[MAXLINE] = '!!!!!!!!!!!!!!!!!!!!!!!!...'
c := undef, i := 0
while(...)
c := 'x'
i := 1
s[1] := 'x' => s == '!x!!!!...' <- first bug found
while(...)
c := '\n'
end of while(...)
if (...)
(c== '\n' (T) && i != 0 (T)) = T
i := i + 1 = 2
s[2] = '\n' => s == '!x\n!!!!'
i := i + 1 = 3
s[3] = '\0' => s == '!x\n\0!!!' <- good, it's terminated
return i = 3
(len = i = 3) > 0) = T (the while eval)
if (...)
len (i = 3) > max = F
max = 3 <- does this make sense?  is '!x\n' a line 3 chars long?  perhaps.  why did we keep the '\n' character? this is likely to be another bug.
printf("%s\n", line) <- oh, we are adding ANOTHER \n character?  it was definitely a bug.
outputs "!x\n\n\0" <- oh, I expected it to print "x\n".  we know why it didn't.
while(...)
getLine(...)
(s := line[MAXLINE] = '!x\n\0!!!!!!!!!!!!!!!!!!!...' ; <- oh, that's fun.
c := undef, i := 0
while(...)
c := EOF
while terminates without executing body
(c == '\n' && i != 0) = F
if body not executed
return i = 0
(len = i = 0 > 0) = F
while terminates
program stops.

Итак, вы видите, что этот простой процесс, который может быть выполнен в вашей голове или (предпочтительно) на бумаге, может показать вам в считанные минуты, будет ли ваша программа работать или нет.

Следуя другим пограничным случаям и паре общих случаев, вы обнаружите другие проблемы в вашей программе.

0 голосов
/ 26 января 2010

Также следите за переполнением - вы назначаете s [i] в ​​конце с пределом i == lim, поэтому вы можете назначать s [MAXLINE]. Это было бы - подожди - переполнение стека, да.

0 голосов
/ 26 января 2010

Также добавьте типы возврата к функциям (int main и int getLine)

0 голосов
/ 26 января 2010

Делая ++ i вместо i ++, вы ничего не назначаете s [0] в getLine ()!

Кроме того, вы необязательно все время увеличиваете при назначении '\ 0' в конце цикла, что, кстати, всегда следует назначать, так что вынимайте его из условного выражения.

0 голосов
/ 26 января 2010

Из вашего вопроса неясно, какая именно проблема у вас с getLine (ошибка компиляции? Ошибка времени выполнения?), Но в вашей реализации есть пара ошибок. Вместо

s[++i] = something;

Вы должны использовать постфиксный оператор:

s[i++] = something;

Разница в том, что первая версия хранит «что-то» по индексу (i + 1), но вторая версия будет хранить что-то по индексу i. В C / C ++ массивы индексируются от 0, поэтому вам нужно убедиться, что он сохраняет символ в s [0] при первом проходе в цикле while, в s [1] при втором проходе и т. Д. С кодом, который вы разместили, s [0] никогда не назначается, что приведет к тому, что printf () распечатает неопубликованные данные.

У меня работает следующая реализация getline:

int getLine(char s[], int lim) {

    int c;
    int i;

    i = 0;

    while((c = getchar()) != EOF && c != '\n' && i < lim) {
        s[i++] = c;
    }

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

    return i;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...