简体   繁体   English

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

[英]How to correctly initialise a struct in C

I'm working on a small project in C and I want to allocate structs in a function and add them to an array of structs.我正在 C 中进行一个小项目,我想在 function 中分配结构并将它们添加到结构数组中。

For some reason, when I go to print the contents of the array of structs, I appear to start printing from unallocated memory.出于某种原因,当我 go 打印结构数组的内容时,我似乎从未分配的 memory 开始打印。

A minimum working example is provided below:下面提供了一个最小的工作示例:

#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");
    }
}

The output I would expect from this is:我期望的 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

but instead I get:但我得到:

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

which is a pretty clear sign that I'm accessing memory that I'm not supposed to.这是一个非常明显的迹象,表明我正在访问我不应该访问的 memory。

I noticed that rather than declaring the list with struct list list;我注意到,而不是用struct list list; , if I declare the list by allocating memory to a pointer with struct list* list = malloc(sizeof(struct list)); ,如果我通过将 memory 分配给带有struct list* list = malloc(sizeof(struct list)); the program gives the expected output. Why is that?该程序给出了预期的 output。这是为什么? If I want to create the object, rather than a pointer, how can I do that properly.如果我想创建 object,而不是一个指针,我该如何正确地做到这一点。


PS: I am aware that I could just initialise list as a pointer. PS:我知道我可以将list初始化为指针。 This question is mostly asking why can't I initialise it as an object这个问题主要是问为什么我不能将它初始化为 object

These statements within the function list_init这些语句在 function list_init

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

does not make a sense because the local object list will not be alive after exiting the function. So you will have an array of invalid pointers of the type struct list * .没有意义,因为本地 object 列表在退出 function 后将不存在。因此您将拥有一个类型为struct list *的无效指针数组。

You need to allocate dynamically each object of the type struct list that will be pointed to by an element of the array.您需要动态分配数组元素指向的每个 object 类型的struct list

The function can be declared and defined for example the following way可以通过以下方式声明和定义 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;
}

Also as the function does not initialize the allocated array pointed to by the data member values then this loop in main此外,由于 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]);
    }

will invoke undefined behavior.将调用未定义的行为。

You could zero initialize the arras by using calloc instead of malloc. For example您可以使用 calloc 而不是 malloc 对 arras 进行零初始化。例如

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

And pay attention to that according to the C Standard the function main without parameters shall be declared like并注意根据 C 标准,不带参数的 function main 应声明如下

int main( void )

Here is your updated program.这是您更新的程序。

#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;
}

The program output is程序 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 

Of course you need to add a code to your program that will free all the allocated memory in the function list_init .当然,您需要在程序中添加一段代码,以释放 function list_init 中分配的所有list_init

You save the references to the same local variable and it is an UB.您将引用保存到同一个局部变量,它是一个 UB。 Also malloced memory is lost. malloced memory 也丢失了。 Your main is also wrong.你的主要也是错误的。

I would do it this way ( calloc is used as in main you print not initialized allocated 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 https://godbolt.org/z/9TPe1sM1a

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

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