数组和malloc之间的区别

时间:2014-09-10 18:30:45

标签: c arrays memory-management malloc

这是我的代码:

#include<stdio.h>
#include <stdlib.h>

#define LEN 2

int main(void)
{

    char num1[LEN],num2[LEN];   //works fine with
                                //char *num1= malloc(LEN), *num2= malloc(LEN);
    int number1,number2;
    int sum;

    printf("first integer to add = ");
    scanf("%s",num1);

    printf("second integer to add = ");
    scanf("%s",num2);

    //adds integers
    number1= atoi(num1);
    number2= atoi(num2);
    sum = number1 + number2;

    //prints sum
    printf("Sum of %d and %d = %d \n",number1, number2, sum);

    return 0;
}

这是输出:

first integer to add = 15
second integer to add = 12
Sum of 0 and 12 = 12

为什么要使用0代替第一个变量15

无法理解为什么会这样。

如果我使用

,它工作正常
char *num1= malloc(LEN), *num2= malloc(LEN);

而不是

char num1[LEN],num2[LEN];

但它应该可以正常使用。

编辑:

是的,它适用于LEN 3,但为什么它会显示未定义的行为。我的意思是不使用normal arrays并使用malloc。现在我知道它也不适用于malloc。但为什么它对我有用,请具体说明我可以更准确地调试?

我的系统或编译器或IDE有问题吗?

请解释一下,因为它会有所帮助或提供任何资源链接。因为我不想再不幸了。

3 个答案:

答案 0 :(得分:4)

LEN为2,足以存储两个数字但不存储所需的空终止字符。因此,您超出了数组(以及代码版本中的堆分配!),这会导致未定义的行为。一个工作而另一个不工作的事实只是未定义行为如何在您的特定系统上发挥作用的副产品; malloc版本确实会在不同的系统或不同的编译器上崩溃。

当您调用未定义的行为时,正确的结果,错误的结果,崩溃或完全不同的东西都是可能的。

LEN更改为3,您的示例输入将正常工作。

我建议在scanf()行中指出缓冲区的大小,以避免未定义的行为。您可能会得到不正确的结果,但您的程序至少不会崩溃或存在安全漏洞:

scanf("%2s", num1);

请注意,您在那里使用的数字必须小于数组的大小 - 在此示例中,它假设一个大小为3的数组(因此您最多需要读取2个字符,因为您需要最后一个字符null终止字符。)

答案 1 :(得分:3)

LEN定义为2.您没有为空终结符留下空间。在数组的情况下,您将超出阵列末端并损坏堆栈。在malloc情况下,您会超出堆并可能损坏malloc结构。

两者都是未定义的行为。你不幸的是你的代码完全可以工作:如果你“幸运”,你的程序会决定在每种情况下崩溃,只是为了告诉你你正在触发未定义的行为。不幸的是,不是未定义的行为是如何工作的,所以作为C程序员,你只需要防御并避免进入未定义的行为情况。

为什么你要使用字符串呢?只需使用scanf("%d", &number1)即可避免所有这些。

答案 2 :(得分:1)

使用显式声明的数组或malloc - ed数组,您的程序“无法正常工作”(并且不应该“正常工作”)。像1512这样的字符串至少需要char个大小为3的缓冲区。您提供了大小为2的缓冲区。在两种情况下,您的程序都会超出缓冲区边界,从而导致未定义的行为。只是这种未定义行为的后果在不同版本的代码中表现出不同。

malloc版本有更大的机会产生“工作”的错觉,因为动态分配的内存块的大小通常四舍五入到最接近的实现依赖的“圆”边界(如8或{ {1}}字节)。这意味着您的16调用实际上分配的内存比您要求的多。这可能会暂时隐藏代码中出现的缓冲区溢出问题。这会产生你的程序“工作正常”的错觉。

同时,具有显式数组的版本使用本地数组。本地数组通常具有精确的大小(如声明的那样),并且还有更大的机会在内存中最终彼此相邻。这意味着一个数组中的缓冲区溢出很容易破坏另一个数组的内容。这正是你的情况。

然而,即使在基于malloc的版本中,我仍然期望标准库实现的良好调试版本能够捕获溢出问题。很有可能,如果您尝试malloc这些free - 内存块(您显然无需做的事情),malloc会注意到问题并告诉您在free之后的某个时刻违反了堆完整性。

P.S。不要使用malloc将字符串转换为整数。将字符串转换为整数的函数称为atoi