问题
I have an array of array with negative index. It is an array which has real dimensions [dim_y + 40][dim_x + 40] but the user uses the array like it has dimensions [dim_y][dim_x]. First i had global and already defined the dimensions dim_x, dim_y, so i had this
int map_boundaries[dim_y + 40][dim_x + 40];
int (*map)[dim_x+40] = (int(*)[dim_x+40])&map_boundaries[20][20];
It worked fine. Now i need the dimensions dim_y and dim_x to be variable, and with this i mean that i want the array 'map' to not have fixed size but dynamic, i need to read the dim_y, dim_x from a user and the array 'map' to be global, so i have
int **map_boundaries;
and i use calloc
in main()
map_boundaries = (int **)calloc(dim_y + 40,sizeof(int*));
for(i = 0; i < dim_y + 40; i++){
map_boundaries[i] = (int *)calloc(dim_x + 40,sizeof(int));
}
, but i don't know how to declare the second line
For better understanding of the boundaries thing i did what is posted in the 2nd comment here: http://everything2.com/title/Negative+array+indexing
回答1:
I would allocate a single array:
int* storage = calloc((dim_x + 40) * (dim_y + 40), sizeof(int));
Then I'd return it to the user in an opaque struct like this:
struct map {
int* storage;
size_t dim_x;
size_t dim_y;
};
Then I would define an indexing function for the user:
int* get_cell(struct map* m, x, y) {
return &m->storage[(x + 20) + (m->dim_x + 40) * (y + 20)];
}
And perhaps to get an entire row if the user wants to read/write multiple elements in one row:
int* get_row(struct map* m, y) {
return get_cell(m, 0, y);
}
size_t get_row_size(struct map* m) {
return m->dim_x;
}
Since you want the dimensions to be determined at runtime, you will need to do runtime index calculations in any case.
回答2:
Here's my version of the code. The int **map
value is what both user and library use to access the data. The Matrix
structure encapsulates all the information about the array, including a member that is use to initialize map
. The code sets up the sizes, allocates and initializes the structure, then initializes the array, then uses it as a user would, and as the library would. Finally, the allocated memory is freed.
In practice, you'd probably want to split this up into a number of separate functions.
Source: 2da.c
:
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "stderr.h"
typedef struct Matrix
{
int *map_base;
int **map_rows;
int x_dim;
int y_dim;
int extra;
int **map;
} Matrix;
int main(void)
{
Matrix m;
int x_dim = 8;
int y_dim = 6;
int extra = 5;
/* Allocation */
m.extra = extra;
m.x_dim = x_dim;
m.y_dim = y_dim;
int x_cells = x_dim + 2 * extra;
int y_cells = y_dim + 2 * extra;
m.map_base = calloc(x_cells * y_cells, sizeof(**m.map));
if (m.map_base == 0)
err_syserr("Failed to allocate %zu bytes memory\n",
x_cells * y_cells * sizeof(**m.map));
m.map_rows = calloc(x_cells, sizeof(*m.map));
if (m.map_rows == 0)
err_syserr("Failed to allocate %zu bytes memory\n",
x_cells * sizeof(*m.map));
//printf("Map base: 0x%.8" PRIXPTR "\n", (uintptr_t)m.map_base);
//printf("Map rows: 0x%.8" PRIXPTR "\n", (uintptr_t)m.map_rows);
for (int i = 0; i < x_cells; i++)
{
m.map_rows[i] = &m.map_base[i * y_cells + extra];
//printf("Row[%2d] 0x%.8" PRIXPTR "\n", i, (uintptr_t)m.map_rows[i]);
}
m.map = &m.map_rows[extra];
int **map = m.map;
//printf("Map: 0x%.8" PRIXPTR "\n", (uintptr_t)map);
/* Initialization */
int x_min = -extra;
int y_min = -extra;
int x_max = x_dim + extra;
int y_max = y_dim + extra;
printf("Initialization:\n");
for (int i = x_min; i < x_max; i++)
{
for (int j = y_min; j < y_max; j++)
{
map[i][j] = i * 100 + j;
//printf("[%2d,%2d] = %4d\n", i, j, map[i][j]);
}
}
printf("User view:\n");
for (int i = 0; i < x_dim; i++)
{
for (int j = 0; j < y_dim; j++)
printf("[%2d,%2d] = %4d\n", i, j, map[i][j]);
}
printf("Library view:\n");
for (int i = x_min; i < x_max; i++)
{
for (int j = y_min; j < y_max; j++)
printf("[%2d,%2d] = %4d\n", i, j, map[i][j]);
}
/* Deallocation */
free(m.map_base);
free(m.map_rows);
return 0;
}
Example output
When run under valgrind 3.10.0 on Mac OS X 10.9.5 with GCC 4.9.1, I got the following output. The "stderr.h"
header is in $HOME/inc
and declares err_syserr()
, while libjl.a
is in $HOME/lib/64
and provides the implementation for err_syserr()
, a function that reports the given error message and the error identified by errno
and exits. I'm too lazy to write the code in this program this time around. (Search for '[c] user:15168 err_syserr' in SO to find Protect a shared memory segment with semaphore does not work, which has essentially equivalent code. I didn't call err_setarg0()
in the code in this answer.)
$ gcc -O3 -g -I/Users/jleffler/inc -std=c11 -Wall -Wextra -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition -Werror 2da.c -o 2da \
> -L/Users/jleffler/lib/64 -ljl
$ valgrind ./2da
==26293== Memcheck, a memory error detector
==26293== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26293== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==26293== Command: 2da
==26293==
Initialization:
User view:
[ 0, 0] = 0
[ 0, 1] = 1
[ 0, 2] = 2
[ 0, 3] = 3
[ 0, 4] = 4
[ 0, 5] = 5
[ 1, 0] = 100
[ 1, 1] = 101
[ 1, 2] = 102
[ 1, 3] = 103
[ 1, 4] = 104
[ 1, 5] = 105
[ 2, 0] = 200
[ 2, 1] = 201
[ 2, 2] = 202
[ 2, 3] = 203
[ 2, 4] = 204
[ 2, 5] = 205
[ 3, 0] = 300
[ 3, 1] = 301
[ 3, 2] = 302
[ 3, 3] = 303
[ 3, 4] = 304
[ 3, 5] = 305
[ 4, 0] = 400
[ 4, 1] = 401
[ 4, 2] = 402
[ 4, 3] = 403
[ 4, 4] = 404
[ 4, 5] = 405
[ 5, 0] = 500
[ 5, 1] = 501
[ 5, 2] = 502
[ 5, 3] = 503
[ 5, 4] = 504
[ 5, 5] = 505
[ 6, 0] = 600
[ 6, 1] = 601
[ 6, 2] = 602
[ 6, 3] = 603
[ 6, 4] = 604
[ 6, 5] = 605
[ 7, 0] = 700
[ 7, 1] = 701
[ 7, 2] = 702
[ 7, 3] = 703
[ 7, 4] = 704
[ 7, 5] = 705
Library view:
[-5,-5] = -505
[-5,-4] = -504
[-5,-3] = -503
[-5,-2] = -502
[-5,-1] = -501
[-5, 0] = -500
[-5, 1] = -499
[-5, 2] = -498
[-5, 3] = -497
[-5, 4] = -496
[-5, 5] = -495
[-5, 6] = -494
[-5, 7] = -493
[-5, 8] = -492
[-5, 9] = -491
[-5,10] = -490
[-4,-5] = -405
[-4,-4] = -404
[-4,-3] = -403
[-4,-2] = -402
[-4,-1] = -401
[-4, 0] = -400
[-4, 1] = -399
[-4, 2] = -398
[-4, 3] = -397
[-4, 4] = -396
[-4, 5] = -395
[-4, 6] = -394
[-4, 7] = -393
[-4, 8] = -392
[-4, 9] = -391
[-4,10] = -390
[-3,-5] = -305
[-3,-4] = -304
[-3,-3] = -303
[-3,-2] = -302
[-3,-1] = -301
[-3, 0] = -300
[-3, 1] = -299
[-3, 2] = -298
[-3, 3] = -297
[-3, 4] = -296
[-3, 5] = -295
[-3, 6] = -294
[-3, 7] = -293
[-3, 8] = -292
[-3, 9] = -291
[-3,10] = -290
[-2,-5] = -205
[-2,-4] = -204
[-2,-3] = -203
[-2,-2] = -202
[-2,-1] = -201
[-2, 0] = -200
[-2, 1] = -199
[-2, 2] = -198
[-2, 3] = -197
[-2, 4] = -196
[-2, 5] = -195
[-2, 6] = -194
[-2, 7] = -193
[-2, 8] = -192
[-2, 9] = -191
[-2,10] = -190
[-1,-5] = -105
[-1,-4] = -104
[-1,-3] = -103
[-1,-2] = -102
[-1,-1] = -101
[-1, 0] = -100
[-1, 1] = -99
[-1, 2] = -98
[-1, 3] = -97
[-1, 4] = -96
[-1, 5] = -95
[-1, 6] = -94
[-1, 7] = -93
[-1, 8] = -92
[-1, 9] = -91
[-1,10] = -90
[ 0,-5] = -5
[ 0,-4] = -4
[ 0,-3] = -3
[ 0,-2] = -2
[ 0,-1] = -1
[ 0, 0] = 0
[ 0, 1] = 1
[ 0, 2] = 2
[ 0, 3] = 3
[ 0, 4] = 4
[ 0, 5] = 5
[ 0, 6] = 6
[ 0, 7] = 7
[ 0, 8] = 8
[ 0, 9] = 9
[ 0,10] = 10
[ 1,-5] = 95
[ 1,-4] = 96
[ 1,-3] = 97
[ 1,-2] = 98
[ 1,-1] = 99
[ 1, 0] = 100
[ 1, 1] = 101
[ 1, 2] = 102
[ 1, 3] = 103
[ 1, 4] = 104
[ 1, 5] = 105
[ 1, 6] = 106
[ 1, 7] = 107
[ 1, 8] = 108
[ 1, 9] = 109
[ 1,10] = 110
[ 2,-5] = 195
[ 2,-4] = 196
[ 2,-3] = 197
[ 2,-2] = 198
[ 2,-1] = 199
[ 2, 0] = 200
[ 2, 1] = 201
[ 2, 2] = 202
[ 2, 3] = 203
[ 2, 4] = 204
[ 2, 5] = 205
[ 2, 6] = 206
[ 2, 7] = 207
[ 2, 8] = 208
[ 2, 9] = 209
[ 2,10] = 210
[ 3,-5] = 295
[ 3,-4] = 296
[ 3,-3] = 297
[ 3,-2] = 298
[ 3,-1] = 299
[ 3, 0] = 300
[ 3, 1] = 301
[ 3, 2] = 302
[ 3, 3] = 303
[ 3, 4] = 304
[ 3, 5] = 305
[ 3, 6] = 306
[ 3, 7] = 307
[ 3, 8] = 308
[ 3, 9] = 309
[ 3,10] = 310
[ 4,-5] = 395
[ 4,-4] = 396
[ 4,-3] = 397
[ 4,-2] = 398
[ 4,-1] = 399
[ 4, 0] = 400
[ 4, 1] = 401
[ 4, 2] = 402
[ 4, 3] = 403
[ 4, 4] = 404
[ 4, 5] = 405
[ 4, 6] = 406
[ 4, 7] = 407
[ 4, 8] = 408
[ 4, 9] = 409
[ 4,10] = 410
[ 5,-5] = 495
[ 5,-4] = 496
[ 5,-3] = 497
[ 5,-2] = 498
[ 5,-1] = 499
[ 5, 0] = 500
[ 5, 1] = 501
[ 5, 2] = 502
[ 5, 3] = 503
[ 5, 4] = 504
[ 5, 5] = 505
[ 5, 6] = 506
[ 5, 7] = 507
[ 5, 8] = 508
[ 5, 9] = 509
[ 5,10] = 510
[ 6,-5] = 595
[ 6,-4] = 596
[ 6,-3] = 597
[ 6,-2] = 598
[ 6,-1] = 599
[ 6, 0] = 600
[ 6, 1] = 601
[ 6, 2] = 602
[ 6, 3] = 603
[ 6, 4] = 604
[ 6, 5] = 605
[ 6, 6] = 606
[ 6, 7] = 607
[ 6, 8] = 608
[ 6, 9] = 609
[ 6,10] = 610
[ 7,-5] = 695
[ 7,-4] = 696
[ 7,-3] = 697
[ 7,-2] = 698
[ 7,-1] = 699
[ 7, 0] = 700
[ 7, 1] = 701
[ 7, 2] = 702
[ 7, 3] = 703
[ 7, 4] = 704
[ 7, 5] = 705
[ 7, 6] = 706
[ 7, 7] = 707
[ 7, 8] = 708
[ 7, 9] = 709
[ 7,10] = 710
[ 8,-5] = 795
[ 8,-4] = 796
[ 8,-3] = 797
[ 8,-2] = 798
[ 8,-1] = 799
[ 8, 0] = 800
[ 8, 1] = 801
[ 8, 2] = 802
[ 8, 3] = 803
[ 8, 4] = 804
[ 8, 5] = 805
[ 8, 6] = 806
[ 8, 7] = 807
[ 8, 8] = 808
[ 8, 9] = 809
[ 8,10] = 810
[ 9,-5] = 895
[ 9,-4] = 896
[ 9,-3] = 897
[ 9,-2] = 898
[ 9,-1] = 899
[ 9, 0] = 900
[ 9, 1] = 901
[ 9, 2] = 902
[ 9, 3] = 903
[ 9, 4] = 904
[ 9, 5] = 905
[ 9, 6] = 906
[ 9, 7] = 907
[ 9, 8] = 908
[ 9, 9] = 909
[ 9,10] = 910
[10,-5] = 995
[10,-4] = 996
[10,-3] = 997
[10,-2] = 998
[10,-1] = 999
[10, 0] = 1000
[10, 1] = 1001
[10, 2] = 1002
[10, 3] = 1003
[10, 4] = 1004
[10, 5] = 1005
[10, 6] = 1006
[10, 7] = 1007
[10, 8] = 1008
[10, 9] = 1009
[10,10] = 1010
[11,-5] = 1095
[11,-4] = 1096
[11,-3] = 1097
[11,-2] = 1098
[11,-1] = 1099
[11, 0] = 1100
[11, 1] = 1101
[11, 2] = 1102
[11, 3] = 1103
[11, 4] = 1104
[11, 5] = 1105
[11, 6] = 1106
[11, 7] = 1107
[11, 8] = 1108
[11, 9] = 1109
[11,10] = 1110
[12,-5] = 1195
[12,-4] = 1196
[12,-3] = 1197
[12,-2] = 1198
[12,-1] = 1199
[12, 0] = 1200
[12, 1] = 1201
[12, 2] = 1202
[12, 3] = 1203
[12, 4] = 1204
[12, 5] = 1205
[12, 6] = 1206
[12, 7] = 1207
[12, 8] = 1208
[12, 9] = 1209
[12,10] = 1210
==26293==
==26293== HEAP SUMMARY:
==26293== in use at exit: 29,341 bytes in 374 blocks
==26293== total heap usage: 452 allocs, 78 frees, 36,581 bytes allocated
==26293==
==26293== LEAK SUMMARY:
==26293== definitely lost: 0 bytes in 0 blocks
==26293== indirectly lost: 0 bytes in 0 blocks
==26293== possibly lost: 0 bytes in 0 blocks
==26293== still reachable: 4,096 bytes in 1 blocks
==26293== suppressed: 25,245 bytes in 373 blocks
==26293== Rerun with --leak-check=full to see details of leaked memory
==26293==
==26293== For counts of detected and suppressed errors, rerun with: -v
==26293== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$
The 'still reachable' block is the buffer for stdout
; if I included fclose(stdout);
before returning from main()
, it would go. The Mac OS X runtime library allocates a lot of memory too, but that usage is identified in the suppressed information.
Comment and response
I do the whole initiallization as you see in 2 lines. But it is not the initialization that's the problem; the problem is that in every frame the values of map are changed. So I need just a 'map' which points directly to 'boundaries map'.
map[0][0]
isboundaries_map[20][20]
and so on. I tried to declare global**map
and then write my second line into the main but I get an error about cast.(*map)[dim_x+40]
this is a**map
isn't it?
I'm not sure I completely understand what you're after, which is one reason this response has taken a long time.
You cannot have global variables that are VLAs; they can only be allocated in functions, either on the stack as local variables or on the heap via malloc()
et al. The original code I showed allows you to define an array via a global variable, a double pointer, that can be accessed from any code that can read the double pointer.
The code below could be considered an exercise in constructing VLAs. It uses malloc()
to create a VLA, recording where it was created in a pointer to a VLA. This can be passed to a function just like a stack-based VLA can be passed. The code compiles cleanly under GCC 4.9.1 on Mac OS X 10.9.5:
$ gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror \
> 2dv.c -o 2dv
It runs cleanly and leak-free according to valgrind.
Source: 2dv.c
:
#include <stdio.h>
#include <stdlib.h>
static void dump_vla_1(int x_size, int y_size, int vla[x_size][y_size]);
static void dump_vla_2(int x_min, int y_min, int x_size, int y_size,
int vla[x_size][y_size]);
static void dump_vla_3(int x_min, int x_max, int y_min, int y_max,
int x_size, int y_size, int vla[x_size][y_size]);
int main(void)
{
int extra = 3;
int x_base = 5;
int y_base = 4;
int x_size = x_base + 2 * extra;
int y_size = y_base + 2 * extra;
int (*vla)[x_size][y_size] = calloc(x_size * y_size, sizeof(int));
for (int i = 0; i < x_size; i++)
for (int j = 0; j < y_size; j++)
(*vla)[i][j] = (i + 1) * 100 + (j + 1);
for (int i = 0; i < x_size; i++)
{
for (int j = 0; j < y_size; j++)
printf(" %4d", (*vla)[i][j]);
putchar('\n');
}
dump_vla_1(x_size, y_size, *vla);
dump_vla_2(0, 0, x_size, y_size, *vla);
/* Harsh cast! */
int (*vla_2)[x_size][y_size] = (int (*)[x_size][y_size])&(*vla)[extra][extra];
dump_vla_2(-extra, -extra, x_size, y_size, *vla_2);
dump_vla_3(-extra, x_size - extra, -extra, y_size - extra, x_size, y_size, *vla_2);
dump_vla_3(0, x_base, 0, y_base, x_size, y_size, *vla_2);
free(vla);
return 0;
}
static void dump_vla_1(int x_size, int y_size, int vla[x_size][y_size])
{
printf("Matrix %dx%d\n", x_size, y_size);
for (int i = 0; i < x_size; i++)
{
for (int j = 0; j < y_size; j++)
printf(" %4d", vla[i][j]);
putchar('\n');
}
}
static void dump_vla_2(int x_min, int y_min, int x_size, int y_size,
int vla[x_size][y_size])
{
printf("Matrix %dx%d (%d..%d, %d..%d)\n",
x_size, y_size, x_min, x_min + x_size - 1, y_min, y_min + y_size - 1);
for (int i = x_min; i < x_min + x_size; i++)
{
for (int j = y_min; j < y_min + y_size; j++)
printf(" %4d", vla[i][j]);
putchar('\n');
}
}
static void dump_vla_3(int x_min, int x_max, int y_min, int y_max,
int x_size, int y_size, int vla[x_size][y_size])
{
printf("Matrix %dx%d (%d..%d, %d..%d)\n",
x_size, y_size, x_min, x_max, y_min, y_max);
for (int i = x_min; i < x_max; i++)
{
for (int j = y_min; j < y_max; j++)
printf(" %4d", vla[i][j]);
putchar('\n');
}
}
Note the use of *vla
and *vla_2
to pass the VLA to the functions. Since the vla
and vla_2
variables are pointers to a VLA, *vla
is the VLA which the functions expect.
Output:
101 102 103 104 105 106 107 108 109 110
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
601 602 603 604 605 606 607 608 609 610
701 702 703 704 705 706 707 708 709 710
801 802 803 804 805 806 807 808 809 810
901 902 903 904 905 906 907 908 909 910
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
Matrix 11x10
101 102 103 104 105 106 107 108 109 110
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
601 602 603 604 605 606 607 608 609 610
701 702 703 704 705 706 707 708 709 710
801 802 803 804 805 806 807 808 809 810
901 902 903 904 905 906 907 908 909 910
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
Matrix 11x10 (0..10, 0..9)
101 102 103 104 105 106 107 108 109 110
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
601 602 603 604 605 606 607 608 609 610
701 702 703 704 705 706 707 708 709 710
801 802 803 804 805 806 807 808 809 810
901 902 903 904 905 906 907 908 909 910
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
Matrix 11x10 (-3..7, -3..6)
101 102 103 104 105 106 107 108 109 110
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
601 602 603 604 605 606 607 608 609 610
701 702 703 704 705 706 707 708 709 710
801 802 803 804 805 806 807 808 809 810
901 902 903 904 905 906 907 908 909 910
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
Matrix 11x10 (-3..8, -3..7)
101 102 103 104 105 106 107 108 109 110
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
601 602 603 604 605 606 607 608 609 610
701 702 703 704 705 706 707 708 709 710
801 802 803 804 805 806 807 808 809 810
901 902 903 904 905 906 907 908 909 910
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
Matrix 11x10 (0..5, 0..4)
404 405 406 407
504 505 506 507
604 605 606 607
704 705 706 707
804 805 806 807
来源:https://stackoverflow.com/questions/26350717/calloc-for-an-array-of-array-with-negative-index-in-c