0

私は C を初めて使用しますが、データベースから通話ログ情報を取得するプロジェクトに取り組んでいます。実際のプログラムでこれを実装しようとする前に、構造に静的データを手動で追加するだけでロジックが正しいことを確認できるように、テスト アプリを作成しようとしています。

コール ログには、電話番号や通話時間などのインバウンド コール レッグの詳細が保持されます。その構造内には、1 つ以上のアウトバウンド レッグを含むリンクがリストされています。

GDB でコードをステップ実行するときからわかる限り、データを正しく挿入しているように見えますが、問題は、ファイルに書き込む文字列を作成しようとするときです。

エクスポート プロセスでは、構造をループし、インバウンド レッグの詳細についてコンマ区切り値の文字列を作成し、構造内のリンク リストから各アウトバウンド レッグを取得して、カンマ区切り値の別の文字列を作成することになっています。

インバウンド レッグに関連付けられたすべてのレッグを取得したら、これら 2 つのインバウンド レッグ文字列とアウトバウンド レッグ文字列を CSV ファイルに書き込みます。

これは、1 つの問題を除いてあまり機能しません。インバウンド レッグに 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;
}

UPDATE 挿入機能内にさらにデバッグを追加したので、ステップスルーすると正しいことをしているように見えますが、最後のアウトバウンドレッグしか取得した直後に挿入されたものをループしようとすると.

以下は私が追加したものです

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

そのprintfステートメントは、リストに挿入された最後のアウトバウンドターゲット番号のみを表示しているため、追加が間違っているかどうか、またはポインターが間違っているかどうかがわからないため、常に終わり。

4

1 に答える 1

0

主な問題は、insertOutBoundLeg関数にあります。2 番目のアウトバウンド レグを割り当てると、ルート ポインター ( outBoundLegsメンバー) が新しいノードを指すように更新されるため、最初のノードが失われます。

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

リスト内の最後のノードを見つけるために一時ポインタを使用してから、新しいノードのデータを設定する必要があります。

したがって、2 番目の足を挿入するためのコードは次のようになります。

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;

もう 1 つの問題は、writeToFile関数にあります。出力文字列を「0」で初期化しますが、これはほぼ確実に必要なものではありません。

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

仮定すると、次のようになります。

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

そうしないと、csv のインバウンド レッグとアウトバウンド レッグの間に不要なゼロができてしまいます。

insertOutBoundLegs関数と同じ問題があるため、アウトバウンド レグをトラバースするときに一時ポインターを使用するようにwriteToFile関数を更新することを検討することもお勧めします。ルート ポインター ( 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するため、文字列が 2 回複製されるだけで、メモリ リークが発生する可能性があります。

于 2013-07-22T09:56:28.010 に答える