Я пишу программу для решения упражнения 2-2 K&R.
#include<stdio.h>
#define MAXLINE 1000
/* write an equivalent loop without using && or || */
int Getline(char s[], int lim);
int main()
{
int len;
char line[MAXLINE];
while ((len = Getline(line, MAXLINE)) > 0) {
printf("%s%15s%d\n", line, "length: ", len);
}
return 0;
}
int Getline(char s[], int lim)
{
int flag = 1;
int i = 0, c = 0;
for (i = 0; flag == 1; ++i) {
if (i < lim - 1) {
if ((c = getchar()) != '\n') {
if (c != EOF) {
;
}
else {
flag = 0;
}
}
else {
flag = 0;
}
}
else {
flag = 0;
}
if (flag == 1) {
s[i] = c;
}
}
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
Эта программа неправильная ... странным образом. Я запускаю этот код с перенаправлением вроде
./2-2 <in
с файлом в
Get this line.
Тогда вывод на экран бесчисленный
G length: 1
Похоже, программа застряла в цикле. Но когда я прекращаю использовать перенаправление и просто набираю Получите эту строку. в терминал, хотя это все еще неправильно, бесчисленные выходные данные исчезают. Почему?
Вместо этой ерунды flag = 0 используйте, пожалуйста, break - он существует в языке не зря!
Я знаю break, но он не описан в главе 2 K&R, поэтому я попытался решить упражнение без break.





Проблема здесь:
for (i = 0; flag == 1; ++i) {
^^^
i will always increment to at least 1
before the for-loop ends
so your function will never return 0
Вместо увеличения в цикле for увеличивайте только после вставки нового элемента. Нравиться
if (flag == 1) {
s[i] = c;
++i;
}
Вместо цикла for вы можете использовать цикл while, например:
int i = 0;
while (flag == 1)
{
...
}
Следующим шагом будет избавление от флага и использование встроенного break. Нравиться:
int i = 0;
while (1)
{
if (i >= lim - 1) break;
...
}
Ваш код будет намного короче и легче читается.
Спасибо! Я сделал такую ошибку в стиле новичка. Но я думаю, что break не был представлен в главе 2 K&R, поэтому мне не следует использовать его в своем решении для упражнений. И проблема в моей функции может быть решена добавлением --i после цикла for.
Вы также немного усложнили свою функцию. Если вы просто хотите перенаправить строку из файла, сохранить ее в line и убедиться, что это прекращенный (и без конечного '\n', который вы не должны оставлять свисающими со строк, которые вы храните), вы можете сделать что-то довольно простое, например:
int Getline (char *s, int lim)
{
int i = 0; /* char count - length */
while (i < lim - 1) { /* loop while chars fit */
int c = getchar(); /* getchar */
if (c == EOF) /* validate EOF? */
goto done;
if (c == '\n') /* validate newline */
continue;
s[i++] = c; /* good char, increment len */
}
done:;
s[i] = 0; /* nul-terminate */
return i; /* return length */
}
(Примечание: из вашего комментария о том, что раньше вы не использовали break, тогда простой goto работает так же хорошо)
Пример использования / вывода
Учитывая ваш файл, содержащий строку "Get this line."
$ ./bin/equivloop <dat/in
Get this line. length: 14
(примечание: если вы сохраните новую строку, длина будет 15, и этот вывод будет на следующей строке)
Есть ли в строке вашего входного файла новую строку? Попробуйте добавить второй пустой.