假设我有一个指针
char *p;
在我的main
函数中,我有一个多维数组a:
char a[10][15];
我希望p
指向a
并能够使用p[x][y]
引用数组中的值。我以为p = a;
通常会解决这个问题,但出现强制转换错误。
p = &a[0][0];
生成新的指针,但将其视为char的一维数组。 有什么办法使指针将数组视为二维的?
请注意,当我定义p
时,我还不知道a
的尺寸。
答案 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);
}