4

在一些内存分配中,我发现了这一点。但我不明白。

char * mem_alloc()
{   
    char *point;
    char *a;
    point = (char *)malloc(block_num);

    a = *(char**) point;
    return a;
}   
4

6 回答 6

8

char * mem_alloc()

以我的经验,返回指针的函数几乎总是程序设计有缺陷的标志。这样的指针可以指向以下内容:

  • 局部变量(公然错误,UB)
  • 全局/静态(糟糕的程序设计,也不是线程安全的)
  • 动态内存(糟糕的程序设计,使用内存的代码应该处理分配,泄漏的可能性很大)
  • 或传递给函数的参数之一(糟糕的程序设计,晦涩的函数接口)

在这种情况下,它指向动态内存,因此我们可能会假设程序设计不佳并且可能存在内存泄漏。

point = (char *)malloc(block_num);

这段代码意味着编写它的人对 malloc 的工作方式和 void 指针的工作方式感到困惑。malloc 的结果不应该进行类型转换,请参见thisthis。类型转换的冲动意味着程序员对 C 语言感到困惑,和/或他们试图在 C++ 编译器上编译 C 代码。

“block_num”是可疑的,如果这是一个全局的、非常量的变量,那么程序设计很差。

a = *(char**) point;

这意味着,获取指向堆上未初始化内存的点的地址,然后假设该点是一个指向指针的指针,从而将堆的垃圾内容视为指针。然后将该指针返回给调用者,该指针指向 la-la 土地中的一个随机位置。在这样做的同时,会造成内存泄漏。

于 2012-06-11T06:48:20.890 回答
0

这似乎设置了一个指向点的值(这是一个地址)。
a = *(char**) point;
上面的语句是类型转换指向 - `(char**) point' 部分中的“pointer to a pointer”。在此之后,您将 * 用于取消引用,将其更改
为(指向指针的指针)
=> 指针的值。
因此,存储在 point 中的值(而不是地址)被复制到 a 中。
我仍然不确定为什么要编写这种代码。

于 2012-06-11T05:32:19.673 回答
0

您发布的代码很愚蠢-您确定它是完整的吗?

“point”和“a”都是指针。

"a" 被初始化为 "point" ...但 "point" 完全是uninitialized。如果调用者试图使用返回值“a”,就会发生不好的事情。

这是另一个例子:

struct Point {
  int x;
  int y;
};

...

char * mem_alloc (int size)
{
  return (char *)malloc (size);
}

...
  Point *my_point = (Point *)mem_alloc (sizeof (struct Point));
  ...

这个片段也很愚蠢......但希望它说明了你正在查看的代码背后的一些基本原理......

于 2012-06-11T05:34:10.903 回答
0

a包含存储在 指向的位置的值point。由于point未初始化,它指向一个包含随机值的随机位置,因此现在a指向它开始的随机值。

所以代码是无操作的。

于 2012-06-11T05:40:40.793 回答
0

如果你看 的概念malloc,它总是返回分配的内存空间的基地址,malloc函数的实际语法是语法:

pointer_to_store_base_add_of_mem = (data_type_of_allocated_memory)malloc(size_of_array)

在上面的示例中,您已经分配了内存的字符类型,因此您使用了 (char*),并且在 block_num 中您已经给出了字符数组的大小,并且点指针存储了分配内存的基地址。

于 2012-06-11T08:25:12.553 回答
0

查看在 Lundin 的回答的评论中发布的代码 chenyoufu123:

ptr = (char *)malloc(block_num * size);
for(k=0; k<block_num-1; k++) {
    *((char **)(ptr + k*size)) = ptr + (k+1) * size;
}
*((char **)(ptr + k*size)) = NULL;

那仍然是糟糕的代码,但与问题中的原始代码相比并非完全没有意义。特别是与它用于从另一个评论创建链接列表的注释一起。

情况是——假设代码是“正确的”——你有一个

struct Node
{
    struct Node *next;
    /* More members */
};

size_t size = sizeof(struct Node);(名称可能会有所不同)。然后

ptr = (char *)malloc(block_num * size);

block_num为连续struct Node的 s分配内存。人们通常会将其分配为

struct Node *ptr = malloc(block_num * sizeof *ptr);

循环

for(k=0; k<block_num-1; k++) {
    *((char **)(ptr + k*size)) = ptr + (k+1) * size;
}
*((char **)(ptr + k*size)) = NULL;

k * sizeof(struct Node)然后将内存块开头后面的地址重新解释ptr + k*size为指向指针的指针(a char**,但在当今的大多数 PC 体系结构中,这并不重要,因为所有对象指针都具有相同的表示形式 - 如果它很重要,则代码被破坏无论如何)并将下一个sizeof(struct Node)大小的内存块的地址写入该位置。由于next指针是 的第一个成员,因此将列表中struct Node下一个的地址写入当前的指针。最后,最后的指针设置为。struct Nodenextstruct Nodenextstruct NodeNULL

通常的写法,

struct Node *ptr = malloc(block_num * sizeof *ptr);
int k;
for(k = 0; k < block_um - 1; ++k)
{
    ptr[k].next = &ptr[k+1]; // or ptr + (k+1), if you prefer
}
ptr[block_num-1].next = NULL;

不仅更清晰,它还具有在具有不同大小或表示的平台char*上工作的优势。struct Node*

于 2012-06-11T10:37:43.557 回答