从结构中的链表导出数据

时间:2013-07-18 13:14:00

标签: c linked-list structure

我是C的新手但正在开发一个项目,该项目将从数据库中检索呼叫日志信息。在我尝试在真实程序中实现这一点之前,我正在尝试创建一个测试应用程序,这样我就可以通过手动将一些静态数据添加到结构中来确保逻辑正确。

通话记录将保留呼入支路详细信息,例如电话号码和持续时间等,并且在该结构中,列出了包含一个或多个出站支路的链接。

当我逐步浏览GDB中的代码时,我似乎正确地插入了数据,但我认为这个问题是当我尝试构建一个字符串来写入文件时。

在导出过程中,它应该循环遍历结构,为入站段详细信息创建一个逗号分隔值字符串,然后从结构中的链表中检索每个出站段并创建另一个逗号分隔值的字符串。

一旦我将所有腿与入站腿相关联,我就会将这两个入站腿串和出站腿串写入CSV文件。

除了一个问题外,这项工作更少。如果入站分支有2个出站分支,当它写入文件时,它只显示最后一个出站分支,第一个出站分支不会写入该文件。

以下是我的结构的定义方式。

typedef struct CallLogStructure
{
    char * date;
    char * time;
    char * bParty;
    char * aParty;
    float duration;
    char * cleardownCause;
    struct Node *outBoundLegs;
} callLogStructure;

typedef struct Node
{
    char * target;
    float targetDuration;
    char * targetCleardownCause;
    struct Node *next;
}node;

以下是我如何为入站呼叫设置数据并调用函数以将出站分支插入到链表中。

callLogStructure * callLog = NULL;
    node *temp = NULL;
    int dataRow = 0;

    callLog = malloc(dataRow+2 * sizeof(*callLog));
    //start = (node*)malloc(sizeof(node));
    callLog[dataRow].outBoundLegs = NULL;
    callLog[dataRow].outBoundLegs = (node*)malloc(sizeof(node));
    if (callLog[0].outBoundLegs == NULL)
    {
        printf("Failed to allocate RAM\n");
    }
    temp = callLog[dataRow].outBoundLegs;
    temp->next = NULL;
    callLog[dataRow].outBoundLegs->target = NULL;
    callLog[dataRow].outBoundLegs->targetDuration = 0;
    callLog[dataRow].outBoundLegs->targetCleardownCause = strdup("0");

    //Insert first inbound leg
    callLog[dataRow].date = "16/05/2011";
    callLog[dataRow].time = "00:00:03";
    callLog[dataRow].aParty = "1234";
    callLog[dataRow].bParty = "5678";
    callLog[dataRow].duration = 0;
    callLog[dataRow].cleardownCause = "unanswered";

    outboundTarget = strdup("4321");
    outboundDuration = 0;
    outboundCleardown = strdup("Unanswered");

    //insertOutBoundLeg(&callLog[0].outBoundLegs, outboundTarget, outboundDuration, outboundCleardown);
    insertOutBoundLeg(callLog, outboundTarget, outboundDuration, outboundCleardown, dataRow);

    //Insert secord inbound
    dataRow++;
    callLog[dataRow].outBoundLegs = NULL;
    callLog[dataRow].outBoundLegs = (node*)malloc(sizeof(node));
    //temp = callLog[0].outBoundLegs;
    //temp->next = NULL;
    callLog[dataRow].outBoundLegs->target = NULL;
    callLog[dataRow].outBoundLegs->targetDuration = 0;
    callLog[dataRow].outBoundLegs->targetCleardownCause = strdup("0");

    callLog[dataRow].date = "16/05/2011";
    callLog[dataRow].time = "00:00:58";
    callLog[dataRow].aParty = "6789";
    callLog[dataRow].bParty = "9876";
    callLog[dataRow].duration = 0;
    callLog[dataRow].cleardownCause = "unanswered";

    outboundTarget = strdup("654321");
    outboundDuration = 0;
    outboundCleardown = strdup("unanswered");

    insertOutBoundLeg(callLog, outboundTarget, outboundDuration, outboundCleardown, dataRow);

    outboundTarget = strdup("87654");
    outboundDuration = 10;
    outboundCleardown = strdup("answered");

    insertOutBoundLeg(callLog, outboundTarget, outboundDuration, outboundCleardown, dataRow);
        //printf("NEWLY INSERTED OUTBOUND TARGET: %s", callLog[0].outBoundLegs[0].target);

    writeToFile(callLog, dataRow+1);

以下是将数据写入链表的功能

