0

これは、単純な形式でキューのデータ構造を実装する 2 つの C プログラムです。

  • 最初:

    1 つのキューを定義すると、完全に機能します

  • 二番目:

    複数のキューを定義し、実行時にクラッシュする

main()機能は、実装が少し異なることを除いて、両方のプログラムで同じです。

ここでの質問: 2 番目のコードが機能しないのはなぜですか?

*ここにコードがあります*

コード 1:

/*
 Single queue  -- this work perfectly
*/
#include <stdio.h>
#define Q_MAX_SIZE 255

struct queue {
    int* pointer;
    int* currentValue;
    int max, count, theQueue[Q_MAX_SIZE];
};

//prototyps
void initQueue(struct queue*);
unsigned short pushQueue(struct queue*, int);
int* popQueue(struct queue*);

int main(void) {
    int j;
    struct queue q;

    initQueue(&q);

    for (j = 0; j < 6; j++)
        pushQueue(&q, j);

    int* inputobj = popQueue(&q);
    while (inputobj != NULL)
    {
        printf("%d  ", *inputobj);
        inputobj = popQueue(&q);
    }

    printf("\n\ndone..Queue is empty\n");

    return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void initQueue(struct queue *Q)
{
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}

unsigned short pushQueue(struct queue *Q, int input) {
    if (Q->count < Q->max)
    {
       *Q->pointer = input;
        Q->pointer++;
        Q->count++;
        return 1;
    }
    else
        return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int* popQueue(struct queue *Q) {
    int i;
    if (Q->count > 0)
    {

       *Q->currentValue = *Q->theQueue;
        Q->pointer--;
        Q->count--;

        for (i = 0; i < Q->count; i++)
        {
            int* currentPtr = Q->theQueue + i;
            int* nextPtr = currentPtr + 1;
            *currentPtr = *nextPtr;
        }

        return Q->currentValue;
    }
    else
        NULL;
}

コード 2:

/*
 Multiple queues  -- this not work and crash at execution
*/
#include <stdio.h>
#define Q_MAX_SIZE 255

struct queue {
    int* pointer;
    int* currentValue;
    int max, count, theQueue[Q_MAX_SIZE];
};

//prototyps
void initQueue(struct queue*);
unsigned short pushQueue(struct queue*, int);
int* popQueue(struct queue*);

int main(void) {
        int i, j;
    struct queue obj[5];

    for(i=0; i<5; i++)
    {
        initQueue(&obj[i]);

        for(j = 0; j<3; j++)
        {
            pushQueue(&obj[i], j);
        }
    }

    for(i=0; i<5; i++)
    {
        printf("Queue[%d]:\n", i);
        int* inputobj;
        inputobj = popQueue(&obj[i]);

        while(inputobj != NULL)
        {
            printf("Queue[No.%d] = %d\n", i, *inputobj);
            inputobj = popQueue(&obj[i]);
        }
        putchar('\n');
    }

    return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void initQueue(struct queue *Q)
{
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}

unsigned short pushQueue(struct queue *Q, int input) {
    if (Q->count < Q->max)
    {
       *Q->pointer = input;
        Q->pointer++;
        Q->count++;
        return 1;
    }
    else
        return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int* popQueue(struct queue *Q) {
    int i;
    if (Q->count > 0)
    {

       *Q->currentValue = *Q->theQueue;
        Q->pointer--;
        Q->count--;

        for (i = 0; i < Q->count; i++)
        {
            int* currentPtr = Q->theQueue + i;
            int* nextPtr = currentPtr + 1;
            *currentPtr = *nextPtr;
        }

        return Q->currentValue;
    }
    else
        NULL;
}

更新:問題が発生しinitQueue()、メモリを割り当てることで解決しましQ->currentValueた。編集後の機能は次のとおりです。

void initQueue(struct queue *Q)
{
    Q->currentValue = malloc(sizeof(int));
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}
4

4 に答える 4

3

両方の回答が既に述べたように、問題はQ->current_value値が割り当てられていないため、未定義のアドレスを指しており、すべての逆参照*Q->currentValue = ..は未定義の動作です。コード 1 が機能しているように見えるという事実は、UB の性質上、動作が保証されていないため、プログラムがクラッシュする場合とクラッシュしない場合があるため (または、犬が爆発したり、ドラゴンが鼻から飛び出したりする可能性があります ... :- ) )

もちろん、すべて異なる意味を持つ複数のソリューションがあります。

  1. currentValue特定の値のコピーを保持する必要がある場合は、代わりint currentValueint *...代入することができます

    Q->currentValue = *Q->theQueue;

    returnステートメントは次のようになりますreturn &Q->currentValue。その場合、元の値へのポインターを返しますtheQueue[0]

  2. の場所を指したい場合theQueue、ジムのアンサーは正しい方法を教えてくれます:

    Q->currentValue = Q->theQueue;

    その場合、新しい値へのポインターを返す必要がtheQueue[0]あります (これは望ましくない可能性があります)。

  3. Q->currentValuemyにメモリを割り当てmalloc( sizeof (int) );て、割り当てをそのままにしておくことができます。その場合、(1) のような元の値へのポインターを返します。theQueue[0]

于 2013-08-30T16:45:58.557 に答える
1

これは実際には非常に微妙な問題だと思います。問題は (私が思うに) popqueue() の次の行です。

*Q->currentValue = *Q->theQueue;

再確認したところ、最初のコード (配列なし) にもセグメント障害がありました。あなたが言ったようには機能しません。あなたは書いたはずです:

Q->currentValue = Q->theQueue;

Cはポインターを少し理解して適切に割り当てることができますが、別のレベル(配列)を追加すると、割り当てが機能しないものに強制されたと思います。それが私の見解です。より良い回答が得られるように、報奨金を出そうと思います。

于 2013-08-30T13:16:17.540 に答える
0

ロケーション Q->currentValue にアクセスできません。これが問題です。割り当てられていません。

解決策は、init ルーチンでメモリの適切な部分を割り当てることです。

Q = malloc(sizeof(struct queue));

その後、すべての変数の値を初期化することもできます。

于 2013-08-27T20:32:12.423 に答える