C反向功能不适用于32个字符

时间:2013-06-25 16:29:12

标签: c string while-loop

为了测试我的技能,我正在尝试编写一些标准库函数的自己版本。我为strlen()strlength()

写了一个替代品
int strlength(const char *c){
    int len = 0;
    while (*c != '\0') {
        c++;
        len++;
    }
    return len;
}

包含空终止符,我正在尝试编写一个函数来反转字符串。这样:

char *reverse(const char *s){
    char *str = (char *)malloc(sizeof(char) * strlength(s));
    int i = 0;
    while (i < strlength(s)) {
        str[i] = s[(strlength(s) - 1) - i];
        i++;
    }
    str[strlength(s)] = '\0';
    return str;
}

适用于每个字符串,除了包含32个字符(不包括空终止符)的字符串,如foofoofoofoofoofoofoofoofoofoofo。它挂起reverse()函数while循环。对于所有其他数量的字符,它的工作原理。为什么会这样?

5 个答案:

答案 0 :(得分:6)

str的缓冲区关闭1.您的写入溢出到堆的其余部分。

至于为什么它适用于32以外的值,我的猜测是它与堆的内存对齐有关。编译器为较小的缓冲区大小添加了额外的填充,但是32个字节很好地对齐(它是2的幂,8的倍数等),所以它不会添加额外的填充,这会导致你的bug显示出来。尝试其他8的倍数,你可能会得到相同的行为。

答案 1 :(得分:4)

char *reverse(const char *s){

这里你分配N个字符(其中N是没有\0的s的长度):

    char *str = (char *)malloc(sizeof(char) * strlength(s));

然后你对s

的所有字符进行N次迭代
    int i = 0;
    while (i < strlength(s)) {
        str[i] = s[(strlength(s) - 1) - i];
        i++;
    }

最后以N + 1个字符添加\0

    str[strlength(s)] = '\0';
    return str;
}

所以你应该这样做:

    char *str = malloc(sizeof(*str) * strlength(s) + 1); // +1 for final `\0`
有趣的是,我刚刚测试了你的代码,它对我来说很好(有一个字符关闭)和你的32个字符串。正如@JoachimPileborg所说,“这是关于未定义行为的有趣事情”

正如其他人所建议的那样,问题肯定是由于memory alignment,当你的数据与内存对齐时会溢出,而当它没有对齐时会覆盖填充值。

答案 2 :(得分:2)

你问:

  

但这适用于所有其他字符串长度。为什么不为32?

最有可能的原因是运行时以32字节为单位分配内存。因此,当缓冲区大小为22字节时,1字符缓冲区溢出不是问题。但是当你分配32个字节并尝试写入第33个字节时,就会出现问题。

我怀疑你会看到同样的错误,包含64个字符,96,128等字符串。 。

答案 3 :(得分:1)

替换

malloc(sizeof(char) * strlength(s))

通过

malloc(sizeof(char) * (1+strlength(s)));

该行:

str[strlength(s)] = '\0';

通常工作,因为malloc库例程保留字边界对齐块并且仅分配呼叫中请求的尽可能多的块,即。 2的幂,但是当溢出的数据覆盖超出分配的部分时,通过调试器检查反汇编是理解特定于目标行为的构建工具链的最佳方法。由于该行是跟随while循环而不是在其中,因此如果没有反汇编,while循环如何变为无限是不可预测的。

答案 4 :(得分:0)

关于缓冲区溢出和运行时内存分配实现/策略的变幻莫测,其他人都说了些什么。由于NUL终止八位字节,C字符串的大小比其长度多1个。

这样的事情应该对你有所帮助(更清洁,更容易阅读):

#define NUL ((char)0) ;

char *reverse( const char *s )
{
  int   len = strlen(s) ;
  char *tgt = ((char*)malloc( 1+len )) + len ;
  char *src = s ;

  *(tgt--) = NUL ;
  while ( *src )
  {
    *(tgt--) = *(src++) ;
  }

  return tgt;
}

您的strlen()实施也比它需要的更复杂。这就是您所需要的一切:

int string_length( const char *s )
{
  char *p = s ;
  while ( *p ) ++p ;
  return p - s ;
}