简体   繁体   English

具有内存重新分配结构和链接列表的段故障

[英]Segfault with memory reallocation structure and linked list

I am new to C and I am working on a project which I have been struggling with trying to get working for days and I cannot figure out where the problem is. 我是C语言的新手,我正在从事一个项目,我一直在努力尝试工作数天,但我无法弄清楚问题出在哪里。

Basically, what the application is supposed to do is read data from a database and insert the values into a structure. 基本上,应用程序应该做的是从数据库中读取数据并将值插入结构中。 Some rows are related to each so within the structure is a linked list which will contain other values from the database. 有些行彼此相关,因此结构内是一个链接列表,其中将包含数据库中的其他值。

I do not know how many records I am going to get out of the database, so I initially malloc the structure to be 100 items, and I keep track of an index which if it reaches 100, it then reallocs the structures to add another 100 items. 我不知道要从数据库中取出多少条记录,因此我最初将结构分配为100个项目,并且跟踪一个索引,如果索引达到100,它将重新分配结构以添加另外100个项目。 The reallocation bit seems to work but it is then why I try to insert something into the linked list within the structure I get a segfault. 重新分配位似乎起作用,但这就是为什么我尝试在结构中的链接列表中插入某些内容的原因。

Below is the definition for the main structure. 以下是主要结构的定义。

typedef struct CallLogSearchDataStruct
{
    char * date;
    char * time;
    char * bParty;
    char * aParty;
    float duration;
    char * cleardownCause;
    struct CallLogSearchOutboundStruct * outboundLegs;
} callLogSearchDataStruct;

Below is the code for the linked list (CallLogSearchOutboundStruct) 以下是链接列表的代码(CallLogSearchOutb​​oundStruct)

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

I initialise the structures using the following code 我使用以下代码初始化结构

callLogSearchData = calloc(INITIAL_CALL_STRUCT_SIZE,sizeof(callLogSearchDataStruct));
callLogSearch = calloc(INITIAL_CALL_STRUCT_SIZE,sizeof(callLogSearchResultStruct));
switches = calloc(INITIAL_CALL_STRUCT_SIZE, sizeof(switchIDStructure));

Each time it loops around the data, I malloc the outboundLeg linked list within the structure using the following code 每次它遍历数据时,我都会使用以下代码在结构内分配outboundLeg链接列表

if (dataRow > -1 && callLogSearchData[dataRow].outboundLegs == NULL)
                {
                    //Initialise the outbound struct
                    callLogSearchData[dataRow].outboundLegs = malloc(sizeof(callLogSearchOutboundStruct));
                    callLogSearchData[dataRow].outboundLegs->cleardownCause = NULL;
                    callLogSearchData[dataRow].outboundLegs->duration = 0;
                    callLogSearchData[dataRow].outboundLegs->target = NULL;
                    callLogSearchData[dataRow].outboundLegs->nextLeg = NULL;
                }
            outboundCallLegStartPtr = callLogSearchData[dataRow].outboundLegs;
            outboundCallLegStartPtr->nextLeg = NULL;

Below is the code that calls the function to insert the data into the linked list within the structure 以下是调用该函数以将数据插入结构中的链表中的代码

insertOutboundLegToList(outboundCallLegStartPtr, targetBuffer, durationBuffer, atoi(rowReport[cleardownColIndex]), debugFile);

Below is the code for the actual insert function 以下是实际插入功能的代码

void insertOutboundLegToList(callLogSearchOutboundStruct * outboundLeg, char * target, float duration, int cleardown, FILE * debugFile)
{
    //fprintf(debugFile, "INSIDE INSERT OUTBOUND LEG FUNCTION\n");
    if (outboundLeg->target == NULL)
    {
        outboundLeg->target = strdup(target);
        outboundLeg->duration = duration;
        outboundLeg->cleardownCause = strdup(setCallResult(cleardown));
        //fprintf(debugFile, "Outbound target is: %s\n", outboundLeg->target);
    }
    else
    {
        while (outboundLeg->nextLeg != NULL)
        {
            outboundLeg = outboundLeg->nextLeg;
        }
        outboundLeg->nextLeg = (callLogSearchOutboundStruct*)malloc(sizeof(callLogSearchOutboundStruct));
        outboundLeg = outboundLeg->nextLeg;
        outboundLeg->target = strdup(target);
        outboundLeg->duration = duration;
        outboundLeg->cleardownCause = strdup(setCallResult(cleardown));
        //fprintf(debugFile, "Outbound target is: %s\n", outboundLeg->target);
        outboundLeg->nextLeg = NULL;
    }


}

