从动态分配的结构数组中释放特定元素

Freeing specific element from dynamically allocated array of structs

我有一个简单的结构s_personconstructor(int number),它接受我们想要构造的s_person的数量和returns指向它的指针。

在这个例子中,我构造了 2 个 s_person,并为它们的属性 name 赋值。并且有效。

#include<stdio.h>
#include<stdlib.h>
#define MAX_NAME 50
typedef struct s_person {
    char *name;
    double grade;
}s_person;

s_person* construct(int number){
    int each;
    s_person *person = (s_person*)malloc(sizeof(s_person) * number);
    if(person){
        for(each=0; each<number; each++){
            person[each].name = (char*)malloc(sizeof(char));
        }
    }
    return person;
}

main()
{
    s_person *person = construct(2);
    person[0].name = "steven";
    person[1].name = "michael";

    printf("%s %s\n", person[0].name, person[1].name);

    // This works
    free(&person[0]);
    printf("%s %s\n", person[0].name, person[1].name);

    //This doesn't work
    free(&person[1]); // Crashes here
    printf("%s %s\n", person[0].name, person[1].name);
}

当我尝试释放元素 0 并再次打印值时,它起作用了。

但是如果我尝试释放元素 1 并打印值它会崩溃。

那么,如何为这个结构数组中的特定元素释放内存?

使用 constructor(int number) 函数为结构数组动态分配内存是一种有效的方法还是有更好的做法?

您不能释放内存块的一部分。

在您的函数 construct 中,您分配了一个大小为 sizeof(s_person) * number 字节的内存区域。如果您尝试释放第一个元素,则会释放整个内存(请注意 &person[0] 等于 construct(2);.

返回的值

如果您尝试释放 &person[1],您将尝试释放一个未知的内存区域,而 free(&person[1]) 将失败。释放 invalid/unknown 内存区域不会导致崩溃。但是在您发布的代码中,您释放了 person 的整个内存区域,这在尝试获取 person[1] 的地址时导致访问冲突,这是您的 free 调用的输入.

如果你想释放单身人士,你可能想使用 linked lists 而不是一个巨大的数组......网络上有很多例子。

我在您的代码中发现了另一个问题。看看你的函数 construct 我注意到你为人物的名字分配了一个字节(但我猜你希望名字最多有 MAX_NAME 个字符)。因此,要么将 person[each].name = (char*)malloc(sizeof(char)); 修改为 person[each].name = (char*)malloc(sizeof(char) * MAX_NAME);,要么将您的代码更改为以下内容:

#define MAX_NAME 50
typedef struct s_person {
    char name[MAX_NAME];
    double grade;
}s_person;

s_person* construct(int number){
    s_person *person = (s_person*)malloc(sizeof(s_person) * number);
    return person;
}

我推荐后者,因为您不会忘记释放为每个人的姓名分配的内存,这使您的代码更容易维护。

您的程序有几个错误,其中大部分与内存分配和内存泄漏有关。

例如,在函数 construct 中,您为数据成员 name

分配了内存
    for(each=0; each<number; each++){
        person[each].name = (char*)malloc(sizeof(char));

然后主要覆盖这个值

person[0].name = "steven";
person[1].name = "michael";

因此您无法再访问分配的内存,也无法释放它。

至于这个说法

free(&person[1]); 

那你没有单独分配person[1]。您为结构的两个实例分配了一个范围。所以你只能释放这个分配的范围。

您可以在函数构造中通过分配指向结构的指针数组来分别分配结构的每个实例。在这种情况下,该函数将如下所示

s_person ** construct( int number )
{
    int each;

    s_person **persons =  ( s_person ** ) malloc( number * sizeof( s_person * ) );

    if ( persons != NULL )
    {
        for ( each = 0; each < number; each++ )
        {
            persons[each] = ( s_person * )malloc( sizeof( s_person ) );
            if ( persons[each] != NULL )
            {
                persons[each]->name = ( char* )malloc( MAX_NAME );
            }
        }
    }

    return persons;
}

并且在 main 中,您必须使用标准 C 函数 strcpy 来初始化具有字符串文字的已分配结构的数据成员 name

#include <string.h>

//...

int main( void )
//^^^^^^^^^^^^^^
{
    s_person **persons = construct( 2 );
    if ( persons[0] ) strcpy( persons[0]->name, "steven" );
    if ( persons[1] ) strcpy( persons[1]->name, "michael" );

    //...

在这种情况下,您可以删除每个单独的元素。例如

free( persons[0]->name );
free( persons[0] );
persons[0] = NULL;

free( persons[1]->name );
free( persons[1] );
persons[1] = NULL;

// and at last

free( persons );

为什么malloc personn可以使用栈:

#include<stdio.h>                                                              
#include<stdlib.h>                                                             
#define MAX_NAME 50                                                            
typedef struct s_person {                                                      
    char *name;                                                                
    double grade;                                                              
}s_person;                                                                     


main()                                                                         
{                                                                              
    s_person person[2];                                                        
    person[0].name = "steven";                                                 
    person[1].name = "michael";                                                

    printf("%s %s\n", person[0].name, person[1].name);                         
}