c-数组和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有问题吗?

请多解释一下,因为这会很有帮助,或者提供任何资源链接。因为我不想再倒霉了。

LEN是2,这足以存储两个数字,但不存储所需的null终止字符。因此,您正在溢出数组(以及该版本代码中的堆分配!),这将导致未定义的行为。一个有效,另一个无效,这只是未定义行为在特定系统中表现的副产品;malloc版本确实可能在不同的系统或不同的编译器上崩溃。

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

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

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

scanf("%2s", num1);

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

LEN定义为2。你没有给空终止符留下任何空间。在数组的情况下,你会越过数组的末端并损坏你的堆栈。在malloc的情况下,您将溢出堆并可能损坏malloc结构。

两者都是未定义的行为。你很不幸你的代码能正常工作:如果你"幸运",你的程序会决定在任何情况下崩溃,只是为了向你表明你正在触发未定义的行为。不幸的是,未定义行为并不是这样工作的,所以作为一名C程序员,你只需要保持防御,避免进入未定义行为的情况。

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

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

malloc版本有更大的机会产生"工作"的错觉,因为动态分配的内存块的大小通常被四舍五入到最近的取决于实现的"圆形"边界(如816字节)。这意味着malloc调用实际分配的内存比您要求的要多。这可能会暂时隐藏代码中存在的缓冲区溢出问题。这会产生程序"运行良好"的错觉。

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

然而,即使在基于malloc的版本中,我仍然希望有一个良好的标准库实现调试版本来解决溢出问题。很有可能,如果您尝试实际free这些malloc的内存块(这显然是您没有费心去做的),free会注意到问题,并告诉您在malloc之后的某个时刻违反了堆完整性。

附言:不要使用atoi将字符串转换为整数。将字符串转换为整数的函数称为strtol

相关内容

  • 没有找到相关文章