我是C的初学者。我想知道,malloc
是如何工作的。
这是一个示例代码,我在试图理解它的工作时写了。
CODE:
#include<stdio.h>
#include<stdlib.h>
int main() {
int i;
int *array = malloc(sizeof *array);
for (i = 0; i < 5; i++) {
array[i] = i+1;
}
printf("\nArray is: \n");
for (i = 0; i < 5; i++) {
printf("%d ", array[i]);
}
free(array);
return 0;
}
输出:
Array is:
1 2 3 4 5
在上面的程序中,我只为1个元素分配了空间,但现在该数组包含5个元素。因此,当程序顺利运行而没有任何错误时,realloc()
的目的是什么。
有人可以解释原因吗?
提前致谢。
答案 0 :(得分:6)
程序运行顺利并不意味着它是正确的!
尝试在某种程度上增加for循环中的5
(例如,500000
就足够了)。在某些时候,它将停止工作,为您提供SEGFAULT
。
这称为未定义行为。
valgrind
也会警告您有关以下内容的问题。
==16812== Invalid write of size 4
==16812== at 0x40065E: main (test.cpp:27)
如果你不知道valgrind
是什么,请查看:How do I use valgrind to find memory leaks?。 (顺便说一下,它是一个很棒的工具)
这有助于您提供更多说明:Accessing unallocated memory C++
答案 1 :(得分:3)
这是典型的undefined behavior(UB)。
您不能像这样编码。作为一个初学者,认为这是一个错误,一个错误,一个罪恶,一些非常肮脏的东西等。
有人可以解释原因吗?
如果您需要了解真正正在发生什么(并且细节很复杂),您需要深入了解您的实施细节(而且您并不想)。例如,在Linux上,您可以学习C标准库,内核,编译器等的源代码。您需要了解编译器生成的机器代码(所以使用GCC编译时gcc -S -O1 -fverbose-asm
获取.s
汇编程序文件。)
另请参阅this(其中包含更多参考资料)。
尽快阅读Lattner的博客What Every C programmer should know about undefined behavior。每个人都应该阅读它!
关于UB最糟糕的事情是,遗憾的是,有时,它出现到&#34;工作&#34;就像你想要的那样(但事实上并非如此)。
尽可能快地学习以系统地避免UB。
顺便说一下,启用编译器中的所有警告可能会有所帮助(但在您的特定情况下可能不会)。如果使用GCC,请习惯使用gcc -Wall -Wextra -g
进行编译。
请注意,您的程序没有任何数组。 array
变量是指针(不是数组),因此命名非常糟糕。您需要阅读有关指针和C dynamic memory allocation的更多信息。
int *array = malloc(sizeof *array); //WRONG
非常错误。名称array
的选择非常糟糕(它是一个指针,而不是一个数组;你应该花几天时间阅读有什么区别 - 以及#34;数组如何衰减成指针& #34;意思是)。您分配的sizeof(*array)
与sizeof(int)
完全相同(通常至少4个字节,至少在我的机器上)。因此,您只为一个 int
元素分配空间。除此之外的任何访问(即具有任何甚至小的正索引,例如array[1]
或array[i]
且具有一些正i
)都是undefined behavior。你甚至不能测试malloc
(可以发生)的失败。
如果你想为({比如说)8 int
- s分配内存空间,你应该使用:
int* ptr = malloc(sizeof(int) * 8);
当然你应该检查失败,至少:
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
你需要初始化那个数组(你的内存包含不可预测的垃圾),例如
for (int i=0; i<8; i++) ptr[i] = 0;
或者您可以使用
清除所有位(在我知道的所有机器上具有相同的结果)memset(ptr, 0, sizeof(int)*8);
请注意,即使在成功执行此类malloc
(或失败的sizeof(ptr)
之后,您总是malloc
相同(在我的Linux / x86-64框中,它是8个字节),因为它是指针的大小(即使你int
- 为一百万 #define MY_ARRAY_LENGTH 8
- s的内存区域。
实际上,当您使用C dynamic memory allocation时,您需要知道常规该指针的已分配大小。在上面的代码中,我在几个的地方使用了8个,这样的风格很差。至少
会更好MY_ARRAY_LENGTH
并使用8
,而不是 int* ptr = malloc(MY_ARRAY_LENGTH*sizeof(int));
,从
expectedDate = [int(i) for i in (input().split(" "))]
actualDate = [int(i) for i in (input().split(" "))]
在实践中,分配的内存通常具有运行时定义的大小,并且您将保留大小的某个位置(在变量,参数等中......)。
研究一些现有免费软件项目的源代码(例如在github上),您将学习非常有用的东西。
还阅读(可能在一两周内)flexible array members。有时它们非常有用。
答案 2 :(得分:1)
因此程序运行顺利,没有任何错误
那只是因为你很幸运。继续运行此程序,您可能很快就会出现段错误。您依赖未定义的行为(UB),这总是一件坏事。
realloc()
的目的是什么?
从手册页:
void *realloc(void *ptr, size_t size);
realloc()函数改变指向的内存块的大小 通过ptr来调整字节大小。内容将在该范围内保持不变 从该地区的起点到新旧规模的最小值。如果新尺寸大于旧尺寸,则添加 记忆 不会被初始化。如果ptr为NULL,则对于所有size值,调用等效于malloc(size);如果大小相等 零, 并且ptr不为NULL,则调用等效于free(ptr)。除非ptr为NULL,否则它必须由a返回 之前调用malloc(),calloc()或realloc()。如果指向的区域被移动,则完成免费(ptr)。