如何在C语言中使用malloc初始化静态指针?

10

我试图在C语言中的一个函数内部用malloc初始化一个静态变量,但是出现了"initializer not constant error" 的错误。我知道在C语言中不能使用非常数值进行静态初始化,但有没有人能想到解决办法?我需要代码具有与这个相同的效果:

static int *p = (int *)malloc(sizeof(int));

有什么诀窍或变通方法吗?

编辑:我有一个函数,每次标志位高时就会调用它。在这个函数中,我正在创建并启动一个新线程。我声明了一个指向结构体的指针,并使用malloc来分配内存,然后将该指针传递给线程。然后函数返回控制权。当我重新进入该函数时,最初打开的线程仍然在运行,我希望能够访问最初传递给该线程的内存区域。这就是为什么我需要一个静态变量,以便在第一次调用时进行malloc,然后在后续调用中使用相同的地址。这样我就可以从线程中获得信息。所有这些都是为了避免使用全局变量。

5个回答

22
static int *p = NULL;
if(!p) p = (int *)malloc(sizeof(int));

4
这个不需要两个变量,因此比被采纳的答案更好。 - Jonathan Leffler
1
@JonathanLeffler 我同意,尽管我的答案仍然有价值,因为它更通用 - 适用于没有指定空值的情况。 - Elazar

9
假设您想要功能静态变量:
int foo(void) {
    static int b=1;
    static int *p;
    if (b) {
        p =  malloc(sizeof(int));
        b = 0;
    }
    ...
}

在第一次调用之后,只要您知道它不会再是NULL,就可以使用空值作为p的检查。

记得检查malloc中的错误;它是一个运行时分配,并且在不再需要时也应该被释放。


谢谢您提供的解决方案!本质上,我想做的是让malloc只分配一次内存,并保持后续调用时相同的地址。这个方法完美地实现了我的需求。 - Arash Fotouhi
这个该怎么编译呢?那个“if…”语句必须放在一个类似于main()的函数内部,这样你就有普通运行时分配了。 - Lee Daniel Crocker
@LeeDanielCrocker - 我理所当然地假设这是在一个函数内部。当然,这是普通的运行时分配 - 这就是 OP 所要求的。 - Elazar
听起来你在谈论静态声明位于函数内部的情况。你最初的问题没有提到这一点;你问的是文件级别的静态变量。是的,这个答案也适用于在函数内部声明的静态变量。 - Lee Daniel Crocker
是的,你恰好假设了OP没有说的内容,所以你回答得很正确。我真傻,实际上回答了问题。 :-) - Lee Daniel Crocker
这段代码不是线程安全的,因此在编写库时特别糟糕。一个更好的方法是 static int foo, *p = &foo;,除非你真的需要通过 malloc 分配内存。当然,在任何情况下,你都应该使用适当的互斥锁来保护对静态对象的访问,或者最好根本不使用任何非 const 的静态对象。 - R.. GitHub STOP HELPING ICE

5

malloc() 只用于在运行时分配内存。静态变量在编译时初始化。你需要:

static int p[1];

如果您希望分配取决于第一次调用的参数,则此方法无法帮助。VLA 可能有所帮助,但我无法确定具体情况。 - Elazar
那么你确实是在运行时分配内存,需要使用malloc()而不是初始化器。这是两个不同的概念。 - Lee Daniel Crocker
是的,但这正是OP所要求的:在运行时为静态变量分配一次内存。 - Elazar

1
如果是文件静态的话,那么你需要在该文件中提供一个公共函数来初始化该静态变量。
void initialize () {
    if (p == 0) p = malloc(sizeof(*p));
}

或者,您可以使用静态函数代替静态变量。但每次访问都需要进行一次检查:

static int * p () {
    static int * p_;
    return p_ ? p_ : (p_ = malloc(sizeof(*p_)));
}

对于整数类型来说,这似乎有点傻,但如果p是一种比malloc()返回值更复杂的类型,需要更复杂的初始化序列,那么像这样有意义。

-2

C语言无法做到这一点。C++可以通过静态构造函数实现。

您可以在main()函数中或在任何其他在指针需要之前调用的函数中进行分配。

虽然不可移植,但某些可执行文件格式(例如经典Mac OS的代码片段管理器)支持初始化/终止入口点。CFM初始化用于C++静态构造。如果您的平台上的可执行文件格式支持初始化入口点,则可以使用该入口点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接