来自realloc()的奇怪行为

时间:2014-03-29 22:53:58

标签: c linux glibc

  • 编译:GCC 4.7.2(Debian 4.7.2-5)
  • 平台:Linux 3.2.0 x86(Debian Wheezy)

编辑:请参阅答案贝娄代码已更新并已经过测试。它再次正确地运行到WhozCraig。

我正在编写一个简单的头文件,其中包含动态操作宽字符串的函数。例如,我的标头包含一个复制功能,可以根据需要扩展目标缓冲区。我正在编写的当前函数仅将提供的缓冲区的一部分复制到提供的目标缓冲区中。最初我使用的目标缓冲区对于我的测试用例来说已经足够大了,而且该功能完全没有问题。但我想测试我的realloc()逻辑,所以我将目标缓冲区的大小设置为1,以便该函数必须realloc()目标缓冲区。但看起来我的realloc()正在改变目标缓冲区内容的值。我已将错误跟踪到第三个realloc()调用。这是我一直在使用的功能和测试用例。

#include <wchar.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#define DWS_DEF_SIZ 16

#define DWS_ENOMEM -1
#define DWS_EINVAL -2

int scpydws(wchar_t* *des, size_t *siz, int argc, wchar_t *src, size_t num, ...)
{   
    size_t i = 0;
    size_t j = 0;
    va_list argv;
    wchar_t *tmp = NULL;
    size_t x = 0;

    if(des == NULL) return DWS_EINVAL;
    if(siz == NULL) return DWS_EINVAL;
    if(*siz == 0 && *des != NULL) return DWS_EINVAL;

    if(*des == NULL)
    {
        if(*siz == 0)
        {
            if((*des = malloc(DWS_DEF_SIZ * sizeof(wchar_t))) == NULL) return DWS_ENOMEM;

            *siz = DWS_DEF_SIZ;
        }
        else if((*des = malloc(*siz * sizeof(wchar_t)) == NULL) return DWS_ENOMEM;
    }

    for(va_start(argv, num); argc > 0; argc--, src = va_arg(argv, wchar_t*), num = va_arg(argv, size_t))
    {
        if(src == NULL || src[0] == 0) continue;

        for(j = 0; j < num; j++, i++)
        {
            for(x = 0; x < i; x++) putwchar((*des)[x]);
            wprintf(L" | %i == %i\n", i, *siz - 1);

            if(i == *siz - 1)
            {
                if((tmp = realloc(*des, *siz * 2 * sizeof(wchar_t))) == NULL)
                {
                    va_end(argv);
                    return DWS_ENOMEM;
                }

                *siz *= 2;
                *des = tmp;
            }

            (*des)[i] = src[j];
        }
    }

    (*des)[i] = 0;
    va_end(argv);
    return 0;
}

int main()
{
    int ret = 0;
    size_t siz = 1;
    wchar_t *des = NULL;
    wchar_t src1[] = L"123456789";
    wchar_t src2[] = L"abcdefghijklmnopqrstuvwxyz";
    wchar_t src3[] = L"blahblah";

    //The syntax is fairly straight forward the numbers following the
    //buffers represent how many characters to copy into the destination buffer
    ret = scpydws(&des, &siz, 3, src1, 2, src2, 3, src3, wcslen(src3));
    wprintf(L"ret = %i\n", ret);

    return 0;
}

以下是测试用例的输出。一切正常,直到第三个realloc()“|”之前的字符在函数操作期间表示目标缓冲区。 “|”之后的内容表示目标缓冲区的函数索引变量(“==”左侧的整数)与目标缓冲区的最后一个有效索引(“==”右侧的整数)之间的比较,如果该语句为真,则为函数将realloc()目标缓冲区。所以我的问题基本上就是'Y'来自哪里(见下文)?另外在我注意到我在使用MinGW-GCC的Windows Vista SP3系统上编译代码(我不知道MinGW-GCC版本是什么)而不是随机的'Y'字符我从realloc()得到ENOMEM错误,具有讽刺意味在第三次realloc()调用,但我真的不在乎为什么会这样。

 | 0 == 0
1 | 1 == 1
12 | 2 == 3
12a | 3 == 3
12ab | 4 == 7
12abc | 5 == 7
12abcb | 6 == 7
12abcbl | 7 == 7 Note: The function realloc()s here
12abcYla | 8 == 15 Note: Notice how the 'b' changes to a 'Y'?
12abcYlah | 9 == 15
12abcYlahb | 10 == 15
12abcYlahbl | 11 == 15
12abcYlahbla | 12 == 15
ret = 0

1 个答案:

答案 0 :(得分:3)

malloc()realloc()的尺寸参数需要乘以sizeof(wchar_t)

我改变了这个:

*des = malloc(DWS_DEF_SIZ))

到此:

*des = malloc(DWS_DEF_SIZ * sizeof(wchar_t)))

和此:

tmp = realloc(*des, *siz * 2)

到此:

tmp = realloc(*des, *siz * 2 * sizeof(wchar_t))

感谢WhozCraig