我正在開發一個 C 語言的小專案,我想在一個函式中分配結構并將其添加到結構陣列中。
由于某些原因,當我要列印結構陣列的內容時,我似乎從未分配的記憶體開始列印。
下面提供了一個最基本的作業實體:
#include <stdio.h>/span>
#include <stdlib.h>
//這個結構只是簡單地存盤一個串列和它的大小。
struct list {
int* values;
size_t size。
};
//此函式初始化一個串列陣列。
//大小為len的陣列,每個串列(即list.values) //大小為len的陣列。
//有一個大小為list_len的串列。
//`lists`是一個指向串列的陣列。
void list_init(struct list**串列。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]; /span>
list_init(lists, len, 5)。
//列印串列。
for (size_t i = 0; i < len; i ) {
printf("list %zu: "/span>, i);
printf("size: %zu
", lists[i]->size)。)
for (size_t j = 0; j < 5; j ) { //使用5而不是lists[i]->size,原因很明顯。
printf("%d", lists[i]-> values[j])。
}
printf("
")。)
}
我所期望的輸出是:
list 0: size: 5: size: 5
0 0 0 0 0
list 1: size: 5: size: 5.
0 0 0 0 0
list 2: size: 5: size: 5.
0 0 0 0 0
但我得到的是:
list 0: size。5: 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
這是一個非常明顯的跡象,表明我正在訪問我不應該訪問的記憶體。
我注意到,如果我不是用 struct list list; 來宣告串列,而是用 struct list* list = malloc(sizeof(struct list)); 來分配記憶體到一個指標,程式會給出預期的輸出。這是為什么呢?如果我想創建物件,而不是一個指標,我怎樣才能正確地做到這一點呢。
P.S.: 我知道我可以直接將list初始化為一個指標。這個問題主要是問為什么不能我把它初始化為一個物件
uj5u.com熱心網友回復:
你把參考保存到同一個區域變數,它就是一個UB。同時malloced的記憶體也會丟失。你的main也是錯誤的。
我會這樣做。
我會這樣做(calloc被使用,因為在main中你列印了沒有初始化的分配記憶體):
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])。
/* 檢查分配錯誤!!!!。*/
list -> size = list_len;
wrk[i] = list;
}
return wrk;
}
int main(void) {
size_t len = 3;
list **lists;
/* 如果你傳遞NULL,它將自己創建串列*/。
lists = list_init(NULL, len, 5)。
/* 檢查分配錯誤!!!!。*/
//列印串列
for (size_t i = 0; i < len; i ) {
printf("list %zu: "/span>, i);
printf("size: %zu
", lists[i]->size)。)
for (size_t j = 0; j < 5; j ) { //使用5而不是lists[i]->size,原因很明顯。
printf("%d", lists[i]-> values[j])。
}
printf("
")。)
}
for (size_t i = 0; i < len; i ) free(list[i])。
free(lists)。
https://godbolt.org/z/9TPe1sM1a
uj5u.com熱心網友回復:
函式list_init
struct list list; /span>
//...
lists[i] = &list;
這樣做是沒有意義的,因為在退出函式后,本地物件串列將不復存在。所以你會有一個無效的指標陣列,其型別為struct list *。
你需要動態地分配每個struct list型別的物件,這些物件將被陣列中的一個元素所指向。
例如,可以用以下方式宣告和定義該函式
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;
}
另外,由于該函式沒有初始化資料成員值所指向的分配的陣列,所以main中的這個回圈
for (size_t j =0; j < 5; j ) { //使用5而不是lists[i]->size,原因很明顯。
printf("%d", lists[i]-> values[j])。
}
將呼叫未定義的行為。
你可以通過使用 calloc 而不是 malloc 來實作 arras 的零初始化。比如說
lists[i]->values = calloc( list_len, sizeof( int )。
而且要注意,根據C標準,不帶引數的函式main應該像這樣宣告
int main( void )/span>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/334246.html
標籤:
