我是C的新手,但正在从事一个从数据库中检索调用日志信息的项目。在我尝试在实际程序中实现这一点之前,我正在尝试制作一个测试应用程序,这样我就可以通过手动向结构中添加一些静态数据来确保逻辑是正确的。
呼叫日志将保存入站呼叫支路的详细信息,如电话号码和持续时间等,在该结构中列出了一个包含1个或多个出站支路的链接。
当我在GDB中逐步执行代码时,我似乎能够正确地插入数据,但我认为问题是当我试图构建一个字符串写入文件时。
在导出过程中,它应该遍历该结构,为入站分支详细信息创建一个逗号分隔的值字符串,然后从该结构内的链表中检索每个出站分支,并创建另一个逗号间隔的值字符串。
一旦我有了与入站分支相关联的所有分支,我就会将这两个入站分支字符串和出站分支字符串写入CSV文件。
除了一个问题外,这是一个或多或少的工作。如果入站分支有两个出站分支,当它写入文件时,它只显示最后一个出站,第一个出站不会写入文件。
以下是如何定义我的结构。
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 RAMn");
}
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 INBOUNDn");
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 LEGn");
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 legsn");
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: %sn", 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%sn", inboundLegFileString, outboundLegFileString);
inboundLegFileString = "";
outboundLegFileString = "";
}
fclose(myFile);
return;
}
更新我在insert函数中添加了更多的调试,因此,尽管当我逐步完成它时,看起来我做的是正确的事情,但如果我尝试并循环完成刚插入的内容,我仍然只得到最后一个出站分支。
下面是我添加的
node * outBoundLeg;
for (outBoundLeg = callLog[callLogIndex].outBoundLegs; outBoundLeg != NULL; outBoundLeg = outBoundLeg->next)
{
printf("INSERT: %sn", outBoundLeg->target);
}
printf语句只显示插入列表中的最后一个出站目标号码,而不是之前的那个,所以我不知道我添加的是不是错了,或者我的指针是否错了,所以我总是在看最后。
主要问题出现在insertOutBoundLeg函数中。分配第二个出站分支时,将更新根指针(outBoundLegs成员)以指向新节点,从而丢失第一个节点。
callLog[callLogIndex].outBoundLegs = callLog[callLogIndex].outBoundLegs->next;
您应该使用临时指针来查找列表中的最后一个节点,然后为新节点设置数据。
因此,插入第二个分支的代码应该是这样的:
printf("INSERTING SECOND OR MORE OUTBOUND LEGn");
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这些参数,所以字符串最终只会重复两次,这可能会导致内存泄漏。