繁体   English   中英

如何正确初始化 C 中的结构

[英]How to correctly initialise a struct in C

我正在 C 中进行一个小项目,我想在 function 中分配结构并将它们添加到结构数组中。

出于某种原因,当我 go 打印结构数组的内容时,我似乎从未分配的 memory 开始打印。

下面提供了一个最小的工作示例:

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

// This struct simply stores a list and its size
struct list {
    int* values;
    size_t size;
};

// This function initialises an array of lists
// of size len, which each list (i.e. list.values)
// having a size of list_len
// `lists` is an array of pointers to lists
void list_init(struct list** lists, size_t len, size_t list_len) {
    for (size_t i = 0; i < len; i++) {
        struct list list;
        list.values = malloc(sizeof(int) * list_len);
        list.size = list_len;
        lists[i] = &list;
    }
}

void main() {
    int len = 3;
    struct list* lists[len];
    list_init(lists, len, 5);

    // Print lists
    for (size_t i = 0; i < len; i++) {
        printf("list %zu: ", i);
        printf("size: %zu\n", lists[i]->size);
        for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
            printf("%d ", lists[i]->values[j]);
        }
        printf("\n");
    }
}

我期望的 output 是:

list 0: size: 5
0 0 0 0 0
list 1: size: 5
0 0 0 0 0
list 2: size: 5
0 0 0 0 0

但我得到:

list 0: size: 5
0 0 0 0 0 
list 1: size: 140727488332736
0 0 0 0 0 
list 2: size: 140727488332736
0 0 0 0 0

这是一个非常明显的迹象,表明我正在访问我不应该访问的 memory。

我注意到,而不是用struct list list; ,如果我通过将 memory 分配给带有struct list* list = malloc(sizeof(struct list)); 该程序给出了预期的 output。这是为什么? 如果我想创建 object,而不是一个指针,我该如何正确地做到这一点。


PS:我知道我可以将list初始化为指针。 这个问题主要是问为什么我不能将它初始化为 object

这些语句在 function list_init

struct list list;
//...
lists[i] = &list;

没有意义,因为本地 object 列表在退出 function 后将不存在。因此您将拥有一个类型为struct list *的无效指针数组。

您需要动态分配数组元素指向的每个 object 类型的struct list

可以通过以下方式声明和定义 function

size_t list_init( struct list **lists, size_t len, size_t list_len ) 
{
    size_t count = 0;

    for ( size_t i = 0; i < len; i++ ) 
    {
        lists[i] = malloc( sizeof( struct list ) );
        
        if ( lists[i] != NULL )
        {
            ++count;
            
            lists[i]->size = 0;

            lists[i]->values = malloc( sizeof( int ) * list_len );
            
            if ( lists[i]->values != NULL ) lists[i]->size = list_len;
        }
    }

    return count;
}

此外,由于 function 没有初始化数据成员值指向的分配数组,因此在 main 中循环

    for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
        printf("%d ", lists[i]->values[j]);
    }

将调用未定义的行为。

您可以使用 calloc 而不是 malloc 对 arras 进行零初始化。例如

lists[i]->values = calloc( list_len, sizeof( int ) );

并注意根据 C 标准,不带参数的 function main 应声明如下

int main( void )

这是您更新的程序。

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

// This struct simply stores a list and its size
struct list 
{
    int* values;
    size_t size;
};

size_t list_init( struct list **lists, size_t len, size_t list_len ) 
{
    size_t count = 0;

    for ( size_t i = 0; i < len; i++ ) 
    {
        lists[i] = malloc( sizeof( struct list ) );
        
        if ( lists[i] != NULL )
        {
            ++count;
            
            lists[i]->size = 0;

            lists[i]->values = calloc( list_len, sizeof( int ));
            
            if ( lists[i]->values != NULL ) lists[i]->size = list_len;
        }
    }

    return count;
}


int main(void) 
{
    size_t len = 3;
    struct list* lists[len];
    
    list_init(lists, len, 5);

    // Print lists
    for ( size_t i = 0; i < len; i++ ) 
    {
        printf( "list %zu: ", i );
        
        if ( lists[i] != NULL )
        {
            printf( "size: %zu\n", lists[i]->size );
            for (size_t j = 0; j < lists[i]->size; j++) 
            {
                printf( "%d ", lists[i]->values[j] );
            }
            
            printf("\n");
        }           
    }
    
    return 0;
}

程序 output 是

list 0: size: 5
0 0 0 0 0 
list 1: size: 5
0 0 0 0 0 
list 2: size: 5
0 0 0 0 0 

当然,您需要在程序中添加一段代码,以释放 function list_init 中分配的所有list_init

您将引用保存到同一个局部变量,它是一个 UB。 malloced memory 也丢失了。 你的主要也是错误的。

我会这样做( calloc用作主要打印未初始化分配的内存):

typedef struct list {
    size_t size;
    int values[];
}list;

list **list_init(list **array, size_t size, size_t list_len) 
{
    list **wrk;
    if(!array) wrk = malloc(sizeof(*wrk) * size);
    else wrk = array; 
    if(wrk)
        for (size_t i = 0; i < size; i++) {
            list *list = calloc(1, sizeof(*list) + list_len * sizeof(list -> values[0]));
            /* check for allocation errors!!!! */
            list -> size  = list_len;
            wrk[i] = list;
        }
    return wrk;
}

int main(void) {
    size_t len = 3;
    list **lists;
    
    /* if you pass NULL it will create the list of lists itself */
    lists = list_init(NULL, len, 5);
    /* check for allocation errors!!!! */

    // Print lists
    for (size_t i = 0; i < len; i++) {
        printf("list %zu: ", i);
        printf("size: %zu\n", lists[i]->size);
        for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
            printf("%d ", lists[i]->values[j]);
        }
        printf("\n");
    }
    for (size_t i = 0; i < len; i++) free(lists[i]);
    free(lists);
}

https://godbolt.org/z/9TPe1sM1a

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM