在结构内的结构内划出一个char *,导致valgrind丢失

时间:2014-09-02 10:24:24

标签: c

我目前正在学习C并尝试使用程序调试问题。

我已经将代码片段分成了一个单独的测试程序,并设法复制了故障,但我无法看到我的生活中出错的地方。我认为我最有可能在某个地方搞砸指针,但不确定在哪里。

以下是我的代码:

typedef int BOOL;
#define TRUE 1
#define FALSE 0

typedef struct CallLogSearchDataStruct
{
    char * target;
    float duration;
    struct CallLogSearchOutboundStruct * outboundLegs;
} callLogSearchDataStruct;

typedef struct CallLogSearchOutboundStruct
{
    char * target;
    float duration;
    BOOL allowOverwrite;
    struct CallLogSearchOutboundStruct *nextLeg;
} callLogSearchOutboundStruct;

callLogSearchOutboundStruct *insertOutboundLegtoList(callLogSearchOutboundStruct ** outboundLeg, char * target, float duration, BOOL overwriteFirstoutboundLegs);
void freeCallLogSearchDataStruct(callLogSearchDataStruct *callLogSearchData, int count);
void clearOutboundLinkedList(callLogSearchOutboundStruct **outboundLeg);
/*
 * 
 */
int main(int argc, char** argv) {

    int i = 0;
    int count = 10;
    callLogSearchOutboundStruct * outboundCallLegStartPtr = NULL;
    callLogSearchDataStruct * callLogSearchData = NULL;
    callLogSearchData = calloc(count, sizeof(callLogSearchDataStruct));

    for (i = 0; i < 10; i++)
    {   
    asprintf(&callLogSearchData[i].target, "Target %i", i);
    callLogSearchData[i].duration = i * 10;

    callLogSearchData[i].outboundLegs = malloc(sizeof(callLogSearchOutboundStruct));
    callLogSearchData[i].outboundLegs->target = NULL;
    callLogSearchData[i].outboundLegs->nextLeg = NULL;

    outboundCallLegStartPtr = callLogSearchData[i].outboundLegs;
    insertOutboundLegtoList(&outboundCallLegStartPtr, "OutboundTarget", i, FALSE);
    }

    freeCallLogSearchDataStruct(callLogSearchData, count);
    free(callLogSearchData);

    return (EXIT_SUCCESS);
}

callLogSearchOutboundStruct *insertOutboundLegtoList(callLogSearchOutboundStruct ** outboundLeg, char * target, float duration, BOOL overwriteFirstoutboundLegs)
{
    if (target == NULL)
    {
    return *outboundLeg;
    }

    if (!*outboundLeg)
    {
    callLogSearchOutboundStruct *newOutboundLeg = NULL;
    newOutboundLeg = malloc(sizeof(*newOutboundLeg));

    newOutboundLeg->nextLeg = NULL;
    newOutboundLeg->target = strdup(target);
    newOutboundLeg->duration = duration;
    newOutboundLeg->allowOverwrite = FALSE;
    *outboundLeg = newOutboundLeg;
    return newOutboundLeg;
    }
    if (overwriteFirstoutboundLegs == TRUE)
    {
    callLogSearchOutboundStruct * currentLeg = *outboundLeg;
    callLogSearchOutboundStruct * temp;

    free(currentLeg->target);
    currentLeg->target = strdup(target);
    currentLeg->duration = duration;
    currentLeg->allowOverwrite = FALSE;
    temp = currentLeg->nextLeg;
    while (temp)
    {
        temp->allowOverwrite = TRUE;
        temp = temp->nextLeg;
    }
    return currentLeg;
    }
    else
    {
    callLogSearchOutboundStruct **ptr = outboundLeg;
    callLogSearchOutboundStruct *currentLeg = *outboundLeg;

    if (currentLeg->target == NULL)
    {
        //This strdup is causing the loss record
        currentLeg->target = strdup(target);
        currentLeg->duration = duration;
        currentLeg->allowOverwrite = FALSE;
        *ptr = currentLeg;
        return currentLeg;
    }
    else
    {
        while (currentLeg && currentLeg->allowOverwrite == FALSE)
        {
        ptr = &currentLeg->nextLeg;
        currentLeg = currentLeg->nextLeg;
        }
        if (currentLeg)
        {
        currentLeg->target = strdup(target);
        currentLeg->duration = duration;
        currentLeg->allowOverwrite = FALSE;
        *ptr = currentLeg;
        return currentLeg;
        }
        else
        {
        currentLeg = malloc(sizeof(*currentLeg));
        currentLeg->nextLeg = NULL;
        currentLeg->target = strdup(target);
        currentLeg->allowOverwrite = FALSE;
        currentLeg->duration = duration;
        *ptr = currentLeg;
        }
    }
    return currentLeg;
    }
}

