在字符串和结构数组中查找动态内存分配错误

Posted

技术标签:

【中文标题】在字符串和结构数组中查找动态内存分配错误【英文标题】:finding dynamic memory allocation errors in arrays of strings and structures 【发布时间】:2020-08-30 02:26:38 【问题描述】:

所以,我有一个名为vitorias(英文为“victories”)的结构数组、一个结构数组、一个该结构的数组和一个字符串数组。

结构和数组:

char **sistema_eq;

typedef struct

    int id;
    char nome[MAX_CHARS];
    int vit;
 vitorias;

问题是,当我使用cppcheck 时,它会报错:

(error) Common realloc mistake: 'conj_vit' nulled but not freed upon failure
(error) Common realloc mistake: 'sistema_eq' nulled but not freed upon failure
(error) Common realloc mistake: 'conj_jogos' nulled but not freed upon failure

而且,如果我使用Valgrind,它说我做了 10 次分配和 2 次释放,但我不明白出了什么问题,因为我认为我最终释放了所有东西。

程序:

#include<stdlib.h> 
#include<stdio.h>
#include <string.h>
#define MAX_CHARS 1024 /* max characters of a word */
#define MAX_SIZE 5

static int size_until = 0; /*conts the size of sistema_eq and conj_vit*/
static int line = 1; /* counts the number of lines of the stdin */
int ident = 0; /*conts the id of jogos*/
static int size_until = 0; /*counts the size of sistema_eq*/
static int size_until2 = 0;/*counts the size of conj_jogos*/

void a(char nome_jg[],char team1[],char team2[],int score1,int score2);
void A(char nome[]);

char **sistema_eq;
jogo *conj_jogos;
vitorias *conj_vit;

int main()

    char c;
    char nome_jg[MAX_CHARS], team1[MAX_CHARS], team2[MAX_CHARS];
    int score1;
    int score2;
    int i;

    conj_jogos = (jogo*)calloc(MAX_SIZE,sizeof(jogo));
    memset(conj_jogos,0, MAX_SIZE*sizeof(jogo));

    conj_vit = (vitorias*)calloc(MAX_SIZE,sizeof(vitorias));
    memset(conj_vit,0, MAX_SIZE*sizeof(vitorias));

    sistema_eq = (char**)calloc(MAX_SIZE,sizeof(*sistema_eq));
    memset(sistema_eq,0, MAX_SIZE*sizeof(*sistema_eq));

    for(i=0;i<MAX_SIZE;i++)
    
        sistema_eq[i] = (char*)calloc(1024,sizeof(char));
        memset(sistema_eq[i],0, sizeof(char)*1024);
    

    while ((c = getchar())!= 'x') 
    switch (c) 
    
        case 'A':
        
            scanf("%1023[^:\n]",nome_jg);
            remove_esp(nome_jg);
            A(nome_jg);
            break;
        
        case 'a':
        
            scanf("%1023[^:\n]:%1023[^:\n]:%1023[^:\n]:%d:%d",nome_jg,team1,team2,&score1,&score2);
            remove_esp(nome_jg);
            a(nome_jg,team1,team2,score1,score2);
            line++;
            break;
        
    
    
    free(conj_vit);
    free(conj_jogos);
    free(sistema_eq);
   return 0;


/*This functions adds a victory and a equipa (team in english) into the corresponding arrays and updates the vitories of each team*/

//Example in El Classico Barcelona vs Real Madrid 1:0, which means Barcelona won

void A(char nome[])

    if (nome_in_sis(nome) == 1)
    
        printf("%d Equipa existente.\n",line);
        line++;
    
    else
    
        if (size_until < MAX_SIZE)
        
            strcpy(sistema_eq[size_until],nome);
            strcpy(conj_vit[size_until].nome,nome);
            conj_vit[size_until].id = size_until;
            size_until++;
            line++;
        
        else
        
            conj_vit = realloc(conj_vit,sizeof(vitorias)*(size_until+1));
            sistema_eq = realloc(sistema_eq,sizeof(char*)*(size_until+1));
            sistema_eq[size_until] = calloc(1024,sizeof(char*));
            strcpy(sistema_eq[size_until],nome);
            strcpy(conj_vit[size_until].nome,nome);
            conj_vit[size_until].id = size_until;
            size_until++;
            line++;

        
    



/*This functions adds a jogo (game in english) and a equipa (team in english) into the array conj_jogos (the array of jogos)*/

void a(char nome_jg[],char team1[],char team2[],int score1,int score2)

    int vit;
    if (jogo_in(nome_jg) == 1)
    
        printf("%d Jogo existente.\n",line);
        line++;
    
    else if ((nome_in_sis(team1) == 0) || (nome_in_sis(team2) == 0))
        
        printf("%d Equipa inexistente.\n",line);
        line++;
    
    else
    
        if (size_until2 < MAX_SIZE)
        
            conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
            if (score1 > score2)
            
                vit = procura_vit(team1);
                conj_vit[vit].vit++;
            
            else
            
                vit = procura_vit(team2);
                conj_vit[vit].vit++;  
            
            size_until2++;
        
        else
        
            size_until2++;
            conj_jogos = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
            conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
            if (score1 > score2)
            
                vit = procura_vit(team1);
                conj_vit[vit].vit++;
            
            else
            
                vit = procura_vit(team2);
                conj_vit[vit].vit++;  
            
            size_until2++;
        
    

对不起,如果代码看起来很乱,并感谢您的帮助。

【问题讨论】:

Ctrl + F 您的代码并搜索 malloc/calloc's。然后搜索frees。对于每个分配,都需要一个免费的。您的代码并非如此:5 个 calloc 和 3 个 free。如果你在循环中分配了一些东西,那么你需要在循环中free它。 【参考方案1】:

正如 cmets 中所指出的,您永远不会在 for 循环中使用 calloc 分配的数据 free。在main 的末尾附近添加此循环(或非常类似的内容):

//...
    for(i=0;i<MAX_SIZE;i++) free(sistema_eq[i]); // MUST be before the next line!
    free(sistema_eq);
//...

此外,当您使用calloc 时,您不需要任何memset 调用!来自void* calloc( size_t num, size_t size ) 的链接文档:

为大小为 num 个对象的数组分配内存并初始化 分配存储中的所有字节都为零。

关于realloc 报告的“错误”:如果对realloc 的调用失败,您使用的代码将阻止随后释放原始 数据(其地址是在指针中),因为它的地址将被替换为NULL在这样的失败!为防止这种情况,请使用临时指针,如下所示:

    jogo* temp_jogo = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
    if (temp_jogo != NULL) conj_jogos = temp_jogo; 
    else 
    //  In case of failure, we now still have the original conj_jogos
    //  pointer, which we can then pass to "free" at some point, presumably
    //  after we've signalled and/or handled the allocation error.
    

最后(我认为),您可能喜欢阅读以下内容:Do I cast the result of malloc? - 这对于调用callocrealloc 同样有效。

【讨论】:

以上是关于在字符串和结构数组中查找动态内存分配错误的主要内容,如果未能解决你的问题,请参考以下文章

为具有双指针的结构内的动态结构数组分配内存**

对删除分配给结构数组的动态内存感到困惑

C语言之动态内存管理(动态内存分配+经典笔试题+柔性数组)[建议收藏]

指针数组的动态内存分配

4-数组指针与字符串1.4-动态内存分配

栈的动态内存分配数组