在C语言中,分配内存的所有方法是什么?它们有什么不同?
我知道以下几点:在C语言中,分配内存的所有方法是什么?它们有什么不同?,c,dynamic-memory-allocation,C,Dynamic Memory Allocation,我知道以下几点: 马洛克 卡洛克 realloc 它们之间有什么区别?为什么malloc看起来几乎是唯一被使用的?编译器之间是否存在行为差异?malloc分配内存。内存的内容保持原样(填充以前存在的内容) calloc分配内存并将其内容设置为全零 realloc更改现有已分配内存块的大小,或将现有内存块的内容复制到请求大小的新分配内存块中,然后取消分配旧块 显然,realloc是一种特殊情况。如果您没有旧的内存块来调整大小(或复制并释放),那么就没有理由使用它。通常使用malloc而不是ca
- 马洛克
- 卡洛克
- realloc
它们之间有什么区别?为什么malloc看起来几乎是唯一被使用的?编译器之间是否存在行为差异?
malloc
分配内存。内存的内容保持原样(填充以前存在的内容)
calloc
分配内存并将其内容设置为全零
realloc
更改现有已分配内存块的大小,或将现有内存块的内容复制到请求大小的新分配内存块中,然后取消分配旧块
显然,realloc
是一种特殊情况。如果您没有旧的内存块来调整大小(或复制并释放),那么就没有理由使用它。通常使用malloc
而不是calloc
的原因是,将内存设置为全零会带来运行时成本,如果您计划立即用有用的数据填充内存(这是很常见的),那么首先将其归零没有意义
这些函数都是标准函数,在编译器中运行可靠。calloc很可能只是实现为类似于:
void * calloc(size_t nmemb, size_t size) {
size_t len = nmemb * size);
void * ptr = malloc(len);
if (ptr) {
return memset(ptr, 0, len);
}
return ptr;
}
所以它只是在malloc之前加一个乘法,在malloc之后加一个clear
malloc可以(但可能永远不会)实现为:
void * malloc(size_t size) {
return realloc(NULL, size);
}
因为您可以将一个空指针作为前一个指针传递给realloc,但是malloc很可能不是这样实现的,因为它会减慢所有malloc的速度,并且realloc可能使用malloc
关于realloc,需要了解的主要内容是,它通常能够确定任何堆分配例程返回的内存块的实际大小,并查看该块是否已经足够大,或者在某些情况下,是否最好尝试收缩或移动该块
void realloc(void * ptr, size_t size) {
size_t alen = MALLOC_LENGTH_OF(ptr); // this just stands for some method of determining
// the size of the block that was allocated, and could
// be looking it up in a table or looking at a place
// several bytes before the pointer, or some other
// implementation specific thing
if (0 == size) {
free(ptr);
return NULL;
}
if (alen >= size) {
return ptr; // big enough, and not worrying about it being too big
}
void new_ptr = malloc(size); // since I said that malloc most likely isn't
// implemented using realloc using malloc here is ok
if (new_ptr && ptr) {
memcpy(new_ptr, ptr, alen);
}
free(ptr);
return new_ptr;
}
Malloc使用较多,因为它最简单。程序员通常可以使他们的分配足够大,这样他们就不必担心用realloc调整它们的大小,而且通常不需要清除内存
不同的库之间有不同的行为,您甚至可以将程序与其他版本链接,以获得不同的行为,而无需更改编译器
一些malloc库用于调试和错误检测。其他可能提供更好的性能。有些优化了同时为几个不同的线程分配内存,避免了不同的线程需要锁定整个堆来执行分配或释放
不过,从应用程序的角度来看,它们都应该提供相同的语义 除了您提到的那些(有些是扩展):
- 堆栈上的变量也是动态分配的。递归是一种分配和使用它的方法李>
- C99具有可变长度数组(正如BlueRaja提到的)
- 在某些系统上,您甚至有一个
调用,允许您在stackframe中分配可变长度的块alloca
- POSIX具有内存段和文件的映射,具有
或shm_open
和open
的组合mmap
- SysV IPC有
etc调用shmget
因此,如果i在0到3之间变化scanf(“%d”,ptr+i)在4个相邻位置存储4个整数ptr具有第一个整数的地址,ptr+1具有第二个数字的地址,依此类推。 因此printf(“%d”,atstrick(ptr+i))将打印相应的值。 与为变量和数组分配的内存不同,动态分配的内存没有与之关联的名称。如上所述 calloc:它与malloc相似,只是有两个区别:
1. 声明:ptr=(int*)calloc(5,sizeof(int));这里我们有两个参数,5是分配的块数,第二个参数等于4字节。这相当于ptr=(int*)malloc(5*sizeof(int))2。在calloc中,初始分配的内存不是垃圾,而是0。如果堆中没有足够的可用内存,malloc和calloc都返回NULL 不要忘记:)
calloc
对于分配结构数组特别有用,因为它需要两个参数:calloc(项目的数量、项目的大小)
。用有用的数据填充这样一个数组需要更多的工作(正如泰勒所说),因此有一个公平的理由支持将内存初始化为已知(零)值的额外成本。calloc
还具有为您执行乘法的优势,因此,在无错误的实现中,它将检查溢出并失败。您没有提到strdup
或asprintf
,它们也会分配内存。投票反对在与块相同的行上使用开始大括号!(不是真的tho)@Firoso:这样做可以使diff在比较版本时产生更好的输出,同时可以缩减代码。由于我还在单行块周围使用大括号,因此将它们与块开头代码放在同一行确实很有帮助。如果您提到diff-p选项,我相信启发性的做法是,如果一行在第1列有字母,则该行包含函数名。正如R.在其他地方所说,在许多实现中使用calloc()(包括glibc、FreeBSD libc和HP-UX libc IIRC)检查整数溢出,以