2

我是从 Python 来到 C 的。Python 有一种非常简单的白手套操作字符串的方法。我在 C 中使用数组的次数越多,我就越觉得拥有某些特性会多么方便。我决定创建一个库来执行此操作,而不是每次我需要执行特定操作时都编写循环来执行此操作。

所以,假设我有一个库,调用看起来像这样:

char* new_array = meatSlicer(old_array, element_start);

我将指针传递给我想要更改的数组,期望指针返回,并指示要切片的元素。

如果meatSlicer(是的,我是一个错误命名的傻瓜)返回一个指向在切片器中本地创建的数组的指针,则该指针将是一个错误指针。所以,在meatSlicer()我有这个:

    ... manipulation before the below ...

    char *heap_the_Array;     /* put it on the heap to pass it back to caller */
    heap_the_Array = malloc((size + 1) * sizeof(char));

    int i;                
    for (i = 0; i <= (size + 1); i++){           /* make it so... again */

            heap_the_Array[i] = newArray[i];     /* newArray is the local */

    }

    return heap_the_Array;                       /* return pointer */

我的问题是,我是否正确地将所有权归还给调用者函数,以便它可以free()新数组?传递一个指向堆上数组的指针是否足够?

4

7 回答 7

5

是的,将局部变量复制到malloc-ed 内存区域效果很好。您可以用调用替换循环memcpy以减少代码大小。写

memcpy(heap_the_Array, newArray, size+1);

代替

int i;                
for (i = 0; i <= (size + 1); i++){           /* make it so... again */
        heap_the_Array[i] = newArray[i];     /* newArray is the local */
}
于 2013-01-17T21:17:42.183 回答
3

是的,您正在正确地将所有权转移给调用者函数。C 程序员不经常使用这种所有权方法,但有时会发生(strdupGNUishasprintf是广为人知的例子)。

您还可以从一开始就使用堆分配的数组,无需复制。

顺便说一句,在复制自身时,您的代码中存在一个错误:for (i = 0; i <= (size + 1); i++)调用主体的size+2时间。正如另一个答案所暗示的,与 size 参数一起使用memcpy确实比自己做更不容易出错。

最后一件事:sizeof(char)在 ANSI C 中总是 1,请不要乘以它。

于 2013-01-17T21:21:18.987 回答
2

是的,你的肉切片机是用 heap_the_Array 完成的,它现在属于调用者。所以调用者是现在唯一可以(并且必须)删除该数组的人,除非他将所有权传递给其他人。这种所有权概念必须由您以某种方式定义,并且您必须与它保持一致以避免麻烦并避免被内存泄漏怪物切割。

于 2013-01-17T21:18:21.913 回答
1

已经清楚地解释了所有权如何转移。但是,我想提出一种“更传统”的方法。你的代码看起来很像我很乐意在 Python 中做的事情——但 C 不是 Python(而且 Python 也不是 C!),学习一门新语言的一部分是学习“如何用该语言完成事情”。对于刚刚学习 C 的程序员来说,有一种趋势是到处调用 malloc。尽量不要那样做。

不要让函数分配一个数组,而是在你的调用代码中传入一个数组,它有空间存放你想要复制的东西。然后返回你实际得到的元素数量,例如:

 TYPE new_array[some_size];
 int max_size = sizeof(new_array) / sizeof(new_array[0]);
 int actual_size;

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

如果你想使用 malloc 来创建 new_array,那么你当然可以这样做:

 TYPE new_array = malloc(some_size * sizeof(TYPE));
 int max_size = some_size;
 int actual_size;

 if (new_array == NULL) panic();    // Do something useful here. 

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

 ... 

 free(new_array);

我更喜欢使用固定大小的数组,因为开销较小,并且“以后记得释放”的需要较少 - 后者是代码中的常见问题,特别是当代码变得有点复杂并且有几个调用时所涉及的级别 - 如果您在一个函数中分配多个项目,例如,如果以后的分配失败,您需要记住清理第一个项目。让生活变得复杂...

于 2013-01-17T22:02:35.407 回答
0

Yes, only stack allocated variables are automatically "freed" when a function returns, and you have correctly allocated an array on the heap, and correctly returned a pointer to it.

Specifically, the pointer variable heap_the_Array is allocated on the stack, and a copy of that value will be returned.

于 2013-01-17T21:15:19.530 回答
0

尽管您可以返回指向堆分配对象的指针,但这并不意味着您可以忘记 NULL 终止字符数组:)。

它会起作用,只是不要忘记将尾随的 '\0' 添加到混合中,并且free()一旦完成,不要忘记将其添加到 char 数组中。

于 2013-01-17T21:18:27.363 回答
0

假设你的数组是字符串,你可以用一行替换你的错误代码。

return strdup(newArray);
于 2013-01-17T21:34:01.777 回答