我在学习C中的动态内存分配时遇到了困难。我在main
中有这个。
int *a = malloc(sizeof(int));
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
*a = 4;
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
a = realloc(a, sizeof(int) * 2);
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
*(a + 1) = 8;
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
*(a + 2) = 16;
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
打印出来..
7417176 7405760 706735178
4 7405760 958328410
4 7405760 958328410
4 8 958328410
4 8 16
正如您所看到的,我将a
重新分配给了大约8个字节的新大小。但我初始化*(a + 2)
为16,而你可以看到我只分配了~8个字节而不是更多(它至少需要12个字节)。这怎么可能?
答案 0 :(得分:1)
当您访问尚未分配给程序的内存时,您的程序具有未定义的行为。
查看一些细节:
int *a = malloc(sizeof(int));
// This part is fine. It will try to allocate the amount of memory
// needed for storing exactly 1 int. It will assign the pointer a with
// with a value that points to the allocated memory.
但是,malloc
可能会失败(即无法分配所需的内存量),因此您必须检查它是否失败。如果malloc
失败,它将返回NULL。所以你需要添加:
if (a == NULL)
{
// malloc failed...
// print error
exit(1);
}
下一行是:
printf("%d %d %d\n", *a, *(a + 1), *(a + 2));
// This is undefined behavior:
// *a will read the value of the memory just malloc'ed as an int
// In principle that is OK but since you didn't initialize the
// memory, it is still undefined behavior
//
// *(a+1) and *(a+2) will read memory after the memory malloc'ed
// So you access memory not allocated to you. That is undefined
// behavior
所以你应该做的是1)首先初始化内存,2)只访问分配给你的内存。像:
*a = 42;
printf("%d\n", *a);
下一行:
a = realloc(a, sizeof(int) * 2);
// In principle this is valid. However, it is not good as realloc may
// fail just like malloc.
所以你应该这样做:
int* temp = realloc(a, sizeof(int) * 2);
if (temp == NULL)
{
// Error handling or just exit...
free(a);
exit(1);
}
a = temp;
对于其余的代码,您遇到的问题类似于上面提到的问题。
但是我将*(a + 2)初始化为16,而你可以看到我只分配了~8个字节而不是更多(它至少需要12个字节)。这怎么可能?
C语言不会检查您所做的一切是否有效。换句话说 - C让你做你想要的。确保您只做有效的事情是您自己的责任。
在运行时,系统可能会检测到程序正在执行非法操作。如果是这样,将发生崩溃(核心转储)。
但是,在许多情况下,系统无法检测到您的程序正在执行非法操作。所以该计划将继续进行。这可能会导致各种奇怪的错误,但它可能看起来好像程序是正确的,前100次执行它然后再次失败。这就是未定义的行为......未定义 - 你永远不会知道会发生什么。
因此,用C编码会给你带来很多负担。用C做非法的事很容易。你有责任确保你只做合法的事情。
今天有许多工具可用于分析C并找到错误的代码,例如: valgrind和coverity。