8

我想在内存中存储一​​个下三角矩阵,而不存储所有的零。我实现它的方式是为第 th 行的i + 1元素分配空间。i但是,我是 C 中动态内存分配的新手,我的第一次分配似乎有问题。

int main ()
{
    int i, j;
    int **mat1;
    int dim;

    scanf("%d", &dim);
    *mat1 = (int**) calloc(dim, sizeof(int*));

    for(i = 0; i < dim; i++)
    mat1[i] = (int*) calloc(i + 1, sizeof(int));

    for(i = 0; i < dim; i++)
    {
        for(j = 0; j < i + 1; j++)
        {
            scanf("%d", &mat1[i][j]);
        }
    }

    /* Print the matrix without the zeros*/
    for(i = 0; i < dim; i++)
    {
        for(j = 0; j < (i + 1); j++)
        {
            printf("%d%c", mat1[i][j], j != (dim-1) ? ' ' : '\n');
        }
    }

    return 0;
}
4

3 回答 3

11

如果您想节省空间和分配矩阵每一行的开销,您可以通过使用单个数组的巧妙索引来实现三角矩阵。

下三角矩阵(包括对角线)具有以下性质:

维度矩阵元素/行总元素
1 个 . . 1 1
2个 . 2 3
3 xxx 。3 6
4 xxxx 4 10
...

给定维度的元素总数为:

size(d) = 1 + 2 + 3 + ... + d  =  (d+1)(d/2)

如果将行连续放置在单个数组中,则可以使用上面的公式计算矩阵内给定行和列(均从零开始)的偏移量:

index(r,c) = size(r-1) + c

上面的公式适用于下三角矩阵。您可以通过简单地反转索引来访问上矩阵,就像它是下矩阵一样:

index((d-1)-r, (d-1)-c)

如果您担心改变阵列的方向,您可以为上部阵列设计不同的偏移计算,例如:

uindex(r,c) = size(d)-size(d-r) + c-r

示例代码:

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

#define TRM_SIZE(dim) (((dim)*(dim+1))/2)
#define TRM_OFFSET(r,c) (TRM_SIZE((r)-1)+(c))
#define TRM_INDEX(m,r,c) ((r)<(c) ? 0 : (m)[TRM_OFFSET((r),(c))])
#define TRM_UINDEX(m,r,c,d) ((r)>(c)?0:(m)[TRM_SIZE(d)-TRM_SIZE((d)-(r))+(c)-(r)])
#define UMACRO 0


int main (void)
{
  int i, j, k, dimension;
  int *ml, *mu, *mr;

  printf ("Enter dimension: ");
  if (!scanf ("%2d", &dimension)) {
    return 1;
  }

  ml = calloc (TRM_SIZE(dimension), sizeof *ml);
  mu = calloc (TRM_SIZE(dimension), sizeof *mu);
  mr = calloc (dimension*dimension, sizeof *mr);
  if (!ml || !mu || !mr) {
    free (ml);
    free (mu);
    free (mr);
    return 2;
  }

  /* Initialization */

  srand (time (0));
  for (i = 0; i < TRM_SIZE(dimension); i++) {
    ml[i] = 100.0*rand() / RAND_MAX;
    mu[i] = 100.0*rand() / RAND_MAX;
  }

  /* Multiplication */

  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      for (k = 0; k < dimension; k++) {
        mr[i*dimension + j] +=
#if UMACRO
          TRM_INDEX(ml, i, k) *
          TRM_UINDEX(mu, k, j, dimension);
#else
          TRM_INDEX(ml, i, k) *
          TRM_INDEX(mu, dimension-1-k, dimension-1-j);
#endif
      }
    }
  }

  /* Output */

  puts ("Lower array");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      printf (" %2d", TRM_INDEX(ml, i, j));
    }
    putchar ('\n');
  }
  puts ("Upper array");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
#if UMACRO
      printf (" %2d", TRM_UINDEX(mu, i, j, dimension));
#else
      printf (" %2d", TRM_INDEX(mu, dimension-1-i, dimension-1-j));
#endif
    }
    putchar ('\n');
  }
  puts ("Result");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      printf (" %5d", mr[i*dimension + j]);
    }
    putchar ('\n');
  }

  free (mu);
  free (ml);
  free (mr);

  return 0;
}

请注意,这是一个简单的示例。您可以扩展它以将矩阵指针包装在一个结构中,该结构还存储矩阵的类型(上三角形或下三角形或正方形)和尺寸,并编写根据矩阵类型适当操作的访问函数。

对于矩阵的任何重要用途,您可能应该使用专门研究矩阵的第三方库。

于 2014-12-29T00:46:32.760 回答
4
mat1 = calloc(dim,sizeof(int*));

mat1是双指针。您需要为指针数组分配内存,稍后您需要为每个指针单独分配内存。无需强制转换calloc()

于 2014-12-09T13:33:35.527 回答
2

您在第 8 行取消对 mat1的引用,甚至还没有将它设置为指向任何位置。您正在分配一个指向 int 的指针数组,但您没有将其分配给mat1 ,而是分配给未初始化的 mat1 的取消引用,我们不知道它指向什么。

所以这一行:

// ERROR: You are saying an unknown memory location should have the value of calloc.
*mat1 = (int**)calloc(dim,sizeof(int*));

应改为:

// OK: Now you are assigning the allocation to the pointer variable.
mat1 = (int**)calloc(dim,sizeof(int*));
于 2014-12-09T13:34:04.257 回答