【问题标题】:Differences between matrix implementation in CC中矩阵实现的区别
【发布时间】:2012-09-28 20:49:59
【问题描述】:

我以两种不同的方式在 C 中创建了两个二维数组(矩阵)。
我不明白它们在内存中的表示方式之间的区别,以及我不能以相同方式引用它们的原因:

scanf("%d", &intMatrix1[i][j]); //can't refer as  &intMatrix1[(i * lines)+j])

scanf("%d", &intMatrix2[(i * lines)+j]); //can't refer as &intMatrix2[i][j])

这两个数组的实现方式有什么区别,为什么我必须以不同的方式引用它们?

如何以相同的方式引用每个数组中的元素(printMatrix 函数中的??????)?

int main()
{
   int **intMatrix1;
   int *intMatrix2;

   int i, j, lines, columns;

   lines = 3;
   columns = 2;

   /************************* intMatrix1 ****************************/

   intMatrix1 = (int **)malloc(lines * sizeof(int *));

   for (i = 0; i < lines; ++i)
      intMatrix1[i] = (int *)malloc(columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix1[%d][%d]\t", i, j);
       scanf("%d", &intMatrix1[i][j]); 
       }
   }

   /************************* intMatrix2 ****************************/ 

   intMatrix2 = (int *)malloc(lines * columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix2[%d][%d]\t", i, j);
       scanf("%d", &intMatrix2[(i * lines)+j]);
       }
   }

   /************** printing intMatrix1 & intMatrix2 ****************/

   printf("intMatrix1:\n\n");
   printMatrix(*intMatrix1, lines, columns);

   printf("intMatrix2:\n\n");
   printMatrix(intMatrix2, lines, columns);
}


/************************* printMatrix ****************************/

void printMatrix(int *ptArray, int h, int w)
{
    int i, j;

    printf("Printing matrix...\n\n\n");

    for (i = 0; i < h; ++i)
        for (j = 0; j < w; ++j)
        printf("array[%d][%d] ==============> %d\n, i, j, ??????);
}

【问题讨论】:

  • 但实际上没有二维数组之类的东西-AFAIK,它们都只是内存中的一行字节。
  • This question 看起来很相似。
  • stackoverflow.com/questions/16004668/… 我已经为 gcc C11/C99 做了一个解决方案,具有适当的分配功能。也许4u会有用...

标签: c matrix


【解决方案1】:

您将取消引用 Matrix1 两次..

Matrix1[i][j] ;

表示它是一个二维数组或这样声明的双指针。

int **Matrix1 ;

double pointer 可以被认为是指针数组。它的每个元素本身就是一个指针,因此它被取消引用一次以到达指针元素,并取消引用两次以访问该成员指针或数组的数据成员。你写的这个声明相当于这个..

Matrix1[i][j] ;   //is ~ to

*( *(Matrix1 + i) + j) ;

对于这样的单个指针。

int *Matrix2 ;

你只能取消引用一次,像这样。

Matrix2[i] ;  //is ~ to
*(Matrix2 + i) ;

你写的这个声明..

Matrix2[(i * lines)+j] ;
         |-----------|

这部分计算结果为一个数字,因此它取消了一次。

(i * lines) + j ;

对于您的printmatrix() 函数,传递给它的ptArray 是一个单指针。所以你不能取消引用它两次。

也许您可以从我的回答中更好地理解静态和动态二维数组。

2D-array as argument to function

【讨论】:

    【解决方案2】:

    两个矩阵都是内存中的字节序列。但是,它们之间的区别在于您如何定义内存接口来表示矩阵。在一种情况下,您只是定义了一个内存段,其元素数量等于矩阵中的元素,而在另一种情况下,您专门分配内存来表示每个特定的行。

    以下情况的计算成本更高,因为您调用 ma​​lloc() 的次数更多:

    intMatrix1 = (int **)malloc(lines * sizeof(int *));
    for (i = 0; i < lines; ++i)
      intMatrix1[i] = (int *)malloc(columns * sizeof(int));
    

    但是,它带来的优势是您可以更清晰地引用矩阵元素:

    intMatrix1[i][j];
    

    如果你只分配一个元素序列等于矩阵中元素的数量,你必须考虑行/列索引计算来引用内存中正确的矩阵元素。

    为了尝试增加代码的统一程度,我可以建议一个接收矩阵行引用和矩阵列数并打印一行的函数吗?

    void PrintLine(int *ptrLine, int lineLen) {
       unsigned int i;
       for(i = 0; i < lineLen; i++)
          printf("%d ", ptrLine[i]);
       printf("\n");
    }
    

    然后,对于每种矩阵类型,您只需:

    // Case 1
    for(i = 0; i < lines; i++)
       PrintLine(intMatrix1[i], columns);
    // Case 2
    for(i = 0; i < lines; i++) {
       PrintLine(intMatrix2 + i*columns, columns);
    }
    

    【讨论】:

      【解决方案3】:

      在 C 中,数组访问运算符 [] 实际上只是执行 pointer arithmetic 的一种更简洁的方式。对于type_s 类型的元素的一维数组,arr[i] 等价于*(arr + (i * sizeof(type_s)))。剖析该表达式:

      • arr 将是基地址,即存储此数组的最低内存地址
      • i 是数组中元素的零索引位置
      • sizeof 返回 chars 的数量(通常与字节数相同,但 C 规范没有强制要求),arr 中的元素在内存中占用。编译器将确定元素的大小并为您执行此数学运算。

      附带说明一下,此语法具有 arr[i] 等效于 i[arr] 的副作用,尽管普遍接受将索引放在括号中。

      说了这么多,让我们看看你的两个声明之间的区别:

      intMatrix1[i][j] 等价于*(*(intMatrix1 + i * sizeof(int)) + j * sizeof(int))。因此,该表达式中有 两个 取消引用运算符,这意味着 intMatrix 是一个数组数组(它包含指向指针的指针)。

      另一方面,intMatrix2[(i * lines)+j] 等价于 *(intMatrix2 + ((i * lines) + j) * sizeof(int)),后者仅包含一个取消引用运算符。您在这里所做的是定义一个包含与原始二维数组相同数量的元素的一维数组。如果您的数据可以最好地用矩阵表示,那么我建议您使用第一个版本:intMatrix1[i][j]

      【讨论】:

        【解决方案4】:

        不同的是第一个数组:

        intMatrix1 = (int **)malloc(lines * sizeof(int *));
        

        创建一个指针数组intMatrix1。这些指针中的每一个都指向一个 int 数组(你在这里 malloc)。

        for (i = 0; i < lines; ++i)
           intMatrix1[i] = (int *)malloc(columns * sizeof(int));
        

        这就是为什么你需要声明中的 2 星(取消引用指针数组,然后是 int 数组)和双括号来访问单个元素:

        int **intMatrix1;
        
        int i = intMatrix[row][column];
        int i = *(*(intmatrix + row) + column);
        

        对于第二个矩阵,您只创建一个大小为 column * rows 的 int 数组。

        int *intMatrix2 = (int *)malloc(lines * columns * sizeof(int));
        
        int i = intMatrix[row + column];
        int i = *(intMatrix + row + column);
        

        要打印 2 个数组,您必须使用不同的打印函数,因为 2 个矩阵的内部结构不同,但您已经知道访问这两个数组的不同方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多