[英]Difference between array and 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,足以存储两个数字但不存储所需的空终止字符。 因此,您超出了数组(以及代码版本中的堆分配!),这会导致未定义的行为 。 一个工作而另一个不工作的事实只是未定义行为如何在您的特定系统上发挥作用的副产品; malloc版本确实可以在不同的系统或不同的编译器上崩溃。
当您调用未定义的行为时,正确的结果,不正确的结果,崩溃或完全不同的东西都是可能的。
将LEN
更改为3,您的示例输入将正常工作。
我建议在scanf()
行中指出缓冲区的大小,以避免未定义的行为。 您可能会得到不正确的结果,但您的程序至少不会崩溃或存在安全漏洞:
scanf("%2s", num1);
请注意,您在那里使用的数字必须小于数组的大小 - 在此示例中,它假定大小为3的数组(因此您最多读取2个字符,因为您需要空终止字符的最后一个字符)。
LEN
定义为2.您没有留下空终止符的空间。 在数组的情况下,您将超出阵列末端并损坏堆栈。 在malloc
情况下,你会超出你的堆并可能损坏malloc
结构。
两者都是未定义的行为。 你不幸的是你的代码完全可以工作:如果你“幸运”,你的程序会决定在每种情况下崩溃,只是为了告诉你你正在触发未定义的行为。 不幸的是,这不是未定义的行为是如何工作的,因此作为C程序员,您只需要保持防御并避免进入未定义的行为情况。
无论如何,你为什么要使用字符串? 只需使用scanf("%d", &number1)
就可以避免所有这些。
使用显式声明的数组或malloc
-ed数组,您的程序“工作正常”(并且不应该“正常工作”)。 像字符串15
和12
需要char
大小的缓冲区3
至少。 您提供了大小为2
缓冲区。 在两种情况下,您的程序都会超出缓冲区边界,从而导致未定义的行为。 只是这种未定义行为的后果在不同版本的代码中表现出不同。
malloc
版本有更大的机会产生“工作”的错觉,因为动态分配的内存块的大小通常舍入到最接近的实现依赖的“round”边界(如8
或16
字节)。 这意味着你的malloc
调用实际上分配的内存比你要求的多。 这可能会暂时隐藏代码中出现的缓冲区溢出问题。 这会产生你的程序“工作正常”的错觉。
同时,具有显式数组的版本使用本地数组。 本地数组通常具有精确的大小(如声明的那样),并且还有更大的机会在内存中最终彼此相邻。 这意味着一个数组中的缓冲区溢出很容易破坏另一个数组的内容。 这正是你的情况。
但是,即使在基于malloc
的版本中,我仍然期望标准库实现的良好调试版本能够捕获溢出问题。 很有可能,如果你试图实际free
这些malloc
-ed内存块(你显然不愿意这样做), free
会注意到这个问题,并告诉你在malloc
之后的某些时候违反了堆的完整性。
PS不要使用atoi
将字符串转换为整数。 将字符串转换为整数的函数称为strtol
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.