#include <stdio.h>
#include <stdlib.h>
#include "dumper.h"
struct args {
int number;
int array[];
};
int main( int argc, char **argv )
{
if ( argc < 3 )
{
fprintf( stderr, "USAGE: %s rows columns\n", argv[0] );
return EXIT_FAILURE;
}
size_t r = strtoul( argv[1], NULL, 0 );
size_t c = strtoul( argv[2], NULL, 0 );
/**
* Allocate enough space for the struct instance plus
* an r x c array of int. sizeof (int) * c * r would
* also work, this just makes it clear that I'm allocating
* enough space for r instances of c-element arrays.
*/
struct args *a = malloc( sizeof *a + sizeof (int [c]) * r );
if ( a )
{
a->number = r;
/**
* a->array is a 1D array - however, we can map a
* pointer to a c-element array onto a->array,
* allowing us to use regular 2D array subscripting
* to access array elements.
*/
int (*map)[c] = (int (*)[c]) a->array;
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
map[i][j] = c * i + j; // rather than a->array[c * i + j]
/**
* Dumper is a utility I wrote to display the addresses
* and contents of multiple objects.
*/
char *names[] = { "a", "a->array", "map" };
void *addrs[] = { a, a->array, map };
size_t sizes[] = { sizeof *a + sizeof (int [c]) * r,
sizeof *map * r, sizeof *map * r };
dumper( names, addrs, sizes, 3, stdout );
/**
* Display the value of the various struct members
*/
printf( "a->number = %d\n", a->number );
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
printf( "a->array[%zu][%zu] = %d\n", i, j, map[i][j] );
free( a );
}
return 0;
}
struct args a;
/**
* Allocate enough memory to store r pointers to int
*/
a.array = malloc( sizeof *a.array * r );
/**
* For each a.array[i], allocate space for c ints
*/
for ( size_t i = 0; i < r; i++ )
{
a.array[i] = malloc( sizeof *a.array[i] * c );
}
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
a.array[i][j] = c * i + j;
5条答案
按热度按时间qqrboqgw1#
您可以动态地分配数组,也可以定义一个宏或访问函数来使用二维索引访问元素。例如:
rxztt3cl2#
因为你需要一个运行时大小的二维数组,所以你不能使用二维数组语法,例如
a[row][col]
。你将不得不分配一个“平面”数组SIZE*SIZE的大小,然后使用函数调用GetAt(Row,Col)和SetAt(Row,Col,Value)并执行指针算术(简单地index = (row * SIZE) + col;
),然后在平面数组中使用一维索引。记住释放动态分配的阵列!
zphenhs43#
如果你想使用2D语法动态分配数组,你应该像这样声明你的数组:
然后分配数组的第一维:
那么第二维
下面是一个完整的工作示例
vwkv1x7d4#
不幸的是,不能在
struct
定义中使用变长数组;你将不得不依赖于动态内存分配。有几种方法可以做到这一点,但你使用哪一种取决于几件事。
数组是否需要是
struct
示例的一部分,与number
相邻?如果您需要序列化
struct
示例的内容(写入二进制文件、通过网络发送等),就会出现这种情况。当然,您还需要某种方法来保存行数和列数。AFAIK,唯一的方法是使用灵活的数组成员;这将是一个1D数组,如果你想使用2D数组下标,你可以将一个指针Map到一个
c
元素数组。快速和肮脏的例子:下面是一个2 x 3数组的输出:
您可以看到数组内容与结构体示例中的
number
成员相邻。如果你不想使用
map
指针,你可以把索引计算为我只是觉得使用2D下标更容易,更清晰。
数组是否可以存在于与
struct
示例不连续的内存中,但数组本身仍然需要是连续的?在这种情况下,
struct
的定义为我们仍然将
array
成员视为1D数组:和上面的例子一样,我们可以创建一个指向
c
元素数组的指针,以允许我们使用2D数组下标:或者你也可以用
完整示例:
带输出:
正如你所看到的,数组的内容并不存储在
struct
示例本身中,相反,我们将数组的第一个元素的地址存储在array
成员(0x600001d3c240
)中。注意,在number
和array
之间有四个字节的填充。如果你不需要数组是连续的,你可以单独分配行,比如:
在这种情况下,您的
struct
定义将是你会使用两步分配方法:
这种方法的优点是可以在
a.array
上使用常规的2D数组下标;你不需要把指向数组的指针Map到它上面。完整示例:
带输出:
在这种情况下,
a.array
存储指针数组(0x600003979120
)的第一个元素的地址,每个a.array[i]
存储int
的4元素数组的地址。您使用哪种方法取决于您的需要。他们都有自己的长处和短处。
imzjd6km5#
如果你的编译器支持可变长度数组(VLA),你可以尝试以下选项:
这里你的数组是在堆栈上分配的(所以要注意它的大小),并在程序退出时自动释放。所以你不需要管理堆。
缺点是您必须从给定的列和行手动计算项的线性索引。在C中不可能声明一个不完整的二维数组,因此它的元素可以使用 [i][j] 表示法引用。