函数范围之外的动态分配

Dynamic allocation outside the scope of a function

提问人:3sm1r 提问时间:1/17/2023 最后编辑:Vlad from Moscow3sm1r 更新时间:1/17/2023 访问量:85

问:

如果我想创建一个用作全局变量的数组,如果我已经知道大小,我可以这样做:

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

int array[]={1,1,1,1};

int main()
{
    printf("%d", array[0]);
}

但是,这不适用于 。事实上,以下代码malloc

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

int* array=malloc(4*sizeof(int));

int main()
{
    printf("%d", array[0]);
}

将返回错误 ()。然而,如果我尝试在函数范围内做同样的事情,那就没有问题了。error: initializer element is not constant

我相信我一定缺少一些关于动态分配如何工作的东西。

这是怎么回事?如何在任何函数的作用域之外动态定义数组并将它们用作全局变量?

数组 c 初始化 malloc 存储持续时间

评论

3赞 Eugene Sh. 1/17/2023
将 的定义保留在函数外部,但在函数中将其与结果一起分配。arraymalloc
0赞 chux - Reinstate Monica 1/17/2023
@EugeneSh。如果“赋值”不是数组,而是指针,则“赋值”的建议是有道理的。Array
0赞 Eugene Sh. 1/17/2023
@chux-恢复莫妮卡当然。我解决了第二个片段,其中是一个指针。array
0赞 Fe2O3 1/17/2023
示例 1 是“编译时分配”。示例 2 想要“运行时分配”...可执行代码(即:“运行时”)只能出现在函数内部,而不能出现在函数外部。

答:

4赞 0___________ 1/17/2023 #1

在 C 语言中,代码只能在函数体中执行。

第二个代码无效,因为您尝试在函数外部调用。malloc

在 C 中使用全局变量被认为是一种不好的做法,因此如果不是 100% 必要,请尽量避免使用。

如果要有一个全局指针:

int *array;

int main(void)
{
     array = malloc(100);
     /* .... */
}

某些编译器支持非标准扩展。例如,在 GCC 中,可以使用该属性在调用函数之前执行代码main

int* array;

void __attribute__((constructor)) aray_const(void)
{
    array = malloc(4 *sizeof(*array));
    if(array) memcpy(array, (int[]){1,2,3,4}, 4 * sizeof(*array));
}

int main()
{
    printf("%d %d %d %d\n", array[0], array[1], array[2], array[3]);
     /* .... */
}

https://godbolt.org/z/bz4YjzfK5

3赞 Vlad from Moscow 1/17/2023 #2

在 C 语言中,具有静态存储持续时间的对象可以通过常量表达式进行初始化。在文件作用域的第二个程序中声明的指针与在文件作用域中声明的任何对象一样具有静态存储持续时间。array

从 C 标准(6.7.9 初始化)

4 初始值设定项中具有静态对象的所有表达式 或线程存储持续时间应为常量表达式或字符串 文字。

此外,该函数还会分配未初始化的内存。所以printf的这个调用malloc

printf("%d", array[0]);

在任何情况下都可以调用未定义的行为。

例如,您可以使用 main 中的赋值运算符以下列方式重写程序

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

int *array;

int main( void )
{
    size_t n = 4;
    array = malloc( n * sizeof( int ) );

    if ( array != NULL )
    {
        int value = 1;
        for ( size_t i = 0; i < n; i++ )
        {
            array[i] = value++;
        }

        for ( size_t i = 0; i < n; i++ )
        {   
            printf( "%d ", array[i] );
        }
        putchar( '\n' );
    }

    free( array );
}

或者你可以用 function 代替 .在这种情况下,分配的内存将初始化为零。callocmalloc

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

int *array;

int main( void )
{
    size_t n = 4;
    array = calloc( n, sizeof( int ) );

    if ( array != NULL )
    {
        for ( size_t i = 0; i < n; i++ )
        {   
            printf( "%d ", array[i] );
        }
        putchar( '\n' );
    }

    free( array );
}

请注意,当不再需要分配的内存时,应始终释放已分配的内存。

评论

0赞 user253751 1/17/2023
之所以这样,是因为编译器计算出全局变量中的所有字节,并将它们直接存储在程序文件中。如果调用类似 malloc 的东西,编译器不知道变量中有哪些字节。当它仍在编译时,它不能调用 malloc。
1赞 Eric Postpischil 1/17/2023
回复 “此外,函数 malloc 分配未初始化的内存。因此,在任何情况下,printf 的调用都会调用未定义的行为。它必须打印一个值。如果实现在类型中确实具有陷阱表示形式,则代码可能会生成陷阱,但必须打印值。printf("%d", array[0]);intintintint