void freeCallLogSearchDataStruct(callLogSearchDataStruct *callLogSearchData, int count)
{
    int i = 0;
    for (i = 0; i < count; i++)
    {
    if (callLogSearchData[i].outboundLegs != NULL)
    {
        clearOutboundLinkedList(&callLogSearchData[i].outboundLegs);
        free(callLogSearchData[i].outboundLegs);
    }
    free(callLogSearchData[i].target);
    }
}

void clearOutboundLinkedList(callLogSearchOutboundStruct **outboundLeg)
{
    callLogSearchOutboundStruct *currentStruct = *outboundLeg;
    callLogSearchOutboundStruct *temp;

    while (currentStruct->nextLeg != NULL)
    {
        temp = currentStruct;
        currentStruct = currentStruct->nextLeg;
        free(temp->target);
        free(temp);
    }
}

以下是valgrind的输出

==10626== HEAP SUMMARY:
==10626==     in use at exit: 150 bytes in 10 blocks
==10626==   total heap usage: 41 allocs, 31 frees, 1,520 bytes allocated
==10626==
==10626== Searching for pointers to 10 not-freed blocks
==10626== Checked 47,612 bytes
==10626==
==10626== 150 bytes in 10 blocks are definitely lost in loss record 1 of 1
==10626==    at 0x40072D5: malloc (vg_replace_malloc.c:291)
==10626==    by 0xB0798F: strdup (in /lib/libc-2.12.so)
==10626==    by 0x80486F9: insertOutboundLegtoList (main.c:115)
==10626==    by 0x80485BA: main (main.c:55)
==10626==
==10626== LEAK SUMMARY:
==10626==    definitely lost: 150 bytes in 10 blocks
==10626==    indirectly lost: 0 bytes in 0 blocks
==10626==      possibly lost: 0 bytes in 0 blocks
==10626==    still reachable: 0 bytes in 0 blocks
==10626==         suppressed: 0 bytes in 0 blocks
==10626==
==10626== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 8)

从代码中的注释中可以看出,我检查currentLeg-&gt; target是否为NULL,如果是这样的话,我将char *强制转换为此变量,但Valgrind报告此strdup丢失但我看不到怎么样。由于计数器的缘故,我只能写一次,而我正在释放结构,所以不知道在哪里看。

感谢您提供的任何帮助。

1 个答案:

答案 0 :(得分:1)

我想我找到了你的问题,就在这个代码示例中:

`
    if (currentLeg)
       {
           currentLeg->target = strdup(target);
           currentLeg->duration = duration;
           currentLeg->allowOverwrite = FALSE;
           *ptr = currentLeg;
           return currentLeg;
       }
`

事实上,当你遇到这种情况时,你的currentLeg已经将其目标链接到一个duuped char *数组,最好检查currentLeg->target != NULL是否然后释放它:

`
    if (currentLeg)
       {
           if (currentLeg->target != NULL)
              free(currentLeg->target);
           currentLeg->target = strdup(target);
           currentLeg->duration = duration;
           currentLeg->allowOverwrite = FALSE;
           *ptr = currentLeg;
           return currentLeg;
       }
`

修改:我找到并修补了您的错误:

更改

`
      if (callLogSearchData[i].outboundLegs != NULL)
        {
          clearOutboundLinkedList(&callLogSearchData[i].outboundLegs);
          free(callLogSearchData[i].outboundLegs);
        }
` 

`
      if (callLogSearchData[i].outboundLegs != NULL)
        {
          clearOutboundLinkedList(&callLogSearchData[i].outboundLegs);
        }
` 

并将 while (currentStruct->nextLeg != NULL) 更改为 while (currentStruct != NULL) 实际上,链接列表的en从未正确释放 (对不起,我的英文不好)