与Malloc()的奇怪副作用

时间:2010-12-13 01:30:21

标签: c malloc

所以我正在为一个简单的shell编写一个C程序。不是太难,但我遇到了一个我无法解释的奇怪问题。我试图在结构中创建一个二维数组来表示命令及其参数。对于命令“ls -l”,例如我想要第一个元素“ls”和第二个“-l”。似乎工作正常,除了malloc将“ls”更改为“ms”。对于其他命令,同样的事情,第一个字符递增;不是在malloc之前,也不是之后。

这是有问题的代码......

    printf ("PRE MALLOC: %c\n", ret_val->args[0][0]);
    printf ("[0] %p\n", ret_val->args[0]);
    ret_val->args[1] = (char*) malloc ((3) * sizeof (char));
    printf ("[0] %p\n", ret_val->args[0]);
    printf ("[1] %p\n", ret_val->args[1]);
    printf ("POST MALLOC: %c\n", ret_val->args[0][0]);

我试图完成的是分配一个3(-l + null)字符数组来保存args [1]中的“-l”。这些并不是真正的硬编码,但我认为它更好。

输出产生了这个......

PRE MALLOC:l

[0] 80613b0

[0] 80613b0

[1] 80613b8

POST MALLOC:m

所以这两个地址不重叠或有什么奇怪的但是第一个数组的第一个字符是递增的?如果我忽略了一些愚蠢的事情,我很抱歉。但我想不出有什么理由会发生这种情况。

有什么想法吗?

谢谢,

对于某些情况,这里有更多代码。

int lcv;
int numargs;
int numchars;
int offset;
int bool;

TCommand* ret_val;
char** tmp;

ret_val = (TCommand*) malloc ( sizeof (TCommand) );
ret_val->cmd = NULL;
ret_val->args = NULL;

/* CMD */
lcv = 0;
numargs = 0;
numchars = 0;
offset = 0;

/* Remove initial whitespace */
while (input[offset] == ' ')
{
    ++offset;
}

lcv = offset;

/* Loop through command string */
while ( input[lcv] != ' ' && input[lcv] != 0 && input[lcv] != '&')
{
    ++numchars;
    ++lcv;
}

ret_val->cmd = (char*) malloc ( (numchars+1) * sizeof(char));

/* Copy to command string */
memcpy (ret_val->cmd, &(input[offset]), (numchars * sizeof (char)));
ret_val->cmd[numchars] = 0;
offset += numchars;

/* Copy command string into first argument */
ret_val->args = (char**) malloc ( sizeof (char*));
memcpy (ret_val->args[numargs++],ret_val->cmd, (numchars+1) * sizeof(char));

bool = 1;
while ( bool )
{

    /* Remove initial whitespace */
    while (input[offset] == ' ')
    {
        ++offset;
    }

    lcv = offset;

    if ( input[lcv] == 0 )
    {
        bool = 0;
    }
    else
    {
        ++numargs;
        tmp = (char**) realloc (ret_val->args, numargs * sizeof (char*));
        ret_val->args = tmp;
        numchars = 0;

        while ( input[lcv] != ' ' && input[lcv] != 0 &&
            input[lcv] != '&')
        {
            ++numchars;
            ++lcv;
        }

                printf ("PRE MALLOC: %c\n", ret_val->args[0][0]);
                printf ("[0] %p\n", ret_val->args[0]);
                    ret_val->args[1] = (char*) malloc ((2) * sizeof (char));
                printf ("[0] %p\n", ret_val->args[0]);
                printf ("[1] %p\n", ret_val->args[1]);
                printf ("POST MALLOC: %c\n", ret_val->args[0][0]);
                fflush(stdout);
        memcpy (ret_val->args[numargs-1],&(input[offset]),numchars * sizeof (char));
        ret_val->args[numargs-1][numchars] = 0;
        offset += numchars;
    }
}

4 个答案:

答案 0 :(得分:4)

此代码:

/* Copy command string into first argument */
ret_val->args = (char**) malloc ( 2 * sizeof (char*));
memcpy (ret_val->args[numargs++],ret_val->cmd, (numchars+1) * sizeof(char));

通过未初始化的指针ret_val->args[0]进行复制。尝试:

/* Copy command string into first argument */
ret_val->args = malloc(2 * sizeof ret_val->args[0]);
ret_val->args[numargs] = malloc(numchars + 1);
memcpy(ret_val->args[numargs++], ret_val->cmd, numchars + 1);

(注意sizeof(char)被语言定义为1。

答案 1 :(得分:0)

问题出现在您展示的片段中;它是你未展示的代码中的某个地方。

因此,您需要从头开始构建您的示例 - 显示结构声明,内存管理以及您为结构执行的复制。

答案 2 :(得分:0)

这听起来像堆腐败的典型例子。

您所看到的很可能是malloc()调用覆盖args[0]指向其返回值的字符串的结果。如果args数组实际上没有足够的空间用于第二个参数,则会发生这种情况。通过写入args[1],您将覆盖argv[0]指向的字符串的内容,并且我怀疑您在分配{{1}后立即使用strdup()调用或类似内容进行分配} array。

由于堆向上增长,并且假设没有介入args调用,通过超越动态分配的数组的边界,之后立即分配区域的可能性会增加。

我会猜测并建议您通过打印free()调用的参数并检查其返回值来检查args数组的已分配大小。

编辑:

显然不是在这种情况下。似乎realloc()指针实际上可能未初始化,而不会导致分段错误。有趣...

答案 3 :(得分:0)

我想我们需要看看如何分配args [0],以及如何赋值。

我可以提出一些建议,但他们不会解决分配问题:

  1. 没有必要转换malloc()的结果,虽然在一个已编写的C程序中更改类型的能力有限,但没有理由故意通过打开编码重复类型信息来降低抽象级别。

    旧文本和旧代码示例经常会转换malloc(),因为C并不总是有void *类型,即使它到了之后,人们也会习惯性地使用旧代码编写代码对旧编译器的可移植性。但是现在你不太可能需要为PDP-11编译。

  2. sizeof(char)是由C99,1,所以只需说出malloc(3)就可以了,因为它更短,所以更容易阅读。如果你知道它是"-l",你也可以使用"-l"