おふとんガレージ

技術的な忘備録とか雑記

Cで動的に多次元配列を使いたいっ!

ポインタ考えると頭こんがらがり太郎だし入力のチエックめんどくさいしつらいつらいだね。

仕様

構造体matrix
  • 成分 : int row, int col, int **data

内容

  • 行列を2つ入力させ、2つの行列の、和と差、積を導出し出力する。

各関数の仕様とか

関数名:void init_matrix(struct matrix *mat)
引数: 構造体matrixのポインタ
関数の内容:
  • 構造体matrixに含まれる行((int)matrix.row)、列((int)matrix.col)分のメモリ領域を確保する
void init_matrix(struct matrix *mat) {
    int i, j;

    if((mat->data = (int **)malloc(mat->row * sizeof(int *))) == NULL) {
        fprintf(stderr, "メモリ確保エラー\n");
        exit(1);
    }
    for(i = 0; i < mat->row; i++) {
        if((mat->data[i] = (int *)malloc(mat->col * sizeof(int))) == NULL) {
            fprintf(stderr, "メモリ確保エラー\n");
            exit(1);
        }
        for(j = 0; j < mat->col; j++) mat->data[i][j] = 0;
    }
}

各行へのポインタを保持する配列を先に確保し、子要素として各行のデータを保持する配列を確保している。
配列が2つ必要となるのでメモリ効率的にもよろしくないし、別個別個にメモリ領域を確保するのでメモリ確保及び開放にループが必要。

実際に使う時は行数*列数の要素数を持つ一次元配列で確保した方が構造も楽だし、連続した領域も確保できそうだし良さそうな気がする。

関数名:void free_matrix(struct matrix *mat)
引数: 構造体matrixのポインタ
関数の内容:
  • 構造体matrixに割り当てられたメモリ領域を開放する
void free_matrix(struct matrix *mat) {
    int i;
    for(i = 0; i < mat->row; i++) {
        free(mat->data[i]);
    }
    free(mat->data);
}

forループで各行のデータ本体を保持する領域を捨ててから、各行へのポインタの配列を開放する。

関数名 : int add_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans)
引数 : 加算を行う行列に対応する構造体matrixのポインタ*2, 計算結果を格納するmatrixのポインタ
関数の内容 : 計算結果を格納するメモリ領域を確保、行列を加算して格納
返り値 : 計算可能であった場合に1、計算不可能の場合に2
int add_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j;

    if(mat_1->row != mat_2->row || mat_1->col != mat_2->col) {
        printf("加算を行う行列の行数もしくは列数が一致しません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_1->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            ans->data[i][j] = mat_1->data[i][j] + mat_2->data[i][j];
        }
    }
    return 0;
}
関数名 : int sub_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans)
引数 : 減算を行う行列に対応する構造体matrixのポインタ*2, 計算結果を格納するmatrixのポインタ
関数の内容 : 計算結果を格納するメモリ領域を確保、行列を加算して格納
返り値 : 計算可能であった場合に1、計算不可能の場合に2
int sub_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j;

    if(mat_1->row != mat_2->row || mat_1->col != mat_2->col) {
        printf("加算を行う行列の行数もしくは列数が一致しません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_1->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            ans->data[i][j] = mat_1->data[i][j] - mat_2->data[i][j];
        }
    }
    return 0;
}

この2つはほぼほぼ共通。行数と列数がそれぞれ一致するか確認した後に先程のinit_matrix()でメモリ確保して計算結果を放り込む。

関数名 : int mul_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans)
引数 : 乗算を行う行列に対応する構造体matrixのポインタ*2, 計算結果を格納するmatrixのポインタ
関数の内容 : 計算結果を格納するメモリ領域を確保、行列を加算して格納
返り値 : 計算可能であった場合に1、計算不可能の場合に2
int mul_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j, k;

    if(mat_1->col != mat_2->row) {
        printf("内積が定義できません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_2->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            for(k = 0; k < mat_1->col; k++) {
                ans->data[i][j] += mat_1->data[i][k] * mat_2->data[k][j];
            }
        }
    }
    return 0;
}

行列の積なので解答を格納するメモリ領域の大きさ等が異ってくる。
ただただ各要素に対して内積求めて放り込んでるだけ。

