Матрица переменного размера в C - PullRequest
4 голосов
/ 24 марта 2012

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

Спасибо, Vi.

Ответы [ 6 ]

3 голосов
/ 24 марта 2012

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

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

в матрице.ч

#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 
2 голосов
/ 24 марта 2012

Как я вижу, вы не хотите объявлять как: 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.

1 голос
/ 24 марта 2012

Как только вы знаете размер, вам нужно выделить достаточно места в куче, чтобы приспособиться к этому размеру. Вы можете выделить место в куче с помощью 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, либо запросить больше места в куче, скопировать значения и освободить старую память.

1 голос
/ 24 марта 2012

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

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

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

0 голосов
/ 24 марта 2012

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

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 голосов
/ 24 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...