calloc(4,6)和calloc(6,4)一样吗?
我是一名C程序员初学者,我认为情况会是这样,但如果可能的话,我希望得到一些肯定calloc(4,6)和calloc(6,4)一样吗?,c,memory-management,C,Memory Management,我是一名C程序员初学者,我认为情况会是这样,但如果可能的话,我希望得到一些肯定 如果它们是相同的,为什么不只接受一个参数呢?它是相同的。原因是,大多数情况下,您希望使用sizeof运算符作为参数之一。如果传递两个参数会让您感到麻烦,那么调用只有一个参数的malloc()。人们通常使用分配例程为一定数量的项目分配空间,因此calloc()允许很好地指定。例如,如果您想要为100个整数或20个您自己的结构留出空间: int *pInt = calloc (100, sizeof(int)); tMy
如果它们是相同的,为什么不只接受一个参数呢?它是相同的。原因是,大多数情况下,您希望使用
sizeof
运算符作为参数之一。如果传递两个参数会让您感到麻烦,那么调用只有一个参数的malloc()
。人们通常使用分配例程为一定数量的项目分配空间,因此calloc()
允许很好地指定。例如,如果您想要为100个整数或20个您自己的结构留出空间:
int *pInt = calloc (100, sizeof(int));
tMyStruct *pMyStruct = calloc (20, sizeof(tMyStruct));
此代码实际上看起来比等效的malloc()
调用稍微“好一些”:
int *pInt = malloc (100 * sizeof(int));
tMyStruct *pMyStruct = malloc (20 * sizeof(tMyStruct));
不过,对于经验丰富的C程序员来说,这并没有什么真正的区别(当然除了零初始化)
我必须说,我从来没有在野外使用过calloc,因为我几乎总是在创建一个
struct
,其中零是没有意义的。我更喜欢手动初始化所有字段,以确保获得所需的值。有一点区别:Calloc可以决定仅在需要时将内存归零,这样做的好处是知道元素的大小
我不能说出任何这样做的实现,但它被认为是为了这个
例如:
一个调用可分配4GB内存,但系统只有2GB:将2GB的零内存写入虚拟内存是没有意义的,因此系统可以在该内存上设置一个脏标志,以便在加载到内存时将其归零。calloc(4,6)和calloc(6,4)是不同的:
在典型的32位/64位系统上,第一个分配32字节,第二个分配24字节
关键的一点是,calloc必须返回内存,就像它作为数组正确对齐一样。这意味着分配一个数组并按如下方式使用:
A *p = (A*)calloc(count, sizeof(A));
for (int i = 0; i < count; ++i)
{
f(&(p[i]));
// f(p + i) is also valid
}
calloc应该在分配阵列时考虑目标系统的填充和其他操作要求。因此,在大多数32位机器上,6字节的结构需要填充到8字节,它会分配4批8字节
第一个参数为sizeof()的calloc很可能是一个bug,应该进行调查
第二个参数不是sizeof(atype)的calloc未定义。它散发着隐藏的假设的气味,对港口是危险的
澄清:
在典型的32位/64位系统上,结构可能会被填充并对齐到32位的倍数。因此,在这些系统上,sizeof不会返回6字节。事实上,如果编译器/平台需要16字节的倍数,则不能保证编译器不会进行填充和对齐
我的回答是基于这样一个事实,即你不应该对结构尺寸做出假设。它们可以随编译器选项或目标平台而更改。只要确保你的第二个参数是一个sizeof表达式,不要做假设
从: 函数的作用是:为nelem元素数组分配未使用的空间,每个元素的大小(字节)都是elsize。空间应初始化为所有位0 如果分配成功,则返回的指针应适当对齐,以便将其分配给指向任何类型对象的指针,然后用于访问分配空间中的此类对象或此类对象数组(直到显式释放或重新分配空间)。每个这样的分配应产生一个指向与任何其他对象不相交的对象的指针。返回的指针应指向分配空间的起始(最低字节地址)
尽管得到了公认的答案(我认为是正确的),但由于对齐,在分配多少字节方面似乎存在混淆。下面是在我的32位Linux和gcc-4.3上的一个小测试:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* p1 = calloc(6, 4);
char* p2 = calloc(4, 6);
char* p3 = calloc(1,1);
printf("%p, %p, %p\n", p1, p2, p3);
return 0;
}
这表明calloc(6,4)
和calloc(4,6)
分配的内存量相同,在我的系统上四舍五入为32字节。将数字更改为calloc(3,4)
和calloc(4,3)
将得到以下结果:
0x95d2008, 0x95d2018, 0x95d2028
这表明,当请求12个字节并将其分配给程序时,保留了16个字节。在这两种情况下,calloc(a,b)
和calloc(b,a)
调用对内存使用具有相同的影响
由Jonathan Leffler添加,因为300个字符永远不够 考虑一下这个程序,它像一个真正的筛子一样泄漏内存,但它说明了一点:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int i, j, k;
for (i = 1; i < 17; i++)
for (j = 1; j < 9; j++)
for (k = 0; k < 4; k++)
printf("(%2d,%d)%d: %p\n", i, j, k, calloc(i, j));
return(0);
}
#包括
#包括
int main()
{
int i,j,k;
对于(i=1;i<17;i++)
对于(j=1;j<9;j++)
对于(k=0;k<4;k++)
printf((%2d,%d)%d:%p\n“,i,j,k,calloc(i,j));
返回(0);
}
在Windows上,在Cygwin下,首先分配相隔16字节的块(实际上,第二个块在第一个块之后是24字节,但之后,它们相隔16字节)。分配(2,7)时,块地址开始递增24字节;同样,(3,4)将块分配为相隔16字节,但(3,5)将块分配为相隔24字节。并且,对于记录,(4,6)和(6,4)都返回32字节间隔的指针
这只是说明分配调用有一些开销。如果您查看K&R中malloc()等的原型实现,您将看到块的大小存储在您有权使用的内存之前。不同的实现方式做这些事情的方式不同;那些担心内存被破坏的人将避免将控制数据存储在用户可能造成严重破坏的地方
当您调用OC(4,6)时,您只能可靠地访问24字节的数据。即使实现返回的值相隔32个字节,也不能安全地使用超过请求的24个字节的值。以及malloc()wi的调试版本
0x826b008, 0x826b028, 0x826b048
0x95d2008, 0x95d2018, 0x95d2028
#include <stdlib.h>
#include <stdio.h>
int main()
{
int i, j, k;
for (i = 1; i < 17; i++)
for (j = 1; j < 9; j++)
for (k = 0; k < 4; k++)
printf("(%2d,%d)%d: %p\n", i, j, k, calloc(i, j));
return(0);
}
void * __libc_calloc (size_t n, size_t elem_size)
{
// ... (declarations)
/* size_t is unsigned so the behavior on overflow is defined. */
bytes = n * elem_size;
#define HALF_INTERNAL_SIZE_T \
(((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0))
{
if (elem_size != 0 && bytes / elem_size != n)
{
__set_errno (ENOMEM);
return 0;
}
}
void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
sz = bytes;
mem = (*hook)(sz, RETURN_ADDRESS (0));
if (mem == 0)
return 0;
return memset (mem, 0, sz);
}
sz = bytes;
// ...more stuff, but no mention of n & elem_size anymore
}