4

我正在阅读 K&R C,主要是为了刷我的 C 技能,并且在尝试编写程序来反转给定字符串时,我遇到了一个困扰着我的错误,最糟糕的是,我无法调试 - 也没有线索可能是什么原因。

我的代码如下:

#include <stdio.h>
#include <string.h>

char * reverse(char *string);

int main(int argc, char *argv[])
{
    printf("Please input a string: \t");

    char string[256];

    scanf("%s", string);

    char *reversed = reverse(string);

    printf("The reversed string is %s\n", reversed);

    return 0;
}

char * reverse(char string[])
{
    int size = strlen(string);
    printf("DEBUG: The size of the string that we got as input was: %d\n", size);
    int counter;
    char reversed[size + 1];

    for(counter = size - 1; counter >= 0; counter--) {
        reversed[size - counter] = string[counter];
        printf("DEBUG: The character copied now was %c and was at index %d\n", string[counter], counter);
    }

    reversed[size + 1] = '\0';

    printf("DEBUG: The reversed string is %s\n", reversed);

    return reversed;
}

(请原谅乱扔代码逻辑的调试语句。除此之外,请随时纠正您可能看到的任何错误,并随时提出改进建议)

现在,我的代码正在运行(大部分情况下),但错误是它复制了我没有输入的字符。以下是两次测试运行的(有趣的)结果:

第一个:

nlightnfotis@crunchbang:~/SoftwareExperiments$ ./reverse
Please input a string:  fotis
DEBUG: The size of the string that we got as input was: 5
DEBUG: The character copied now was s and was at index 4
DEBUG: The character copied now was i and was at index 3
DEBUG: The character copied now was t and was at index 2
DEBUG: The character copied now was o and was at index 1
DEBUG: The character copied now was f and was at index 0
DEBUG: The reversed string is $sitof
The reversed string is $sitof

(注意$

第二个:

nlightnfotis@crunchbang:~/SoftwareExperiments$ ./reverse
Please input a string:  lol
DEBUG: The size of the string that we got as input was: 3
DEBUG: The character copied now was l and was at index 2
DEBUG: The character copied now was o and was at index 1
DEBUG: The character copied now was l and was at index 0
DEBUG: The reversed string is lol
The reversed string is lol

在这里更准确地描述:

错误

比我更有知识和经验的人可以向我解释我的代码有什么问题,或者给我一个提示,告诉我为什么我会遇到这个令人沮丧的错误?

4

4 回答 4

10

您正在返回一个局部变量:

char * reverse(char string[]) {    
  char reversed[size + 1];
  ....
  return reversed;
}

一旦函数返回,分配在堆栈上的局部变量reversed将不复存在。reverse因此,对它的任何引用都会main导致未定义的行为。

要解决此问题,您可以执行以下任一操作:

  1. 制作函数void并修改输入数组。

  2. 将数组声明reversed为静态,以便其生命周期更改为程序的生命周期。

  3. 动态分配(然后取消分配)reversed

于 2013-04-19T19:29:21.690 回答
8

总是同样的错误,一遍又一遍......

我。

char reversed[size + 1];
// ...
return reversed;

您正在返回一个自动数组,该数组在函数返回后立即超出范围 - 未定义的行为。做reversed一个变量来避免这种情况(然后在你开始相信它是魔法之前static阅读关键字)。static

二、

char string[256];
scanf("%s", string);

输入带有空格的字符串时可能出现缓冲区溢出和错误。将此更改为

fgets(string, sizeof(string), stdin);

三、

char reversed[size + 1];
// ...
reversed[size + 1] = '\0';

另一个缓冲区溢出。在 C 中,数组从 0 开始索引。


是时候阅读一本好的 C 书了。

于 2013-04-19T19:32:03.290 回答
3

除了 codaddict 的帖子和 H2CO3 的精彩解释之外,您还有一个错误:

 char reversed[size + 1];
 reversed[size + 1] = '\0';

这将导致出界索引。说size = 10,那么size +1 =11reversedchar 数组的 索引值为0,1,2,3,...,10. 因此,reversed[11] 会给你带来麻烦。

于 2013-04-19T19:32:24.063 回答
2

好的,用上面发现的错误加上我自己的答案进行了注释:

char * reverse(char string[])
{
    int size = strlen(string);
    printf("DEBUG: The size of the string that we got as input was: %d\n", size);
    int counter;

    /* BUGBUG: You are using a stack variable to store the return string.
     * char *reversed = malloc(sizeof(char) * (size + 1))
     * to allocate a string that can be returned safely.
     */
    char reversed[size + 1];

    for(counter = size - 1; counter >= 0; counter--) {
        /* BUGBUG: You are setting the wrong char in "reversed", it should be
         * reversed[size - 1 - counter].  You want the "size - 1" char from the original
         * to be copied to the 0 position of the reversed
         */
        reversed[size - counter] = string[counter];
        printf("DEBUG: The character copied now was %c and was at index %d\n", string[counter], counter);
    }

    /* BUGBUG: You are setting the null character one past the end of the string.
     * Here you want reversed[size], which with 0-indexing is the size+1'st
     * character.
     */
    reversed[size + 1] = '\0';

    printf("DEBUG: The reversed string is %s\n", reversed);

    /* BUGBUG: Just to stress this -- you cannot expect this to work; that it
     * does so is accidental because the call stack is not cleaned.  If the calling
     * function called another function (say printf) then the printf is likely to 
     * overwrite the contents of reversed.
     */
    return reversed;
}
于 2013-04-22T15:12:21.687 回答