从已分配的内存中设置内存值

时间:2016-12-20 06:11:43

标签: c memory memory-management

我在学习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个字节)。这怎么可能?

1 个答案:

答案 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。