【问题标题】:K&R 1.19 exercise ("reverse" func)K&R 1.19 练习(“反向”函数)
【发布时间】:2016-11-27 22:08:38
【问题描述】:

这是任务:

编写一个反转字符串 s 的函数 reverse(s) 。用它来编写一个程序,一次将其输入反转一行。

好的,现在,我的表演:

#include <stdio.h>

#define LIM 40

char line[LIM];
int c;
int reverse(char line[], int lim);
int len;

int main(void) {
    while ((len = reverse(line, LIM)) > 0) {
        ;
    }
    printf("\n      END OF THE PROGRAM     \n");
    return 0;
}

********** THE REVERSE FUNCTION*********
int reverse(char s[], int lim) {
    char rev[LIM];
    int 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';

    int r;
    for (r = 0; r < lim - 1; ++r) {
        rev[r] = s[i];
        --i;
    }
    int x;
    for (x = 0; x < lim - 1; ++x) {
        putchar(rev[x]);
    }
    printf("\n");
    return r;
}

它似乎工作正常,但有一些与输出相关的错误。 例如:

输入:大家好输出:ydobyreve olleh

输入:abc 输出:cba'

输入:ABC 输出:CBA'

输入:ABC ABC 输出:CBA CBA

输入:se se 输出:es es'

看到了吗?一些奇怪的“'”出现在输出的末尾,我无法弄清楚为什么这些“工件”会被打印出来。它随机发生(对我来说)。您能否提出任何建议,代码有什么问题?

【问题讨论】:

  • 抱歉,这太可怕了,而且太复杂了。我什至不知道从哪里开始! main中的空while循环?将全局 line 传递给函数 reverse 但从未在其他任何地方使用它?三重条件如果 for?
  • @John3136 是的,我的代码还不好,抱歉。好吧,关于'reverse':第一个'for' - 我从输入中得到一条线。第二个'for' - 我声明一个数组并用反向线填充它。第三个'for' - 我打印反转线。
  • 为什么不“分而治之”让reverse 只是反转一个字符串:不读取字符串并写入字符串。然后,您可以专注于做一件事,并为其提供一些“预先确定的”输入,直到它工作为止。考虑一下您是只想打印反转的字符串还是将其反转或反转它的副本。
  • 第二个和第三个循环的问题是它们一直运行到lim - 1,也就是全部 40 个字符。它们应该只针对字符串中实际存在的字符数运行。因此,在第二个循环中,您应该循环直到 i 达到 0,同时在循环内递增 r。然后第三个循环可以运行直到x 等于r
  • @user3386109 好的,谢谢你,我试试看。

标签: c arrays string function kernighan-and-ritchie


【解决方案1】:

你的reverse函数有问题:

  • 您不应该将换行符存储到s 数组中,因为您不希望它参与反向操作。

  • 当您到达s 中的字符串末尾时,您应该停止后续的for 循环,而不是一直运行到缓冲区的末尾。

  • 您应该空终止rev 数组。

  • rev数组不需要一次输出一个字符,使用is作为字符串。

这是一个更正和简化的版本:

#include <stdio.h>

#define LIM 40

int reverse(char line[], int size);

int main(void) {
    char line[LIM];
    int len;

    while (reverse(line, LIM) > 0) {
        continue;
    }
    printf("\n      END OF THE PROGRAM     \n");
    return 0;
}

/* THE REVERSE FUNCTION */
int reverse(char s[], int size) {
    char rev[size];
    int i, r, c, len;
    for (i = 0; i < size - 1 && (c = getchar()) != EOF && c != '\n'; i++) {
        s[i] = c;
    }
    len = i;
    s[i] = '\0';

    for (i = 0; i < len; i++) {
        rev[len - i - 1] = s[i];
    }
    rev[i] = '\0';

    printf("%s\n", rev);
    return len;
}

【讨论】:

    【解决方案2】:

    更模块化的解决方案。我不太确定 K&R 所说的“一次一行”是什么意思。但这将反转字符串,直到找到换行符。然后等待用户并重复。

    #include <stdio.h>
    
    #define MAXLINE 1000
    
    int get_line(char s[], int limit);
    int reverse(char to[], char from[], int l);
    
    int main() {
        int size;
        char line[MAXLINE];
        while ((size = get_line(line, MAXLINE)) > 0) {
            char revline[size];
            int len = reverse(revline, line, size);
            printf("%s\n", revline);
        }
    
        return 0;
    }
    
    int reverse(char to[], char from[], int l) {
        int i;
        int j = l - 2;
        for (i = 0; i < l; i++, j--) {
            to[i] = from[j];
        }
        to[i] = '\0';
        return i;
    }
    
    // read a line into s until limit
    // return length of line
    int get_line(char s[], int limit) {
        int c = 0;
        int i = 0;
    
        for (i = 0; i < limit-1 && (c = getchar()) != '\n'; ++i) {
            s[i] = c;
        }
        if (c == '\n') {
            s[i] = c;
            ++i;
        }
        s[i] = '\0';
        return i;
    }
    

    输出:

    testing one two
    owt eno gnitset
    three four
    ruof eerht
    five six
    xis evif
    

    【讨论】:

    • getchar() 函数在某些情况下可能会返回 EOF。如果发生罕见的读取错误,getchar() 将在连续调用时返回EOF,导致此代码进入无限循环。如果用户从键盘发出EOF的信号,这段代码将继续寻找进一步的输入,当输入最终以\n结束时,输出可能不会像预期的那样。
    • 我不明白为什么get_line() 函数在此处保留换行符;这需要reverse() 了解额外字符。也许reverse() 更适合命名为reverse_line();除了它不会创建反向线....
    • @exnihilo 酷。让我们看看你的解决方案。此外,reverse() 实际上确实创建了一条反转线。 get_line() 保留换行符,因为我想要它。
    • 我不需要提供解决方案来获得指出其他解决方案缺陷的权利。你想向 OP 展示如何使用getchar() 来获取一行输入,所以向他们展示好的代码。您必须测试EOF 以满足“好代码”,并注意接受的解决方案会这样做;这是循环 getchar() 时的 C 习惯用法。未能在此处测试EOF 会导致代码脆弱。我已经提到了原因,但是通过在输入中几次从键盘(Linux 上的 CTRL-D)发出 EOF 信号来向自己展示,输出将不符合预期。
    • "另外,reverse() 实际上确实创建了一条反转线。" -- 这不是真的。一行以\n 结尾,反向行也以\n 结尾。上面提到的问题是反转一个string。您的代码执行此操作,但保留输入中的 \n 意味着 reverse() 必须忽略该字符。传递一个 not 最后包含 \n 的字符串将失败。 reverse() 需要一个 line,但不返回一行(只是一个字符串)。我的目的不是挑剔你的答案,而是提供建设性的批评,但你忽略了。
    猜你喜欢
    • 2010-12-26
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多