Below is how I call the function to check if the structures need to be reallocated 下面是我如何调用该函数以检查是否需要重新分配结构的方法

if (reallocateStructures(&callLogSearch, &callLogSearchData, &switches, &timesStructHasBeenReallocated, currentStructIndexValue, dataRow) == 0)
                    {
                        //Structures have been reallocated so reset the index
                        currentStructIndexValue = -1;
                    }

And below is the actual function for the reallocation of the structures 以下是重新分配结构的实际功能

int reallocateStructures(callLogSearchResultStruct **callLogSearch, callLogSearchDataStruct ** callLogSearchData, 
        switchIDStructure ** switches, int *timesStructHasBeenReallocated, int currentStructIndexValue,
        int dataRow)
{
    int INITIAL_CALL_STRUCT_SIZE = 100;
    int currentSize = 0;
    int newSize = 0;
    int initFromIndex = 0;
    callLogSearchResultStruct * callLogSearchTemp;
    callLogSearchDataStruct * callLogSearchDataTemp;
    switchIDStructure * switchesTemp;


    printf("Current Struct Index Value: %i\n", currentStructIndexValue);

    if (currentStructIndexValue >= INITIAL_CALL_STRUCT_SIZE) {
        printf("REALLOCATING STRUCTURES");
        currentSize = currentStructIndexValue * *timesStructHasBeenReallocated;

        newSize = currentSize + INITIAL_CALL_STRUCT_SIZE;
        *timesStructHasBeenReallocated = *timesStructHasBeenReallocated + 1;


        callLogSearchTemp = (callLogSearchResultStruct*)realloc(*callLogSearch, (newSize * sizeof(callLogSearchResultStruct)));
        callLogSearchDataTemp = (callLogSearchDataStruct*)realloc(*callLogSearchData, (newSize * sizeof(callLogSearchDataStruct)));
        switchesTemp = (switchIDStructure*)realloc(*switches, (newSize * sizeof(switchIDStructure)));


        /**callLogSearchData = realloc(*callLogSearchData, newSize * sizeof (callLogSearchDataStruct));
        *callLogSearch = realloc(*callLogSearch, newSize * sizeof (callLogSearchResultStruct));
        *switches = realloc(*switches, newSize * sizeof (switchIDStructure));
        */
        for (initFromIndex = currentSize; initFromIndex < newSize; initFromIndex++) {
            callLogSearchDataTemp[initFromIndex].aParty = NULL;
            callLogSearchDataTemp[initFromIndex].bParty = NULL;
            callLogSearchDataTemp[initFromIndex].cleardownCause = NULL;
            callLogSearchDataTemp[initFromIndex].date = NULL;
            callLogSearchDataTemp[initFromIndex].duration = 0;
            callLogSearchDataTemp[initFromIndex].outboundLegs = NULL;
            callLogSearchDataTemp[initFromIndex].time = NULL;

            callLogSearchTemp[initFromIndex].date = NULL;
            callLogSearchTemp[initFromIndex].dRowIndex = dataRow;

            switchesTemp[initFromIndex].switchID = NULL;
        }

        *callLogSearch = callLogSearchTemp;
        *callLogSearchData = callLogSearchDataTemp;
        *switches = switchesTemp;
        return 0;
    }
    else
    {
        return 1;
    }
}

I've tried running my program through Valgrind but I'm not entirely sure what all the messages mean and doing a Google, although I've found something, haven't help me to understand the problem. 我已经尝试通过Valgrind运行程序,但是我不确定所有消息的含义并使用Google,尽管我发现了一些问题,但并没有帮助我理解问题。

The messages from Valgrind are 来自Valgrind的消息是

