2012-03-24 3 views
4

Как реализовать переменную размерную матрицу (int) в C? Для уточнения я должен иметь возможность добавлять строки и столбцы в соответствии с фактами ситуации (внутри предложения if).Матрица с переменным размером в C

Спасибо, Vi.

ответ

3

Вы можете написать интерфейс для разделения компонентов многократного использования. Основным решением, которое вы должны принять, является реализация разреженной или плотной схемы размещения.

Предполагая плотную схему, объект может быть

в matrix.h

#include <stdio.h> 

typedef struct matrix { 
    int nrows, ncols, *data; 
} matrix; 

matrix* allocate(matrix *mat, int nrows, int ncols); 
int *cell(const matrix *mat, int row, int col); 
matrix *addrow(matrix *mat); 
matrix *addcol(matrix *mat); 
matrix *print(FILE *f, matrix *mat); 

в matrix.c

#include "matrix.h" 
#include <assert.h> 
#include <stdlib.h> 
#include <string.h> 

matrix* allocate(matrix *mat, int nrows, int ncols) 
{ 
    assert(nrows > 0 && ncols > 0); 
    mat->nrows = nrows; 
    mat->ncols = ncols; 
    mat->data = malloc(sizeof(int) * nrows * ncols); 
    return mat; 
} 

int *cell(const matrix *mat, int row, int col) 
{ 
    assert(row >= 0 && row < mat->nrows); 
    assert(col >= 0 && col < mat->ncols); 
    return mat->data + row * mat->ncols + col; 
} 

matrix *addrow(matrix *mat) 
{ 
    mat->nrows++; 
    mat->data = realloc(mat->data, sizeof(int) * mat->nrows * mat->ncols); 
    return mat; 
} 

/* adding a column it's an expensive operation */ 
matrix *addcol(matrix *mat) 
{ 
    mat->ncols++; 
    mat->data = realloc(mat->data, sizeof(int) * mat->nrows * mat->ncols); 

    /* shift rows' elements, to make room for last column */ 
    for (int r = mat->nrows - 1; r > 0; --r) 
    { 
    int *dest = mat->data + r * mat->ncols, 
     *orig = mat->data + r * (mat->ncols - 1); 
    memmove(dest, orig, sizeof(int) * (mat->ncols - 1)); 
    } 
    return mat; 
} 

matrix *print(FILE *f, matrix *mat) 
{ 
    for (int r = 0; r < mat->nrows; ++r) 
    { 
     for (int c = 0; c < mat->ncols; ++c) 
      fprintf(f, "%4d ", *cell(mat, r, c)); 
     fprintf(f, "\n"); 
    } 
    return mat; 
} 

int main_matrix(int argc, char **argv) 
{ 
    matrix m; 
    allocate(&m, 3, 5); 

    for (int r = 0; r < m.nrows; ++r) 
     for (int c = 0; c < m.ncols; ++c) 
      *cell(&m, r, c) = 35; 
    print(stdout, &m); 
    fprintf(stdout, "\n"); 

    addrow(&m); 
    for (int c = 0; c < m.ncols; ++c) 
     *cell(&m, m.nrows - 1, c) = 45; 
    print(stdout, &m); 
    fprintf(stdout, "\n"); 

    addcol(&m); 
    for (int r = 0; r < m.nrows; ++r) 
     *cell(&m, r, m.ncols - 1) = 46; 
    print(stdout, &m); 
    fprintf(stdout, "\n"); 

    // remember to free memory 
    free(m.data); 

    return argc; 
} 

тест выход:

35 35 35 35 35 
    35 35 35 35 35 
    35 35 35 35 35 

    35 35 35 35 35 
    35 35 35 35 35 
    35 35 35 35 35 
    45 45 45 45 45 

    35 35 35 35 35 46 
    35 35 35 35 35 46 
    35 35 35 35 35 46 
    45 45 45 45 45 46 
+0

Спасибо, очень, я понимаю свою ошибку! –

1

Просто потому, что C не поддерживает языковую поддержку объектно-ориентированных идей, таких как инкапсуляция и скрытие информации, не означает, что вы не можете использовать их в своем коде; вам просто нужно усердно работать, чтобы ввести их в действие.

