我是从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()
新数组?将指针传递给堆上的数组是否足够?
答案 0 :(得分:5)
是的,将局部变量复制到malloc
- 内存区域的效果很好。您可以使用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 */
}
答案 1 :(得分:3)
是的,您正确地将所有权转移到来电者功能。 C程序员并不经常使用这种所有权方法,但它有时会发生(strdup
和GNUish asprintf
是众所周知的例子)。
您也可以从一开始就使用堆分配的数组,无需复制。
顺便说一下,在复制时,代码中存在一个错误:for (i = 0; i <= (size + 1); i++)
的主体被调用size+2
次。正如另一个答案暗示的那样,使用带有size参数的memcpy
确实比自己做的更容易出错。
最后一件事:sizeof(char)
在ANSI C中总是1,请不要乘以它。
答案 2 :(得分:2)
是的,你的meatSlicer已经完成了heap_the_Array,它现在属于调用者。所以调用者是现在唯一可以(并且必须)删除该数组的人,除非他将所有权转让给其他人。这种所有权的想法必须由你以某种方式定义,并且你必须与它保持一致,以避免麻烦并避免被内存泄漏怪物切掉。
答案 3 :(得分: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);
我更喜欢使用固定大小的数组,因为开销较少,而且“记得以后免费”的需要较少 - 后者是代码中的常见问题,特别是当代码变得更复杂时涉及多个调用级别 - 例如,如果在一个函数中分配多个项目,则需要记住如果稍后分配失败则清理第一个项目。让生活变得复杂......
答案 4 :(得分:0)
是的,只有堆栈分配的变量在函数返回时自动“释放”,并且您已在堆上正确分配了一个数组,并正确地返回了指向它的指针。
具体来说,指针变量heap_the_Array
在堆栈上分配,并返回该值的副本。
答案 5 :(得分:0)
虽然你可以返回指向堆分配对象的指针,但这并不意味着你可以忘记终止字符数组的NULL:)。
它会工作,只是不要忘记在混合中添加尾部'\ 0',并且在完成后不要忘记free()
char数组。
答案 6 :(得分:0)
假设您的数组是字符串,您可以用一行替换您的错误代码。
return strdup(newArray);