BOOLEAN allocate_items(struct item * items, size_t howmany) 函数用于分配结构项数组
BOOLEAN allocate_items(struct item * items, size_t howmany) function for allocate an array of struct item
最近在学习C,在网上发现一道题。问题是:
What is the problem with this function in terms of memory allocation?
What is a good solution? You may assume that a struct item type has
been declared. The purpose of this function is to allocate an array of
struct item, which you may assume has been declared prior to this
function.
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){
正确吗?
首先,您提到的第 4 行和第 6 行似乎都可以。
也就是说,此函数的基本问题是,您将内存分配给 local 范围的变量。这样
- 由于您没有 return 指向已分配内存的指针,因此在函数 returns 之后,将无法访问已分配内存。
- 如果不释放分配的内存,您将面临内存泄漏。
如果你必须分配内存给一个指针,你需要将该指针的地址传递给函数并分配内存。您也可以 return 指针,但是您需要更改函数签名。
最后,arrays are not pointers and vice-versa。它们可能有时看起来或表现相似,但它们并不相同。
第 4 行没有错,因为他们试图声明一个结构数组。
您应该在声明一个新指针 temp 的函数中添加一行来保存项目的当前值,然后在分配内存之后,
第6行应该是
if(items == temp)
检查值是否已更改(因为这是我们最接近检查 malloc 是否有效的方法)
这是因为!运算符用于检查条件是否为真(至少在大多数语言的基本级别)并且由于指针不是条件或可用作真或假的 int,运算符将不起作用.
这里是一个固定版本,因为它可能会写在 "industry".
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;
}
防御性编程声明:您的函数不能声明 "Heh - my function only crashed because I was given a bad value!"。相反,它必须验证自己。 不会崩溃。指针可能仍然是 != NULL 但在其他方面很糟糕。通常情况下,函数不可能捕捉到这一点。
在 C 中,每个人都以不需要转换 malloc()
的 return 值而自豪。在使用 C++ 编译器编译代码之前,您可以为此感到自豪。然后你必须改变你的代码并修复它。好吧,我想这是一个偏好问题...
虽然参数检查通常被视为函数实现的一个单独部分,但在那之后,您应该尝试坚持 "single point of exit"。主要原因是可维护性。有多个出口点,如果函数后来变得更大,如果一些早期出口忘记释放一些内存或清理其他形式的状态,就更难发现。
最近在学习C,在网上发现一道题。问题是:
What is the problem with this function in terms of memory allocation? What is a good solution? You may assume that a struct item type has been declared. The purpose of this function is to allocate an array of struct item, which you may assume has been declared prior to this function.
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){
正确吗?
首先,您提到的第 4 行和第 6 行似乎都可以。
也就是说,此函数的基本问题是,您将内存分配给 local 范围的变量。这样
- 由于您没有 return 指向已分配内存的指针,因此在函数 returns 之后,将无法访问已分配内存。
- 如果不释放分配的内存,您将面临内存泄漏。
如果你必须分配内存给一个指针,你需要将该指针的地址传递给函数并分配内存。您也可以 return 指针,但是您需要更改函数签名。
最后,arrays are not pointers and vice-versa。它们可能有时看起来或表现相似,但它们并不相同。
第 4 行没有错,因为他们试图声明一个结构数组。 您应该在声明一个新指针 temp 的函数中添加一行来保存项目的当前值,然后在分配内存之后, 第6行应该是
if(items == temp)
检查值是否已更改(因为这是我们最接近检查 malloc 是否有效的方法)
这是因为!运算符用于检查条件是否为真(至少在大多数语言的基本级别)并且由于指针不是条件或可用作真或假的 int,运算符将不起作用.
这里是一个固定版本,因为它可能会写在 "industry".
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;
}
防御性编程声明:您的函数不能声明 "Heh - my function only crashed because I was given a bad value!"。相反,它必须验证自己。 不会崩溃。指针可能仍然是 != NULL 但在其他方面很糟糕。通常情况下,函数不可能捕捉到这一点。
在 C 中,每个人都以不需要转换 malloc()
的 return 值而自豪。在使用 C++ 编译器编译代码之前,您可以为此感到自豪。然后你必须改变你的代码并修复它。好吧,我想这是一个偏好问题...
虽然参数检查通常被视为函数实现的一个单独部分,但在那之后,您应该尝试坚持 "single point of exit"。主要原因是可维护性。有多个出口点,如果函数后来变得更大,如果一些早期出口忘记释放一些内存或清理其他形式的状态,就更难发现。