参考C中的二维数组列?

时间:2009-03-30 19:47:58

标签: c arrays

是否有一种简单的方法可以将二维数组中的列作为普通旧C (不是C ++或C#)中的单独1-D数组引用?这样做很容易。 Asssume我有两个功能:

double doSomethingWithARow( double theRow[3] );
double doSomethingWithACol( double theCol[100] );

然后,我可能会像这样使用第一个:

double matrix[100][3];
double result;

// pass a single row to a function as an array
// this essentially passes the 3-element array at row 48 to the function
for( int i=0; i < 100; i++ )
{
   result = doSomethingWithARow( matrix[i] );
}

我希望它能够轻松地访问列。

for( int j=0; j < 3; j++ )
{
   result = doSomethingWithACol( ??????????? );
}

到目前为止,我唯一想到的就是转换矩阵以将行与列交换。但是这个代码应该在内存和速度方面尽可能高效。有了所有用C语言引用指针的复杂方法,似乎应该有办法做到这一点。

5 个答案:

答案 0 :(得分:5)

好吧,你必须传递一行的大小和行数:

 double doSomethingWithACol(double *matrix, size_t colID, size_t rowSize, size_t nRows);

现在你可以利用矩阵[i] [j] =矩阵+ i * rowSize + j;

这一事实

或者,您还可以使用以下签名:

 double doSomethingWithACol(double *colPtr, size_t rowSize, size_t nRows);

在这里,您必须将指针传递给要处理的列的第一个元素,而不是指向第一行的指针。


示例代码:此代码汇总第二列中的元素(使用 gcc -o main -Wall -Wextra -pedantic -std = c99 test.c 进行编译) :

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

double colSum1(double *matrix, size_t colID, size_t rowSize, size_t nRows)
{
  double *c = NULL, *end = matrix + colID + (nRows * rowSize);
  double sum = 0;

  for (c = matrix + colID; c < end; c += rowSize) {
    sum += *c;
  }

  return sum;
}

double colSum2(double *colPtr, size_t rowSize, size_t nRows)
{
  double *end = colPtr + (nRows * rowSize);
  double sum = 0;

  for (; colPtr < end; colPtr += rowSize) {
    sum += *colPtr;
  }

  return sum;
}

int
main(void)
{
  double matrix[4][3] = {
    {0,  1, 2},
    {3,  4, 5},
    {6,  7, 8},
    {9, 10, 11}
  };

  printf("%f\n", colSum1(*matrix, 1, 3, 4));
  printf("%f\n", colSum2(&matrix[0][1], 3, 4));
  printf("%f\n", colSum2(matrix[0] + 1, 3, 4));

  return EXIT_SUCCESS;
}

答案 1 :(得分:3)

在不将尺寸指定为单独参数的情况下执行此操作的一种不错的类型安全方法如下:

#define ROWS 100
#define COLUMNS 30 

void doSomethingToAllRows(double (*row)[ROWS][COLUMNS], int col, double val)
{
    for(size_t i = 0; i < ROWS; ++i)
        (*row)[i][col] = val;
}

void doSomethingToAllColumns(double (*col)[ROWS][COLUMNS], int row, double val)
{
    for(size_t i = 0; i < COLUMNS; ++i)
        (*col)[row][i] = val;
}

int main(int argc, char **argv)
{
    double matrix[ROWS][COLUMNS];

    /* Modify each column of the 10th row with the value of 3 */
    doSomethingToAllColumns(&matrix, 10, 3); 

    /* Modify each row of the 10th column with the value of 3 */
    doSomethingToAllRows(&matrix, 10, 3);

    return 0;
}

由于这个原因传递双**是完全错误的:

void test()
{
  double **a;
  int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)

  double matrix[ROWS][COLUMNS];
  int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}

如果你传入了一个双**然后像一个数组一样访问它,你会导致崩溃,段错误或未定义的行为。

答案 2 :(得分:0)

由于您调用它们的“列”不连续地存储在内存中,因此无法直接将其关闭。

但是,您可以创建一个指针数组,并将引用存储到该另一个数组的索引中。您需要遍历数组中的所有元素,因此它可能不是一个比其他任何更好的解决方案。根据您需要按列访问数组的频率,这可能是值得的。

答案 3 :(得分:0)

你不能真的这样做,因为存储C中的数组使得每行的元素存储在一起。这意味着一行数组是一个连续的内存块,就C而言,它本身也可能是一个独立的数组。它与列的工作方式不同,因为列的元素在内存中不连续;相反,它们的间隔为N个字节,每行的长度为N个字节。这意味着您可以通过使用指针算法有效地访问2D数组的各列的元素,但除了将元素复制到数组之外,没有办法将列实际创建为数组本身。一个新阵列。

答案 4 :(得分:0)

不,没有。不可能,因为在C中,数组是内存的连续部分,并且行列不能同时连续是微不足道的。

话虽如此,如果您知道行的长度,从列的一个单元格跳到下一个单元格相当容易。请看以下示例:

void processColumn(double *array, int colIdx, int rowLen, int rowCnt) {
    for (int i = colIdx; i < rowCnt * rowLen; i += rowLen) {
       // do whatever you want
    }
}

#define N 5
#define M 10

double array[N*M];

processColumn(array, 3, N, M);