1

行列乗算プログラムを作成していますが、さまざまなサイズのさまざまな行列の実行時間を確認する必要があります。次に、メインの pthreads を使用してコードを並列化する必要があるため、初期化関数と乗算関数を含む 1 つのヘッダー ファイルを作成し、メインを別の .c ファイルに作成しましたが、プログラムを実行すると次のエラーが発生します。 :

エラー: セグメンテーション エラー (コア ダンプ)

サイズ1000の正方行列の行列乗算を試みていることに注意してください。

ここに私のコードがあります:

// mm.h

#ifndef MM_H
#define MM_H

#include <stdlib.h>
#include <time.h>

int SIZE, NTHREADS;
int **A, **B, **C;

void init(int **A, int **B, int **C)
{
    int i, j;

    A = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        A[i] = malloc(SIZE * sizeof(int));

    B = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        B[i] = malloc(SIZE * sizeof(int));

    C = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        C[i] = malloc(SIZE * sizeof(int));

    srand(time(NULL));

    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            A[i][j] = rand()%100;
            B[i][j] = rand()%100;
        }
    }
}

void mm(int **A, int **B, int **C)
{
    int i, j, k;

    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            C[i][j] = 0;
            for(k = 0; k < SIZE; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

#endif

私の主な機能:

// mmserial.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mm.h"

int main(int argc, char* argv[])
{
    int i;

    if(argc != 2)
    {
        printf("Usage: %s <size_of_square_matrix>\n", argv[0]);
        exit(1);
    }

    SIZE = atoi(argv[1]);
    init(A, B, C);

    clock_t begin, end;
    double time_spent;

    begin = clock();

    mm(A, B, C);

    end = clock();

    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

    printf("Elapsed time: %.2lf seconds.\n", time_spent);

    for(i = 0; i < SIZE; i++)
        free((void *)A[i]);
    free((void *)A);

    for(i = 0; i < SIZE; i++)
        free((void *)B[i]);
    free((void *)B);

    return 0;
}

誰かがこの問題を克服するのを手伝ってくれたら、うれしいです。さらに質問があります。乗算の結果の値を保持する最終行列も動的に割り当てる必要がありますか?

4

3 に答える 3

1

コードには複数の問題があります。ここでは、プログラムの問題に対する解決策を示します。

まずC、配列にスペースを割り当てる必要があります。これはすでにtacpでカバーされているため、同じことはスキップします。

主な問題は機能から来ていinit(A,B)ます。ここにはいくつかの問題があります。1つと はグローバル ポインターABあるため、関数の引数として渡す必要はありません。ただし、コードは同じように設計されているため、次の変更を組み込む必要があります

//main function invoking init
init(&A, &B); // Pass references to A and B

のフット プリントは次のinitように変更する必要があります。

void init(int ***Aptr, int ***Bptr)
{
     int    **A; // Define a local pointer to keep rest of the code intact
     int    **B; // Define a local pointer to keep rest of the code intact
     .....................
     //Rest of your code

     // End of function
     *Aptr = A;
     *Bptr = B;
}

これら 2 つの変更により、コードは正常に動作する準備が整います。A以前の実装では、関数内でとのローカル コピーのみBが更新initされ、実際のポインターには反映されませんでした。したがって、init完了するAと、セグメンテーション違反の原因となったB可能性のあるポインターを指していました。NULL

この問題には別の解決策があります。に引数を渡すことを避けることができます。initつまり、実装を に変換initinit()て変更しvoid init()ます。Cこれは正常に機能します(これも割り当てられていると仮定します)

ただし、もう 1 つポイントがあります。最後Cに、配列のメモリも削除するように注意する必要があります(init関数で割り当てられていると仮定します) 。

for(i = 0; i < SIZE; i++)
    free((void *)C[i]);
free((void *)C);

追記:

プログラミングの観点からは、グローバル変数を混ぜて、これらの非常にグローバルな変数を関数パラメーターとして渡すべきではないと思います。スコープはグローバルです。つまり、関数は確実に変数にアクセスできるため、同じものを関数に渡す必要はありません。

于 2013-04-12T13:57:58.620 に答える
0

Cも動的マトリックスですが、メモリを割り当てたことはなく、値を存在しないメモリに直接割り当てるため、コアダンプが発生します。にもメモリを割り当てる必要がありますC

 void mm(int **A, int **B, int **C)
 {
   int i, j, k;

   for(i = 0; i < SIZE; i++) {
      for(j = 0; j < SIZE; j++) {
        C[i][j] = 0;   ///^^^Need to first allocate space for C
        for(k = 0; k < SIZE; k++) {
            C[i][j] += A[i][k] * B[k][j];
        }
      }
   }
}
于 2013-04-12T13:36:23.370 に答える