【问题标题】:Make pointer to multidimensional array in C without knowing dimensions在不知道维度的情况下,在 C 中创建指向多维数组的指针
【发布时间】:2018-12-17 00:41:52
【问题描述】:

假设我有一个指针

char *p;

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

char a[10][15];

我希望 p 指向 a 并能够使用 p[x][y] 来引用数组中的值。我以为 p = a; 通常会处理这个问题,但我遇到了演员错误。

p = &a[0][0];

生成新指针,但将其视为一维字符数组。 有什么办法可以让指针把数组看成二维的?

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

【问题讨论】:

  • char (*p)[10][15]char (*p)[15] 可能都可以,我想不到
  • 给了我同样的错误,在指针的防御中我还不知道数组的尺寸;我在这里给出的数字是为了举例。
  • Accessing multi-dimensional arrays in C using pointer notation 的可能副本 - 正如那里的回答者所说,二维数组衰减为指向数组的指针或指向指针的指针。
  • "当我定义 p 时,我还不知道 a 的尺寸。"很好奇。为什么需要定义p before a?发布证明您需要的代码。
  • 如果您不知道维度,则无法准备导航数组的方法。如果您知道元素的总数,您可以做的是为其分配空间。您可以准备和操作指向该空间的指针。但是,如果您无法确定数组元素的位置,则无法访问它们,这需要知道维度(第一个除外,它仅在知道该维度中有多少元素时才需要)。

标签: c pointers multidimensional-array


【解决方案1】:

声明

char * p;

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

您想要声明一个指向 15 个 chars 的数组的指针,或者指向 15 个 chars 的数组的第一个元素:

char (* p) [15];

现在你可以说

p = a;

并通过p访问a的元素。

【讨论】:

  • 我忘了提到重要的细节,在 p 的定义中,a 的尺寸还不知道。
【解决方案2】:

如果您不知道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 数组的第二维。

【讨论】:

  • 第一部分的代码是对的。以下段落令人困惑。这可能他想要的,因为否则他必须计算偏移量。有了你的代码,他就不用计算了。
  • @MooingDuck 如果您已经在使用C。您可能不希望另一个数组的开销只是使用2d 数组。尤其是当您的阵列实际上没有锯齿状时。
  • 准备一个所谓的“锯齿状”数组(这对性能和其他原因不利)需要准备大量的指针。无需费心费力,只需传递维度就更容易了。
【解决方案3】:

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

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

#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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-25
    • 2020-01-12
    • 2010-11-06
    • 2015-11-14
    • 2013-04-29
    • 2012-08-04
    相关资源
    最近更新 更多