最近,我正在学习C.我在互联网上发现了一个问题。问题是:
此功能在内存分配方面有什么问题? 什么是好的解决方案?您可以假设结构项类型具有 已经宣布。这个函数的目的是分配一个数组 struct item,您可以假设在此之前已声明 功能
BOOLEAN allocate_items(struct item * items, size_t howmany) { size_t count; items = malloc(sizeof(struct item) * howmany); if(!items) { perror("failed to allocate memory"); return FALSE; } return TRUE; }
所以,我认为第4行是错误的。应该是这样的:
items = malloc(sizeof(struct item));
第6行也错了。应该是这样的:
if(items == NULL){
这是对的吗?
答案 0 :(得分:1)
首先,正如你所提到的那样,第4行和第6行似乎都没问题。
也就是说,这个函数的基本问题是,你将内存分配给 local 变量范围。这样
如果必须将内存分配给指针,则需要将该指针的地址传递给该函数并分配内存。您也可以返回指针,但是您需要更改函数签名。
最后,arrays are not pointers and vice-versa。它们可能会出现或类似有时,但它们并不相同。
答案 1 :(得分:-1)
第4行没有错,因为他们试图声明结构数组。 你应该在函数中添加一行来声明一个新的指针temp,以保存项目的当前值,然后在分配内存之后, 第6行应该是
if(items == temp)
检查值是否已更改(因为这是我们最接近检查malloc是否有效)
这是因为!运算符用于检查条件是否为真(至少在大多数语言的基本级别),并且作为指针不是条件或可以用作真或假的int,运算符赢了&#39工作。答案 2 :(得分:-1)
这是一个固定版本,因为它可能会写在“行业”中。
bool allocate_items(struct item ** pitems, size_t howmany)
{
// argument validation
assert(NULL != pitems); // some also add release version checks...
if(NULL == pitems ) return false;
// We can also spot memory leak sources here.
// If *pItems != NULL - does that mean we have to free first to prevent
// a leak? What if it is just some random value and not something we can
// free? So contract usually is: *pitems has to be NULL...
assert(NULL == *pitems);
if(NULL != *pitems) return false;
// implementation
*pitems = malloc(sizeof(struct item) * howmany);
if(NULL == *pitems) {
perror("failed to allocate memory");
}
return NULL != *pitems;
}
虽然stdbool.h
中定义的bool有时会导致C ++互操作出现问题(双方都有相同的符号,但有时sizeof(bool)
不同),与发明另一种bool类型相比,它仍然是更好的选择。
pitems
是指向应写入新内存块的指针的位置的指针。此函数的调用者可能已写入:
int main(int argc, const char*[] argv) {
struct item *myBunchOfStuff = NULL;
if(false != allocate_items( &myBunchOfStuff, 20) ) {
// ...
free(myBunchOfStuff);
myBunchOfStuff = NULL;
}
return 0;
}
防御性编程状态:你的功能不能声称“嘿 - 我的功能只因为我的价值不好而崩溃!”。相反,它必须验证自己。它负责不崩溃。指针仍然可以!= NULL但其他方面都不好。通常,这个函数不可能捕获。
在C中,每个人都为不要求malloc()
的回归值而感到骄傲。在使用C ++编译器编译代码之前,您可以为此感到自豪。然后你必须改变你的代码并修复它。好吧,我想这是一个偏好的问题......
虽然参数检查通常被视为函数实现的一个单独部分,但在此之后,您应该尝试坚持“单点退出”。主要原因是可维护性。有了多个退出点,如果稍后函数变大,如果某些早期退出会忘记释放某些内存或清理其他形式的状态,则更难发现。