void insertOutBoundLeg(callLogStructure *callLog, char * target, float targetDuration, char * targetCleardownCause, int callLogIndex)
{
    if (callLog[callLogIndex].outBoundLegs->target == NULL)
    {
        printf("INSERTING BRAND NEW OUTBOUND LEG FOR INBOUND\n");
        callLog[callLogIndex].outBoundLegs->target = strdup(target);
        callLog[callLogIndex].outBoundLegs->targetDuration = targetDuration;
        callLog[callLogIndex].outBoundLegs->targetCleardownCause = strdup(targetCleardownCause);
        callLog[callLogIndex].outBoundLegs->next = NULL;
    }
    else
    {
        printf("INSERTING SECOND OR MORE OUTBOUND LEG\n");
        while (callLog[callLogIndex].outBoundLegs->next != NULL)
        {
            callLog[callLogIndex].outBoundLegs = callLog[callLogIndex].outBoundLegs->next;
        }
        callLog[callLogIndex].outBoundLegs->next = (node *)malloc(sizeof(node));
        callLog[callLogIndex].outBoundLegs = callLog[callLogIndex].outBoundLegs->next;
        callLog[callLogIndex].outBoundLegs->target = strdup(target);
        callLog[callLogIndex].outBoundLegs->targetDuration = targetDuration;
        callLog[callLogIndex].outBoundLegs->targetCleardownCause = strdup(targetCleardownCause);
        callLog[callLogIndex].outBoundLegs->next = NULL;
    }
}

以下是将数据写入文件的功能。

void writeToFile(callLogStructure * callLog, int maxRecords)
{
    FILE * myFile;
    myFile = fopen("legs.csv", "wb");
    char * inboundLegFileString = "0";
    char * outboundLegFileString = "0";
    //inboundLegFileString = malloc(sizeof(char *));
    //outboundLegFileString = malloc(sizeof(char *));

    if (callLog == NULL)
    {
        printf("No inbound legs\n");
        return;
    }

    int i = 0;
    for (i = 0; i < maxRecords; i++)
    {
        asprintf(&inboundLegFileString, "\"%s\",\"%s\",\"%s\",\"%s\",\"%.1f\",\"%s\"",
                callLog[i].date, callLog[i].time, callLog[i].aParty, callLog[i].bParty,
                callLog[i].duration, callLog[i].cleardownCause);

        //printf("Outbound Target: %s\n", callLog[0].outBoundLegs->target);

        while (callLog[i].outBoundLegs != NULL)
        {
            if (callLog[i].outBoundLegs->target != NULL)
            {
                asprintf(&outboundLegFileString, "%s,\"%s\",\"%.1f\",\"%s\"", outboundLegFileString,
                    callLog[i].outBoundLegs->target, callLog[i].outBoundLegs->targetDuration,
                    callLog[i].outBoundLegs->targetCleardownCause);
            }
            callLog[i].outBoundLegs = callLog[i].outBoundLegs->next;
        }
        fprintf(myFile, "%s%s\n", inboundLegFileString, outboundLegFileString);
        inboundLegFileString = "";
        outboundLegFileString = "";
    }
            fclose(myFile);
    return;
}

更新 我在插入函数中添加了一些更多的调试,所以虽然看起来我正在做正确的事情,当我单步执行它时,如果我然后尝试循环插入的内容之后我仍然只获得最后一个出站段。

以下是我添加的内容

node * outBoundLeg;
    for (outBoundLeg = callLog[callLogIndex].outBoundLegs; outBoundLeg != NULL; outBoundLeg = outBoundLeg->next)
    {
        printf("INSERT: %s\n", outBoundLeg->target);
    }

那个printf语句只显示插入到列表中的最后一个出站目标号而不是之前的那个,所以我不知道我是否添加了错误,或者是否我的指针错了所以我总是看到最后。

1 个答案:

答案 0 :(得分:0)

主要问题在于 insertOutBoundLeg 功能。当您分配第二个出站段时,更新根指针( outBoundLegs 成员)以指向新节点,从而丢失第一个。

callLog[callLogIndex].outBoundLegs = callLog[callLogIndex].outBoundLegs->next;

您应该使用临时指针查找列表中的最后一个节点,然后设置新节点的数据。

所以插入第二条腿的代码应该是这样的:

printf("INSERTING SECOND OR MORE OUTBOUND LEG\n");
struct Node *tempLeg = callLog[callLogIndex].outBoundLegs;
while (tempLeg->next != NULL)
{
    tempLeg = tempLeg->next;
}
tempLeg->next = (node *)malloc(sizeof(node));
tempLeg = tempLeg->next;
tempLeg->target = strdup(target);
tempLeg->targetDuration = targetDuration;
tempLeg->targetCleardownCause = strdup(targetCleardownCause);
tempLeg->next = NULL;

另一个问题出在 writeToFile 函数中。您使用“0”初始化输出字符串,这几乎肯定不是您想要的。

char * inboundLegFileString = "0";
char * outboundLegFileString = "0";

假设应该是:

char * inboundLegFileString = "";
char * outboundLegFileString = "";

否则,您将在csv中的入站和出站段之间出现不需要的零。

我还建议您考虑更新 writeToFile 函数,以便在遍历出站段时使用临时指针,因为它与 insertOutBoundLegs 函数具有相同的问题。您将再次覆盖根指针( outBoundLegs 成员)。

callLog[i].outBoundLegs = callLog[i].outBoundLegs->next;

代码有效,但只能运行一次。

最后,我要提一下,在调用 insertOutBoundLeg之前初始化 outboundTarget outboundCleardown 变量时,你正在对 strdup 进行不必要的调用

outboundTarget = strdup("4321");           // this strdup not needed
outboundDuration = 0;
outboundCleardown = strdup("Unanswered");  // this strdup not needed

insertOutBoundLeg 函数无论如何都将 strdup 这些参数,因此字符串最终会被重复两次,这可能会导致内存泄漏。