为什么我需要分配内存?

时间:2013-02-06 11:47:09

标签: c arrays pointers malloc printf

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

void main()
{
char *arr;
arr=(char *)malloc(sizeof (char)*4);
scanf("%s",arr);
printf("%s",arr);
}

在上面的程序中,我真的需要分配arr吗? 即使不使用malloc也能给我结果。 我的第二个疑问是'我期待第9行出错,因为我认为一定是这样     的printf( “%S”,* ARR); 什么的。

4 个答案:

答案 0 :(得分:5)

  

我真的需要分配arr吗?

是的,否则您将取消引用未初始化的指针(即写入随机内存块),这是未定义的行为

答案 1 :(得分:0)

就个人而言,我认为这是分配内存的一个非常糟糕的例子。

在现代OS /编译器中,char *将占用至少4个字节,在64位机器上占用8个字节。因此,您使用四个字节来存储三个字符串的四个字节的位置。不仅如此,而且malloc将有开销,可能在实际分配的内存中增加16到32个字节。所以,我们使用20到40个字节来存储4个字节。这比实际需要的多5到10倍。

代码也会转换malloc,这在C中是错误的。

缓冲区中只有四个字节,scanf溢出的可能性很大。

最后,没有调用free将内存返回给系统。

使用它会更好:

int len;
char arr[5];
fgets(arr, sizeof(arr), stdin);
len = strlen(arr);
if (arr[len] == '\n') arr[len] = '\0';

这不会溢出字符串,只使用9个字节的堆栈空间(不计算任何填充...),而不是4-8个字节的堆栈空间,并且在堆上更多。我在数组中添加了一个额外的字符,以便它允许换行符。还添加了代码来删除fgets添加的换行符,否则会有人抱怨,我敢肯定。

答案 2 :(得分:0)

  • In the above program, do I really need to allocate the arr?
你打赌你做了。


  • It is giving me the result even without using the malloc.

当然,这完全有可能...... arr是一个指针。它指向一个内存位置。在你做任何事情之前,它是未初始化的...所以它指向一些随机的内存位置。这里的关键是它指向的地方是你的程序不能保证拥有的地方。这意味着您可以执行scanf()并在arr指向该值的随机位置,但另一个程序可以覆盖该数据。

当您说malloc(X)时,您告诉计算机您需要X字节的内存供您自己使用,而其他任何人都无法触及。然后当arr抓取数据时,它会安全地存在,直到您拨打free()您忘记在您的计划中执行BTW

这是一个很好的例子,说明为什么你应该在创建时始终初始化指向NULL的指针......它会提醒你,你没有拥有他们所指向的东西,你最好指出它们在使用之前有效的东西。


  • I am expecting an error in 9th line because I think it must be printf("%s",*arr)

不正确的。 scanf()需要一个地址,这是arr指向的地址,这就是您不需要这样做的原因:scanf("%s", &arr)。而printf的“%s”特定者想要一个字符数组(一个指向一串字符的指针),这又是arr,所以不需要尊重。

答案 3 :(得分:0)

  

我真的需要分配arr吗?

您需要将arr设置为指向您拥有的内存块,方法是调用malloc或将其设置为指向另一个阵列。否则它指向一个随机存储器地址,您可以访问或不可访问该地址。

在C中,不建议使用{sup> 1 来投射malloc的结果;它是不必要的,并且在某些情况下,如果您忘记包含stdlib.h或者在范围内没有malloc的原型,则可以屏蔽错误。

我通常建议将malloc次来电写为

T *ptr = malloc(N * sizeof *ptr);

其中T是您正在使用的任何类型,N是您要分配的该类型的元素数。 sizeof *ptr相当于sizeof (T),因此如果您更改T,则无需在malloc调用本身中复制该更改。只需少一点维护头痛。

  

即使不使用malloc

,它也会给我结果

因为您没有在声明中显式初始化它,arr的初始值是不确定 2 ;它包含一个随机位字符串,可能对应于有效的可写地址,也可能不对应。尝试读取或写入无效指针的行为是 undefined ,这意味着编译器没有义务警告您正在做一些危险的事情。关于未定义行为的可能结果是您的代码出现以按预期工作。在这种情况下,看起来你正在访问一个恰好可写的内存的随机段,并且不包含任何重要内容。

  

我的第二个疑问是'我期待第9行出错,因为我认为它必须是printf(“%s”,* arr);什么的。

%s转换说明符告诉printf相应的参数类型为char *,因此printf("%s", arr);是正确的。如果您使用了%c转化说明符,那么您需要使用arr运算符或下标(例如*或{{1}取消引用printf("%c", *arr); }}。

此外,除非您的编译器文档明确将其列为有效签名,否则printf("%c", arr[i]);定义为main;请改用void main()int main(void)

<小时/> 1。在C ++中需要强制转换,因为C ++不允许在没有显式转换的情况下将int main(int argc, char **argv)值分配给其他指针类型
2。对于在块范围内声明的指针,情况也是如此。在文件范围(任何函数之外)或void *关键字声明的指针被隐式初始化为NULL。