Это было слишком долго, так как я написал C, чтобы быть более конкретным, но Eric Roberts в Стэнфорде преподавал несколько отличных методик в курсе программирования C. Я бы рекомендовал вам заглянуть в них.

Идея состоит в том, что вам нужно будет восстановить память для матрицы нового размера, скопировать в нее старые элементы, инициализировать новые значения, очистить старую память и назначить новую матрицу указательной переменной , Если вы спрячете все это в методе, клиенты вашего кода просто назовут его и не будут беспокоиться о магии, которую вы делаете под ней. Вам не придется повторять сложности в нескольких местах. Вы просто назовете один метод и сделаете это.

1

Как только вы знаете размер, вам нужно выделить достаточно места на куче для размещения такого размера. Вы можете выделить место в куче malloc или calloc.

Например:

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

void set_value(int * matrix, int row, int col, int value); 
int get_value(int * matrix, int row, int col); 

int main() { 
    int rows = 5; /* arbitrary */ 
    int cols = 3; /* arbitrary */ 
    int * matrix = (int *) calloc(rows * cols, sizeof(int)); 

    if (matrix == NULL) { 
     printf("Error with allocation!\n"); 
     return -1; 
    } 

    set_value(matrix, 0, 0, 5); 
    set_value(matrix, 0, 1, 2); 
    set_value(matrix, 4, 2, 1); 

    printf("%d\n", get_value(matrix, 0, 0)); 
    printf("%d\n", get_value(matrix, 0, 1)); 
    printf("%d\n", get_value(matrix, 4, 2)); 

    free(matrix); 

    return 0; 
} 

void set_value(int * matrix, int row, int col, int value) { 
    *(matrix + col * sizeof(int) + row) = value; 
} 

int get_value(int * matrix, int row, int col) { 
    return *(matrix + col * sizeof(int) + row); 
} 

Просто убедитесь, что вы всегда проверить, что вызов malloc или calloc работал, и что вы всегда освободить память позже free.

Если вам когда-либо понадобится изменить размер матрицы, вам придется либо использовать realloc, либо запросить больше места на куче, скопировать ваши значения и освободить более старую память.

+0

Я надеваю Когда я начинаю, я знаю размер. Я бы добавил поэтапные строки и столбцы в соответствии с условными предложениями. –

0

я думаю, что вы можете создать буфер динамической памяти выделения «таНос»

+1

Добро пожаловать в SO! Отвечая на вопросы, старайтесь быть конкретными и включайте код, где сможете. – lnafziger

2

Как я вижу, вы не хотите, чтобы объявить, как: int arr[5][5];

Вы можете использовать мои malloc и realloc. Например, чтобы создать 2D массив динамически:

int nrows; 
int ncolumns; 

scanf("%d %d", &nrows, &ncolumns); 

int **arr = malloc(nrows * sizeof(int *)); 
    for(i = 0; i < nrows; i++) 
     arr[i] = malloc(ncolumns * sizeof(int)); 

Тогда к realloc, если вы хотите изменить размер. Преимущество использования realloc заключается в том, что он автоматически позаботится о копировании значений из исходных мест памяти в новое место в случае, если он не может расширить память в том же регионе.

Обратите внимание, что здесь его для 2D-массива. Если вы хотите изменить сам размер или если вы хотите иметь возможность изменять размеры, вы можете скомпоновать аналогично вышеизложенному с другой функцией для каждого из таких случаев. Опять же, это будет выглядеть немного уродливо. Но нет такого элегантного способа делать такие вещи в C.

-2

Я только что написал ... Надеюсь, он сработает.

int **matrix; 

int m=10; 
int n=10; 

int i,j; 

matrix = (int)** malloc (m*sizeof(int*)); 
for(i=0;i<m;i++){ 
matrix[i]= (int)* malloc (n*sizeof(int)); 
for(j=0;j<n;j++) 
matrix[i][j] = (10.0*rand()); 
} 

free(matrix); 
+0

большая утечка памяти при освобождении только 'matrix' –

Смежные вопросы