関数名 : scan_matrix(struct matrix *mat, char name)
引数 : 入力を受け付ける構造体matrixのポインタ, 行列の名前
関数の内容 : 標準入力で行列の各要素を入力させる。
void scan_matrix(struct matrix *mat, char name) {
    int i, j;
    char buff[128];

    do {
        printf("行数 > ");
        scanf("%127s", buff);
    } while (atoi(buff) > 0);
    mat->row = atoi(buff);

    do {
        printf("列数 > ");
        scanf("%127s", buff);
    } while (atoi(buff) > 0);
    mat->col = atoi(buff);

    init_matrix(mat);

    for(i = 0; i < mat->row; i++) {
         for(j = 0; j < mat->col; j++) {
            do {
                printf("%c[%d][%d] = ", name, i + 1, j + 1);
                scanf("%127s", buff);
                if(!strcmp(buff, "0")) break;
            } while (!atoi(buff));
            mat->data[i][j] = atoi(buff);
        }
    }
}

scanf()めんどくさいめうね。

全体

matrix.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct matrix {
    int row;
    int col;
    int **data;
};

void init_matrix(struct matrix *mat) {
    int i, j;

    if((mat->data = (int **)malloc(mat->row * sizeof(int *))) == NULL) {
        fprintf(stderr, "メモリ確保エラー\n");
        exit(1);
    }
    for(i = 0; i < mat->row; i++) {
        if((mat->data[i] = (int *)malloc(mat->col * sizeof(int))) == NULL) {
            fprintf(stderr, "メモリ確保エラー\n");
            exit(1);
        }
        for(j = 0; j < mat->col; j++) mat->data[i][j] = 0;
    }
}

void free_matrix(struct matrix *mat) {
    int i;
    for(i = 0; i < mat->row; i++) {
        free(mat->data[i]);
    }
    free(mat->data);
}

void print_matrix(struct matrix *mat) {
    int i, j;

    for(i = 0; i < mat->row; i++) {
        for(j = 0; j < mat->col; j++) {
            printf("%04d ", mat->data[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int add_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j;

    if(mat_1->row != mat_2->row || mat_1->col != mat_2->col) {
        printf("加算を行う行列の行数もしくは列数が一致しません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_1->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            ans->data[i][j] = mat_1->data[i][j] + mat_2->data[i][j];
        }
    }
    return 0;
}

int sub_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j;

    if(mat_1->row != mat_2->row || mat_1->col != mat_2->col) {
        printf("加算を行う行列の行数もしくは列数が一致しません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_1->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            ans->data[i][j] = mat_1->data[i][j] - mat_2->data[i][j];
        }
    }
    return 0;
}

int mul_matrix(struct matrix *mat_1, struct matrix *mat_2, struct matrix *ans) {
    int i, j, k;

    if(mat_1->col != mat_2->row) {
        printf("内積が定義できません\n");
        return 1;
    }

    ans->row = mat_1->row;
    ans->col = mat_2->col;
    init_matrix(ans);
    for(i = 0; i < ans->row; i++) {
        for(j = 0; j < ans->col; j++) {
            for(k = 0; k < mat_1->col; k++) {
                ans->data[i][j] += mat_1->data[i][k] * mat_2->data[k][j];
            }
        }
    }
    return 0;
}

void scan_matrix(struct matrix *mat, char name) {
    int i, j;
    char buff[128];

    do {
        printf("行数 > ");
        scanf("%127s", buff);
    } while (atoi(buff) < 0);
    mat->row = atoi(buff);

    do {
        printf("列数 > ");
        scanf("%127s", buff);
    } while (atoi(buff) < 0);
    mat->col = atoi(buff);

    init_matrix(mat);

    for(i = 0; i < mat->row; i++) {
         for(j = 0; j < mat->col; j++) {
            do {
                printf("%c[%d][%d] = ", name, i + 1, j + 1);
                scanf("%127s", buff);
                if(!strcmp(buff, "0")) break;
            } while (!atoi(buff));
            mat->data[i][j] = atoi(buff);
        }
    }
}


int main(void) {
    struct matrix mat_1, mat_2, ans_1, ans_2, ans_3;

    printf("行列 A を入力\n");
    scan_matrix(&mat_1, 'A');

    printf("行列 B を入力\n");
    scan_matrix(&mat_2, 'B');



    printf("行列A\n");
    print_matrix(&mat_1);
    printf("行列B\n");
    print_matrix(&mat_2);

    printf("A + B\n");
    if(!add_matrix(&mat_1, &mat_2, &ans_1)){
        print_matrix(&ans_1);
        free_matrix(&ans_1);
    }

    printf("A - B\n");
    if(!sub_matrix(&mat_1, &mat_2, &ans_2)){
        print_matrix(&ans_2);
        free_matrix(&ans_2);
    }

    printf("A * B\n");
    if(!mul_matrix(&mat_1, &mat_2, &ans_3)){
        print_matrix(&ans_3);
        free_matrix(&ans_3);
    }

    free_matrix(&mat_1);
    free_matrix(&mat_2);

    return 0;
}
結論

ArrayListって便利

追記

ミスが有ったので直しましたてへぺろ