==9152== Invalid read of size 4
==9152==    at 0x80544EB: GenerateCallLog (performreport.c:3112)
==9152==    by 0x804AA49: ProcessReport (performreport.c:344)
==9152==    by 0x8056C7E: PerformReportCheck (reportcheck.c:72)
==9152==    by 0x80494D0: main (main.c:82)
==9152==  Address 0x47b22b0 is not stack'd, malloc'd or (recently) free'd
==9152==
==9152== Invalid read of size 4
==9152==    at 0x80545CF: GenerateCallLog (performreport.c:3123)
==9152==    by 0x804AA49: ProcessReport (performreport.c:344)
==9152==    by 0x8056C7E: PerformReportCheck (reportcheck.c:72)
==9152==    by 0x80494D0: main (main.c:82)
==9152==  Address 0x47b22b0 is not stack'd, malloc'd or (recently) free'd
==9152==
==9152== Invalid write of size 4
==9152==    at 0x80545DF: GenerateCallLog (performreport.c:3124)
==9152==    by 0x804AA49: ProcessReport (performreport.c:344)
==9152==    by 0x8056C7E: PerformReportCheck (reportcheck.c:72)
==9152==    by 0x80494D0: main (main.c:82)
==9152==  Address 0x35c is not stack'd, malloc'd or (recently) free'd

Line performreport.c:3112 is if (dataRow > -1 && callLogSearchData[dataRow].outboundLegs == NULL) 行performreport.c:3112是if (dataRow > -1 && callLogSearchData[dataRow].outboundLegs == NULL)

The line of performreport.c:3123 is outboundCallLegStartPtr = callLogSearchData[dataRow].outboundLegs; performreport.c:3123这一行是outboundCallLegStartPtr = callLogSearchData[dataRow].outboundLegs;

The line of performreport.c:3124 is outboundCallLegStartPtr->nextLeg = NULL; performreport.c:3124这一行是outboundCallLegStartPtr->nextLeg = NULL; , its this line that is also causing the core dump after the reallocations have occurred ,这是在重新分配发生后也导致核心转储的这一行

The setCallResult function as requested is as follows: 所要求的setCallResult函数如下:

char * setCallResult(int callResult)
{
    if (callResult == 1)
    {
        return "Answered";
    }
    else if (callResult != 3)
    {
        return "Unanswered";
    }
    else if (callResult == 3)
    {
        return "Engaged";
    }
    else
    {
        return "N/A";
    }
}

Sorry, for all of the code, but I don't know exactly where the problem might be. 抱歉,对于所有代码,但我不知道可能出在哪里。 Looking in the core dump it looks as if something is trashing the memory as when I inspect some of the values within the structures its just garbled mess. 在核心转储中查看时,似乎有些东西在浪费内存,就像我检查结构中的某些值时一样,只是乱七八糟。

Thanks for any help you can provide. 感谢您的任何帮助,您可以提供。

There's one potential problem I can see: 我可以看到一个潜在的问题:

In insertOutboundLegToList , you seem to take the first condition to mean "there is an allocated struct, but it's empty and yet to be filled". insertOutboundLegToList ,您似乎将第一个条件表示为“有一个已分配的结构,但它为空且尚未填充”。 You then fill it, but you forget NULL ing nextLeg . 然后填充它,但是nextLeg却忘记了NULL So suppose that nextLeg is 0x75732d42 because that's the data still in there; 因此,假设nextLeg0x75732d42因为那仍然是数据。 next time the function is called, you trigger the else condition: 下次调用该函数时,将触发else条件:

while (outboundLeg->nextLeg != NULL)
        {
            outboundLeg = outboundLeg->nextLeg;
        }

Now nextLeg isn't NULL even though it should be. 现在,即使应该, nextLeg也不为NULL After one iteration, outboundLeg points to 0x75732d42 even though there is no allocated struct there. 一次迭代后,即使在那里没有分配的结构, outboundLeg指向0x75732d42 On the next iteration, you crash because you try to read from an invalid memory address. 在下一次迭代中,由于尝试从无效的内存地址读取而导致崩溃。


What I'm suggesting is this (in insertOutboundLegToList ): 我的建议是这个(在insertOutboundLegToList ):

if (outboundLeg->target == NULL)
{
    outboundLeg->target = strdup(target);
    outboundLeg->duration = duration;
    outboundLeg->cleardownCause = strdup(setCallResult(cleardown));
    // HERE v HERE v HERE v HERE
    outboundLeg->nextLeg = NULL;
    ...
}

Also, this line in the realloc function 另外,这行在realloc函数中

*callLogSearchData = callLogSearchData;

is probably missing a Temp . 可能缺少Temp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM