在C语言中指向多维​​数组的指针

时间:2018-12-17 00:41:52

标签: c pointers multidimensional-array

假设我有一个指针

char *p;

在我的main函数中,我有一个多维数组a:

char a[10][15];

我希望p指向a并能够使用p[x][y]引用数组中的值。我以为p = a;通常会解决这个问题,但出现强制转换错误。

p = &a[0][0];

生成新的指针,但将其视为char的一维数组。 有什么办法使指针将数组视为二维的?

请注意,当我定义p时,我还不知道a的尺寸。

3 个答案:

答案 0 :(得分:0)

声明

char * p;

使p指向类型为char的对象或类型为char的对象数组的第一个元素的指针。

您要声明一个指向15 char s数组的指针,或指向15 char s数组的数组的第一个元素的指针:

char (* p) [15];

现在你可以说

p = a;

然后通过a访问p的元素。

答案 1 :(得分:0)

如果您不知道a的尺寸。您需要一个jagged array。那是另一个数组,用于存储每个子数组的地址。

char a1[10];
char a2[20];
char a3[30];
char* jagged[3] = {a1, a2, a3};
char** p = jagged;

但是另一个阵列的开销可能不是您想要的。

没有锯齿状的数组,您至少必须知道数组的第二维才能找到所需的元素。对于数组a[10][15],要找到元素a[x][y],代码将通过计算x * 15 + y获得该元素的偏移量。注意该表达式中的15,它是2d数组的第二维。

答案 2 :(得分:0)

C没有提供机制来传递可变大小的多维数组的维数。您必须自己实现它,即您必须提出自己的类型,即int array[10][20]。例如,在下面的(未试用)代码中,您可以传递int_array *,并使用int_at来获取值。您还可以检查int_array中的尺寸,等等。使用int_array *的代码甚至不需要知道它有多少尺寸。

vint_ptr_at几乎可以完成编译器生成的代码在计算地址时会执行的操作,尽管该代码可以比通用版本更好地进行优化。通常,如果要迭代,可以使用从int*获得的int_ptr_at,并不断增加它。

#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>

typedef struct {
  int *data;
  int num_dims;
  bool owns_data;
  struct {
    size_t count, product;
  } dims[1];
} int_array;

void free_int_array(int_array *arr) {
  if (arr && arr->owns_data) free(arr->data);
#ifdef DEBUG
  arr->data = NULL;
#endif
  free(arr);
}

static bool int_array_setup_dims(int_array *arr, va_list args) {
  size_t n = 1;
  int const num_dims = arr->num_dims;
  for (int i = 0; i < num_dims; i++) {
    int dim = va_arg(args, int);
    arr->dims[i].count = dim;
    arr->dims[num_dims - 1 - i].product = n;
    if (n > SIZE_MAX / dim) return false;
    n *= dim;
  }
  return true;
}

int_array *vnew_int_array_on(void *data, int num_dims, va_list args) {
  int_array *arr = malloc(sizeof(int_array) + (num_dims-1)*sizeof(int));
  if (!arr) goto fail;
  arr->num_dims = num_dims;
  if (!int_array_setup_dims(arr, args)) goto fail;

  arr->data = data ? data : malloc(n * sizeof(int));
  arr->num_dims = num_dims;
  arr->owns_data = !data;
  if (!arr->data) goto fail;
  return arr;
fail:
  free(arr);
  return NULL;
}

int_array *new_int_array(int num_dims, ...) {
  va_list args;
  va_start(args, num_dims);
  int_array *arr = vnew_int_array_on(NULL, num_dims, args);
  va_end(args);
  return arr;
}

int_array *new_int_array_on(void *data, int num_dims, ...) {
  va_list args;
  va_start(args, num_dims);
  int_array *arr = vnew_int_array_in(data, num_dims, args);
  va_end(args);
  return arr;
}

int *vint_ptr_at(const int_array *arr, va_list args) {
  size_t index = 0, n = 1;
  int const num_dims = arr->num_dims;
  for (int i = 0; i < num_dims; i++) {
    int j = va_arg(args, int);
    index += j * arr->dims[i].product;
  }
  return arr->data + index;
}

int *int_ptr_at(const int_array *arr, ...) {
  va_list args;
  va_start(args, arr);
  int *ptr = vint_ptr_at(arr, args);
  va_end(args);
  return ptr;
}  

int int_at(const int_array *arr, ...) {
  va_list args;
  va_start(args, arr);
  int *ptr = vint_ptr_at((int_array*)arr, args);
  va_end(args);
  return *ptr;
}

size_t *indices_for(const int_array *arr) {
  if (!arr) return NULL;
  size_t const size = sizeof(size_t) * arr->num_dims;
  size_t *indices = malloc(size);
  if (indices) memset(indices, 0, size);
  return indices;
}

bool next_index(const int_array *arr, size_t *indices) {
  for (int i = arr->num_dims - 1; i >= 0; i--) {
    if (indices[i] < arr->dims[i].count) {
      indices[i] ++;
      return true;
    }
    indices[i] = 0;
  }
  return false;
}

int main() {
  int data[10][15];
  int_array *arr = new_int_array_on(data, 2, 10, 15);
  assert(arr->dims[0].dim == 10);
  assert(arr->dims[1].dim == 15);
  data[2][3] = 40;
  data[4][5] = 50;
  data[5][6] = 100;
  assert(int_at(arr, 2, 3) == 40);
  assert(int_at(arr, 4, 5) == 50);
  assert(int_at(arr, 5, 6) == 100);
  free_int_array(arr);
}
#include <stdio.h>

void iteration_example(const int_array *arr) {
  size_t *indices = indices_for(arr);
  if (indices) {
    int *data = arr->data;
    do {
      printf("arr");
      for (int i = 0; i < arr->num_dims; ++i)
        printf("[%zd]", indices[i]);
      printf(" = %d\n", *data++);
    } while (next_index(arr, indices));
  }
  free(indices);
}