[英]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.