C语言:为什么动态分配的对象返回一个指针,而静态分配的对象给你一个选择



这实际上是一个比我之前在这里问的问题(对于任何关心这个问题的人来说(更简洁、更清晰的问题:C语言:为什么malloc((返回指针而不是值?(很抱歉那些最初认为我在发垃圾邮件的人……我希望这不是同一个问题,因为我认为我在那里的措辞无意中误导了它(

->基本上,我想问的是:为什么C程序员需要一个指向动态分配的变量/对象的指针?(无论变量/对象之间有什么区别…(

如果C程序员可以选择只创建"int x"或"int*x"(两者都是静态分配的(,那么为什么他不能选择将动态分配的变量/对象初始化为变量(而不是通过malloc((返回指针(?

*如果有一些模糊的方法可以做到我上面解释的,那么,为什么malloc((似乎是大多数教科书关于动态分配的方式?

注意:在下文中,bytesizeof(char)

例如,malloc返回一个void *。它只是不能返回一个值:这在C缺乏泛型的情况下是不可行的。在C语言中,编译器必须在编译时知道每个对象的大小;由于分配的内存大小要到运行时才能知道,因此必须返回一个可以表示任何值的类型。由于void *可以表示任何指针,因此它是最好的选择。

malloc也无法初始化块:它不知道正在分配什么。这与C++的operator new形成了对比,后者同时执行分配和初始化,并且是类型安全的(可能由于历史原因,它仍然返回指针而不是引用(。

此外,malloc分配一个特定大小的内存块,然后返回一个指向该内存的指针(这就是malloc的意思:内存分配(。你得到了一个指针,因为这就是你得到的:一个统一的原始内存块。当您执行malloc(sizeof(int))时,您不是在创建int,而是在分配sizeof(int)字节并获取这些字节的地址。然后,您可以决定将该块用作int,但从技术上讲,您也可以将其用作sizeof(int) char s的数组。

各种备选方案(callocrealloc(的工作方式大致相同(calloc在处理数组时更容易使用,零填充数据,而realloc在需要调整内存块大小时很有用(。

假设您在函数中创建了一个整数数组并想要返回它。所述数组是函数的局部变量。不能返回指向局部变量的指针。

但是,如果使用malloc,则会在堆上创建一个范围超过函数体的对象。你可以返回一个指向它的指针。你只需要稍后销毁它,否则就会发生内存泄漏。

这是因为用malloc()分配的对象没有名称,所以在代码中引用该对象的唯一方法是使用指向它的指针

当你说int x;时,它会创建一个名为x的对象,并且它可以通过该名称引用。当我想将x设置为10时,我可以只使用x = 10;

我也可以设置一个指针变量,用int *p = &x;指向那个对象,然后我也可以用*p = 10;设置x的值。请注意,这一次我们可以在不具体命名x的情况下谈论它(除了我们获得对它的引用之外(。

当我说malloc(sizeof(int))时,它会创建一个没有名称的对象。我不能直接按名称设置该对象的值,因为它没有名称。但是,I可以通过使用指向它的指针变量来设置它,因为该方法不需要命名对象:int *p = malloc(sizeof(int));后面跟着*p = 10;

您现在可能会问:"那么,为什么我不能告诉malloc给对象一个名称?">——类似于malloc(sizeof(int), "x")。答案有两个:

  • 首先,C不允许在运行时引入变量名。这只是语言的一个基本限制
  • 其次,考虑到第一个限制,名称必须在编译时固定:如果是这种情况,C已经有了可以满足您需要的语法:int x;

您认为事情不对。这并不是说int x是静态分配的,malloc(sizeof(int((是动态的。两者都是动态分配的。也就是说,它们都是在执行时分配的。编译时没有为它们保留空间。大小在一种情况下可以是静态的,在另一种情况中可以是动态的,但分配总是动态的。

相反,它是int x分配堆栈上的内存,malloc(sizeof(int((分配堆上的内存。堆上的内存需要有一个指针才能访问它。堆栈上的内存可以直接引用,也可以用指针引用。通常您直接执行,但有时您希望使用指针算术对其进行迭代,或将其传递给需要指针的函数。

  1. 一切都使用指针。"int x"只是一种方便——某个地方的某个人厌倦了处理内存地址,这就是具有人类可读变量名的编程语言诞生的原因。

  2. 动态分配是…动态的。在程序运行之前,您不必知道程序运行时需要多少空间。你可以选择何时执行和何时撤消。它可能会失败。使用静态分配的简单语法很难处理所有这些。

  3. C的设计考虑到了简单性,编译器的简单性就是其中的一部分。这就是为什么您会接触到底层实现的怪癖。所有系统都存储静态大小的本地临时变量(寄存器、堆栈(;这就是静态分配所使用的。大多数系统都有用于动态、自定义生存期对象的存储,以及用于管理它们的系统调用;这就是动态分配所使用和公开的内容。

有一种方法可以满足你的要求,它叫做C++。在那里,"MyInt x = 42;"是一个或两个函数调用。

我想你的问题可以归结为:

如果C程序员可以选择只创建int xint *x(两者都是静态分配的(

第一条语句为一个整数分配内存。根据语句的位置,它可能会在当前执行的函数的堆栈上分配内存,也可能会在程序的.data.bss部分分配内存(如果它是全局变量或static变量,则位于文件范围或函数范围(。

第二条语句为指向整数的指针分配内存——它实际上并没有为整数本身分配内存。如果尝试使用指针*x=1分配值,则会收到非常快速的SIGSEGV分段冲突损坏一些随机内存。C没有预先调零堆栈上分配的内存:

$ cat stack.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    int i;
    int j;
    int k;
    int *l;
    int *m;
    int *n;
    printf("i: %dn", i);
    printf("j: %dn", j);
    printf("k: %dn", k);
    printf("l: %pn", l);
    printf("m: %pn", m);
    printf("n: %pn", n);
    return 0;
}
$ make stack
cc     stack.c   -o stack
$ ./stack
i: 0
j: 0
k: 32767
l: 0x400410
m: (nil)
n: 0x4005a0

ln指向内存中的某个值,但这些值只是垃圾,可能不属于可执行文件的地址空间。如果我们把任何东西存储到这些指针中,程序可能会死。不过,如果将不相关的结构映射到程序的地址空间中,它可能会破坏这些结构。

m至少是一个NULL指针——如果你试图写入它,这个程序肯定会在现代硬件上消亡。

这三个指针实际上还没有指向整数。那些整数的内存不存在。指针的内存确实存在,并且在本例中最初填充了垃圾值。

维基百科上关于L值的文章——大多过于迟钝,无法完全推荐——提出了一点,这对我第一次学习C:时来说是一个相当大的障碍。在有可分配变量的语言中,有必要区分变量的R值(或内容(和L值(或位置(

例如,您可以写:

int a;
a = 3;

这将整数值CCD_ 47存储到被分配用于存储变量CCD_。

如果你以后写:

int b;
b = a;

这将获取存储在a引用的内存中的值,并将其存储到为b分配的内存位置中。

使用指针的相同操作可能如下所示:

int *ap;
ap=malloc(sizeof int);
*ap=3;

第一个ap=分配将内存位置存储到ap指针中。现在ap实际上指向一些内存。第二个赋值*ap=将值存储到该内存位置中。它根本不更新ap指针;它读取存储在名为CCD_ 56的变量中的值以找到用于分配的存储器位置。

以后使用指针时,您可以选择使用与指针关联的两个值中的哪一个:指针的实际内容指针指向的值:

int *bp;
bp = ap; /* bp points to the same memory cell as ap */
int *bp;
bp = malloc(sizeof int);
*bp = *ap; /* bp points to new memory and we copy
              the value pointed to by ap into the
              memory pointed to by bp */

多年来,我发现组装比C容易得多,因为我发现foo = malloc();*foo = value;之间的区别令人困惑。我希望我发现了让你和困惑的地方希望我没有让事情变得更糟。

也许您误解了声明"int x"one_answers"int*x"之间的区别。第一个为int值分配存储;第二个没有——它只是为指针分配存储空间。

如果你要"动态分配"一个变量,那么动态分配无论如何都没有意义(除非你取了它的地址,这当然会产生一个指针(——你还可以静态地声明它。想想代码会是什么样子——你为什么要麻烦:

int x = malloc(sizeof(int)); *x = 0;

当你可以做:

int x = 0;

相关内容

  • 没有找到相关文章

最新更新