为什么 C 中结构的内存分配适用于给 malloc 的任何值?

Why memory allocation for a structure in C works with any value given to malloc?

我试图找到为如下所示的结构动态分配内存的正确方法:

typedef struct myThread {
    unsigned int threadId;
    char threadPriority;
    unsigned int timeSlice;
    sem_t threadSem;
} myThread;

我记得,但我不确定,在一些学校论文中,我看到为这种情况分配内存的正确方法是:

myThread *node = (myThread *)malloc(sizeof(myThread *));

我试过了并且成功了,但我不明白为什么。我的体系结构的 Sizeof 指针是 8 个字节,因此通过编写上面的指令,我分配了 8 个字节的连续内存,不足以保存我的结构中所需的信息。所以我尝试分配 1 个字节的内存,像这样:

myThread *node = (myThread *)malloc(1);

而且它还在工作。 我试图找到这种行为的答案,但没有成功。为什么这是有效的?除此之外,我还有几个问题:

谢谢

稍后编辑:感谢您的回答,但我意识到我没有正确解释自己。说它有效,我的意思是它可以在结构的那些特定字段中存储值并在以后使用它们。我通过填写字段并在之后打印它们来测试它。我想知道为什么这是有效的,为什么我可以填充和使用我只为其分配一个字节内存的结构字段。

你没有分配正确的尺寸

myThread *node = (myThread *)malloc(sizeof(myThread *));

正确的做法可以是例如

myThread *node = (myThread *)malloc(sizeof(myThread));

演员没用所以最后

myThread *node = malloc(sizeof(myThread));

或如对您的问题的评论所述

myThread *node = malloc(sizeof(*node));

原因是你分配的 myThread 不是指向的指针,所以要分配的大小是 myThread[=24 的大小=]

如果您分配 sizeof(myThread *),这意味着您需要 myThread ** 而不是 myThread *

I know that (*node).threadId is equivalent to node->threadI

是的,->取消引用而.没有

myThread node; 访问字段 threadId 你可以 node.threadId,但是有一个指针指向你需要以任何方式尊重


Later Edit: ...

当您从分配的块中访问时分配不足,行为未定义,这意味着任何事情都可能发生,包括立即可见的坏事

下面的工作原理是它们分配内存 - 但大小错误。

myThread *node = (myThread *)malloc(sizeof(myThread *));// wrong size,s/b sizeof(myThread) 
myThread *node = (myThread *)malloc(1);                 // wrong size 

Why is this working?

当代码尝试将数据保存到该地址时,错误的大小可能会或可能不会变得明显。它是 undefined behavior (UB)。

C 是没有 training wheels 的编码。当代码有 UB 比如没有分配足够的内存并使用它时,它不一定会失败,它可能会失败,现在或稍后或下周二。

myThread *node = (myThread *)malloc(1);  // too small
node->timeSlice = 42;  // undefined behavior

Which is the right way to dynamically allocate memory for a structure?

以下内容易于正确编码、审查和维护。

p = malloc(sizeof *p);  //no cast, no type involved.
// or
number_of_elements = 1;
p = malloc(sizeof *p * number_of_elements);

// Robust code does error checking looking for out-of-memory
if (p == NULL) {
  Handle_error();
}

Is that cast necessary?

没有。 Do I cast the result of malloc?

How is the structure stored in memory?

每个成员后面都有潜在的填充。它取决于实现。

unsigned int
maybe some padding
char
maybe some padding
unsigned int
maybe some padding
sem_t
maybe some padding

I wonder why is this working, why I can fill and work with fields of the structure for which I allocated just one byte of memory.

OP 正在寻找它起作用的原因。

也许内存分配是以 64 字节或超过 sizeof *p 的块为单位进行的,因此分配 1 与 sizeof *p.

具有相同的效果

也许后来由于代码使用分配不足而损坏的内存区域会在稍后出现。

也许分配器是一个玩弄 OP 的恶毒野兽,只是为了接下来擦除硬盘驱动器 April 1。 (恶意代码经常利用 UB 感染系统 - 这并非遥不可及)

全是UB。什么事都有可能发生。

由于 C 中的内存分配很容易出错,所以我总是定义宏函数 NEWNEW_ARRAY,如示例中所示以下。这使得内存分配更加安全和简洁。

#include <semaphore.h> /*POSIX*/
#include <stdio.h>
#include <stdlib.h>

#define NEW_ARRAY(ptr, n) \
    { \
        (ptr) = malloc((sizeof (ptr)[0]) * (n)); \
        if ((ptr) == NULL) { \
            fprintf(stderr, "error: Memory exhausted\n"); \
            exit(EXIT_FAILURE); \
        } \
    }

#define NEW(ptr) NEW_ARRAY((ptr), 1)

typedef struct myThread {
    unsigned int threadId;
    char threadPriority;
    unsigned int timeSlice;
    sem_t threadSem;
} myThread;

int main(void)
{
    myThread *node;
    myThread **nodes;
    int nodesLen = 100;

    NEW(node);
    NEW_ARRAY(nodes, nodesLen);
    /*...*/
    free(nodes);
    free(node);
    return 0;
}

malloc预留内存供您使用。

当您尝试使用比请求更多的内存时,可能会出现多种结果,包括:

  • 您的程序访问了它不应该访问的内存,但没有中断。
  • 你的程序访问了它不应该访问的内存,这会破坏你的程序需要的其他数据,所以你的程序失败了。
  • 您的程序试图访问未映射到其虚拟地址 space 的内存,并导致陷阱。
  • 编译器的优化以意想不到的方式转换您的程序,并出现奇怪的错误。

因此,当您未能分配足够的内存时您的程序似乎可以运行,或者当您未能分配足够的内存时您的程序中断,这都不足为奇。

Which is the right way to dynamically allocate memory for a structure?

好的代码是myThread *node = malloc(sizeof *node);

Is that cast necessary?

不,不在 C 中。

How is the structure stored in memory? I know that (*node).threadId is equivalent to node->threadId and this confuses me a bit because by dereferencing the pointer to the structure, I get the whole structure, and then I have to access a specific field. I was expecting to access fields knowing the address of the structure in this way: *(node) it's the value for the first element, *(node + sizeof(firstElement)) it's the value for the second and so on. I thought that accessing structure fields it's similar to accessing array values.

该结构作为字节序列存储在内存中,就像 C 中的所有对象一样。您不需要进行任何字节或指针计算,因为编译器会为您完成。例如,当你写node->timeSlice时,编译器取指针node,加上成员timeSlice的偏移量,并使用结果访问成员[=14=所在的内存] 已存储。