英文:
How to create a user defined sized 2d array of struct in C
问题
Sure, here's the translated code part:
我希望用户在主函数中定义2D数组的大小,我目前有这个结构体:
struct args
{
int number;
int array[SIZE][SIZE];
}
这个代码可以正常工作,但是我想删除#define SIZE命令,让用户定义SIZE的值,所以在主函数中,我希望从键盘获取大小,如下所示:
int SIZE;
printf("请输入数组大小:");
scanf("%d", &SIZE);
Is there anything else you need help with?
英文:
I would like the user to define the size of the 2d array in the main, I currently have this struct:
#define SIZE 2
struct args
{
int number;
int array[SIZE][SIZE];
}
This works fine, however, I would like to remove the #define SIZE command, and let SIZE be a value that the user defines, so in the main function I want to get from keyboard as:
int SIZE;
printf("enter array size");
scanf("%d", &SIZE);
Can you help me?
答案1
得分: 4
你可以动态分配数组,并可选择定义一个宏或访问函数,以使用二维索引访问元素。例如:
struct args
{
int number;
int *array;
};
#define index(i,j) ((i)*SIZE + (j))
...
struct args A;
unsigned SIZE;
printf("输入数组大小");
scanf("%u", &SIZE); // 此处应添加错误检查
A.array = malloc(SIZE*SIZE*sizeof(int)); // 为数组分配内存
...
A.array[index(2,3)] = 4;
printf("在(2,3)处的值=%d\n", A.array[index(2,3)]);
...
free(A.array); // 释放动态分配的内存
英文:
You can allocate the array dynamically and, optionally, define a macro or access function to access the elements using a 2-dimensional index. E.g.:
struct args
{
int number;
int *array;
};
#define index(i,j) ((i)*SIZE + (j))
...
struct args A;
unsigned SIZE;
printf("enter array size");
scanf("%u", &SIZE); // Should add error check here
A.array = malloc(SIZE*SIZE*sizeof(int)); // Allocate memory for the array
...
A.array[index(2,3)] = 4;
printf("Value at (2,3)=%d\n", A.array[index(2,3)]);
...
free(A.array); // Free the dynamically allocated memory
答案2
得分: 1
由于您需要在两个维度中使用运行时大小的二维数组,您将无法使用二维数组语法,例如 a[row][col]
。您将需要分配一个大小为 SIZE*SIZE 的“平面”数组,然后使用函数调用 GetAt(Row,Col) 和 SetAt(Row, Col, Value),并进行指针算术(简单地 index = (row * SIZE) + col;
),然后在您的平面数组中使用这个一维索引。
请记得释放动态分配的数组!
英文:
Since you require a runtime sized 2D array in both dimensions, you will not be able to utilize 2D array syntax, e.g. a[row][col]
. You will have to allocate a "flat" array SIZE*SIZE in size, then use a function call GetAt(Row,Col) and SetAt(Row, Col, Value) and do the pointer arithmetic (simply index = (row * SIZE) + col;
) then use that 1 dimensional index in your flat array.
Remember to free the dynamically allocated array!
答案3
得分: 1
如果您想能够动态分配数组并使用2D语法,您应该这样声明数组:
struct args
{
int number;
int **array;
};
然后,您可以分配数组的第一维:
struct args arr;
arr.array = malloc(SIZE * sizeof(int*));
接着分配第二维:
for (int i = 0; i < SIZE; i++) {
arr.array[i] = malloc(SIZE * sizeof(int));
}
以下是一个完整的工作示例:
struct args
{
int number;
int **array;
};
int main() {
struct args arr;
unsigned size;
printf("enter array size");
scanf("%u", &size);
arr.array = (int**)malloc(size * sizeof(int*));
for (int i = 0; i < size; i++) {
arr.array[i] = (int*)malloc(size * sizeof(int));
}
arr.array[2][3] = 4;
printf("Value at (2,3)=%d\n", arr.array[2][3]);
return 0;
}
英文:
If you want to be able to use the 2D syntax for your array dynamically allocated, you should declare your array like this :
struct args
{
int number;
int **array;
};
Then you allocate the first dimension of your array :
struct args arr;
arr.array = malloc(SIZE * sizeof(int*));
then the second dimension
for (int i = 0; i < SIZE; i++) {
arr.array[i] = malloc(SIZE * sizeof(int));
}
Here is a complete working example
struct args
{
int number;
int **array;
};
int main() {
struct args arr;
unsigned size;
printf("enter array size");
scanf("%u", &size);
arr.array = (int**)malloc(size * sizeof(int*));
for (int i = 0; i < size; i++) {
arr.array[i] = (int*)malloc(size * sizeof(int));
}
arr.array[2][3] = 4;
printf("Value at (2,3)=%d\n", arr.array[2][3]);
return 0;
}
答案4
得分: 1
你可以看到,在第一个例子中,数组的内容与结构体实例中的number
成员是连续存储的。在第二个例子中,数组的内容不存储在结构体实例本身中,而是存储在分配的内存块中,结构体实例中的array
成员存储了数组的首地址。在第三个例子中,数组的每一行都被单独分配了内存,结构体实例中的array
成员存储了指向这些行的指针数组的首地址。
使用哪种方法取决于你的需求,每种方法都有其优点和缺点。
英文:
Unfortunately, you cannot use variable-length arrays in a struct
definition; you're going to have to rely on dynamic memory allocation.
There are several ways to do this, but which you use depends on a few things.
<hr>
Does the array need to be part of the struct
instance, contiguous with number
?
+---+
| | number
+---+
| | array[0][0]
+---+
| | array[0][1]
+---+
...
+---+
| | array[0][C-1]
+---+
| | array[1][0]
+---+
| | array[1][1]
+---+
...
This would be the case if you ever needed to serialize the contents of the struct
instance (writing to a binary file, sending over a network, etc.). Of course, you'd need some way of saving the number of rows and columns as well.
AFAIK, the only way to do this is with a flexible array member; this will have to be a 1D array, onto which you can map a pointer to a c
-element array if you want to use 2D array subscripting. Quick and dirty example:
#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;
}
Here's some output with a 2 x 3 array:
$ ./flex 2 3
Item Address 00 01 02 03
---- ------- -- -- -- --
a 0x60000269d120 02 00 00 00 ....
0x60000269d124 00 00 00 00 ....
0x60000269d128 01 00 00 00 ....
0x60000269d12c 02 00 00 00 ....
0x60000269d130 03 00 00 00 ....
0x60000269d134 04 00 00 00 ....
0x60000269d138 05 00 00 00 ....
a->array 0x60000269d124 00 00 00 00 ....
0x60000269d128 01 00 00 00 ....
0x60000269d12c 02 00 00 00 ....
0x60000269d130 03 00 00 00 ....
0x60000269d134 04 00 00 00 ....
0x60000269d138 05 00 00 00 ....
map 0x60000269d124 00 00 00 00 ....
0x60000269d128 01 00 00 00 ....
0x60000269d12c 02 00 00 00 ....
0x60000269d130 03 00 00 00 ....
0x60000269d134 04 00 00 00 ....
0x60000269d138 05 00 00 00 ....
a->number = 2
a->array[0][0] = 0
a->array[0][1] = 1
a->array[0][2] = 2
a->array[1][0] = 3
a->array[1][1] = 4
a->array[1][2] = 5
You can see the array contents are contiguous with the number
member in the struct instance.
You don't have to use the map
pointer if you don't want to - you can compute the index as
a->array[c * i + j] = ...;
I just think it's easier and more clear to use 2D subscripting.
<hr>
Can the array exist in memory that's not contiguous with the struct
instance, but the array itself still needs to be contiguous?
+---+
| | number
+---+ +---+
| | array -------> | | array[0][0]
+---+ +---+
| | array[0][1]
+---+
...
+---+
| | array[0][C-1]
+---+
| | array[1][0]
+---+
| | array[1][1]
+---+
In this case, the definition of the struct
would be
struct args {
int number;
int *array; // points to an array instance
};
We still treat the array
member as a 1D array:
struct args s;
s.array = malloc( sizeof (int [c]) * r );
And like the example above, we can create a pointer to a c
-element array to allow us to use 2D array subscripting:
int (*map)[c] = ( int (*)[c] ) s.array;
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
map[i][j] = c * i + j;
or again you can just use
a.array[c * i + j] = c * i + j;
Complete example:
#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 );
/**
* Create an automatic struct instance
*/
struct args a;
a.number = r;
/**
* Allocate space for array; we want enough space
* to hold r instances of c-element arrays.
*/
a.array = malloc( sizeof (int [c]) * r );
if ( a.array )
{
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;
char *names[] = { "a", "a.array", "map" };
void *addrs[] = { &a, a.array, map };
size_t sizes[] = { sizeof a, sizeof *map * r, sizeof *map * r };
dumper( names, addrs, sizes, 3, stdout );
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.array );
}
return 0;
}
with output:
$ ./flex2 3 4
Item Address 00 01 02 03
---- ------- -- -- -- --
a 0x16b2e37c0 03 00 00 00 ....
0x16b2e37c4 01 00 00 00 ....
0x16b2e37c8 40 c2 d3 01 @...
0x16b2e37cc 00 60 00 00 .`..
a.array 0x600001d3c240 00 00 00 00 ....
0x600001d3c244 01 00 00 00 ....
0x600001d3c248 02 00 00 00 ....
0x600001d3c24c 03 00 00 00 ....
0x600001d3c250 04 00 00 00 ....
0x600001d3c254 05 00 00 00 ....
0x600001d3c258 06 00 00 00 ....
0x600001d3c25c 07 00 00 00 ....
0x600001d3c260 08 00 00 00 ....
0x600001d3c264 09 00 00 00 ....
0x600001d3c268 0a 00 00 00 ....
0x600001d3c26c 0b 00 00 00 ....
map 0x600001d3c240 00 00 00 00 ....
0x600001d3c244 01 00 00 00 ....
0x600001d3c248 02 00 00 00 ....
0x600001d3c24c 03 00 00 00 ....
0x600001d3c250 04 00 00 00 ....
0x600001d3c254 05 00 00 00 ....
0x600001d3c258 06 00 00 00 ....
0x600001d3c25c 07 00 00 00 ....
0x600001d3c260 08 00 00 00 ....
0x600001d3c264 09 00 00 00 ....
0x600001d3c268 0a 00 00 00 ....
0x600001d3c26c 0b 00 00 00 ....
a.number = 3
a.array[0][0] = 0
a.array[0][1] = 1
a.array[0][2] = 2
a.array[0][3] = 3
a.array[1][0] = 4
a.array[1][1] = 5
a.array[1][2] = 6
a.array[1][3] = 7
a.array[2][0] = 8
a.array[2][1] = 9
a.array[2][2] = 10
a.array[2][3] = 11
As you can see, the contents of the array are not stored in the struct
instance itself - instead, we store the address of the first element of the array in the array
member (0x600001d3c240
). Note that there are four bytes of padding between number
and array
.
<hr>
If you don't need the array to be contiguous you can allocate the rows individually, such as:
+---+
| | number
+---+ +---+ +---+
| | array ------> | | array[0] ------> | | array[0][0]
+---+ +---+ +---+
| | array[1] ----+ | | array[0][1]
+---+ | +---+
... | ...
|
| +---+
+-> | | array[1][0]
+---+
| | array[1][1]
+---+
...
In that case, your struct
definition would be
struct args {
int number;
int **array;
};
and you'd use a two-step allocation method:
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;
The advantage of this method is you can use regular 2D array subscripting on a.array
; you don't need to map a pointer to an array onto it.
Complete example:
#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 );
/**
* Create an automatic struct instance
*/
struct args a;
a.number = r;
/**
* Allocate space for r pointers to int
*/
a.array = malloc( sizeof *a.array * r );
if ( a.array )
{
/**
* 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;
char *names[] = { "a", "a.array", "a.array[0]", "a.array[1]" };
void *addrs[] = { &a, a.array, a.array[0], a.array[1] };
size_t sizes[] = { sizeof a, sizeof a.array[0] * r, sizeof a.array[0][0] * c, sizeof a.array[0][0] * c };
dumper( names, addrs, sizes, 4, stdout );
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, a.array[i][j] );
for ( size_t i = 0; i < r; i++ )
free( a.array[i] );
free( a.array );
}
return 0;
}
with output:
$ ./flex3 3 4
Item Address 00 01 02 03
---- ------- -- -- -- --
a 0x16fc177a0 03 00 00 00 ....
0x16fc177a4 00 00 00 00 ....
0x16fc177a8 20 91 97 03 ....
0x16fc177ac 00 60 00 00 .`..
a.array 0x600003979120 20 c0 b7 03 ....
0x600003979124 00 60 00 00 .`..
0x600003979128 30 c0 b7 03 0...
0x60000397912c 00 60 00 00 .`..
0x600003979130 40 c0 b7 03 @...
0x600003979134 00 60 00 00 .`..
a.array[0] 0x600003b7c020 00 00 00 00 ....
0x600003b7c024 01 00 00 00 ....
0x600003b7c028 02 00 00 00 ....
0x600003b7c02c 03 00 00 00 ....
a.array[1] 0x600003b7c030 04 00 00 00 ....
0x600003b7c034 05 00 00 00 ....
0x600003b7c038 06 00 00 00 ....
0x600003b7c03c 07 00 00 00 ....
a.number = 3
a.array[0][0] = 0
a.array[0][1] = 1
a.array[0][2] = 2
a.array[0][3] = 3
a.array[1][0] = 4
a.array[1][1] = 5
a.array[1][2] = 6
a.array[1][3] = 7
a.array[2][0] = 8
a.array[2][1] = 9
a.array[2][2] = 10
a.array[2][3] = 11
In this case, a.array
stores the address of the first element of the array of pointers (0x600003979120
), and each a.array[i]
stores the address of a 4-element array of int
.
<hr>
Which method you use depends on your needs. All have their strengths and weaknesses.
答案5
得分: 0
以下是您要翻译的内容:
如果您的编译器支持可变长度数组(VLA),您可以尝试以下选项:
#include <stdio.h>
struct args
{
int number;
int *array;
};
void dumpStruct(struct args *toDump)
{
for (int i = 0; i < toDump->number; ++i) {
printf("%d\n", toDump->array[i]);
}
}
int main(int argc, char *argv[])
{
int SIZE;
printf("Enter array size: ");
scanf("%d", &SIZE);
int varArray[SIZE][SIZE];
struct args varArrayStruct = {
.number = SIZE,
.array = (int*) varArray
};
for (int i = 0; i < varArrayStruct.number; ++i) {
varArrayStruct.array[i] = i + 1;
}
dumpStruct(&varArrayStruct);
}
在这里,您的数组分配在堆栈上(因此请注意其大小),并在程序退出时自动释放。因此,您无需管理堆。
缺点是您必须手动计算从给定列和行中的项的线性索引。在C中,不可能声明不完整的二维数组,以便可以使用*[i][j]*表示法引用其元素。
英文:
If your compiler supports the variable length arrays (VLA), you may try the following option:
#include <stdio.h>
struct args
{
int number;
int *array;
};
void dumpStruct(struct args *toDump)
{
for (int i = 0; i < toDump->number; ++i) {
printf("%d\n", toDump->array[i]);
}
}
int main(int argc, char *argv[])
{
int SIZE;
printf("Enter array size: ");
scanf("%d", &SIZE);
int varArray[SIZE][SIZE];
struct args varArrayStruct = {
.number = SIZE,
.array = (int*) varArray
};
for (int i = 0; i < varArrayStruct.number; ++i) {
varArrayStruct.array[i] = i + 1;
}
dumpStruct(&varArrayStruct);
}
Here your array is allocated on stack (so keep your eye on its size) and freed automatically upon your program exits. So you don't need to manage the heap.
The disadvantage is that you have to manually calculate the linear index of an item from the given column and row. It is impossible in C to declare an incomplete two-dimensional array so its elements could be referenced using the [i][j] notation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论