这是我的代码版本。 int **map 值是用户和库用于访问数据的值。 Matrix 结构封装了有关数组的所有信息,包括用于初始化map 的成员。代码设置大小,分配和初始化结构,然后初始化数组,然后像用户和库一样使用它。最后,分配的内存被释放。
在实践中,您可能希望将其拆分为多个单独的函数。
来源: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;
}
示例输出
当在带有 GCC 4.9.1 的 Mac OS X 10.9.5 上在 valgrind 3.10.0 下运行时,我得到以下输出。 "stderr.h" 标头在$HOME/inc 中并声明err_syserr(),而libjl.a 在$HOME/lib/64 中并提供err_syserr() 的实现,该函数报告给定错误消息和由errno 标识的错误并退出。这次我懒得在这个程序中写代码了。 (在 SO 中搜索 '[c] user:15168 err_syserr' 以找到 Protect a shared memory segment with semaphore does not work,它具有基本等效的代码。我没有在此答案的代码中调用 err_setarg0()。)
$ 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)
$
“仍然可达”块是stdout 的缓冲区;如果我在从main() 返回之前包含fclose(stdout);,它就会消失。 Mac OS X 运行时库也分配了大量内存,但在隐藏信息中会识别出这种使用情况。
评论和回复
正如您在 2 行中看到的那样,我进行了整个初始化。但问题不在于初始化;问题是在每一帧中,地图的值都会改变。所以我只需要一个直接指向“边界图”的“地图”。 map[0][0] 是 boundaries_map[20][20] 等等。我试图声明全局**map,然后将我的第二行写入主行,但我收到有关演员表的错误。 (*map)[dim_x+40] 这是**map 不是吗?
我不确定我是否完全理解您的需求,这是此回复需要很长时间的原因之一。
您不能拥有属于 VLA 的全局变量;它们只能在函数中分配,可以作为局部变量在堆栈上分配,也可以通过malloc() 等在堆上分配。我展示的原始代码允许您通过一个全局变量定义一个数组,一个双指针,可以从任何可以读取双指针的代码访问。
下面的代码可以看作是构建 VLA 的练习。它使用malloc() 创建一个VLA,在指向VLA 的指针中记录它的创建位置。这可以传递给函数,就像可以传递基于堆栈的 VLA 一样。代码在 Mac OS X 10.9.5 上的 GCC 4.9.1 下编译干净:
$ gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror \
> 2dv.c -o 2dv
根据valgrind,它运行干净且无泄漏。
来源: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');
}
}
注意使用*vla 和*vla_2 将VLA 传递给函数。由于vla 和vla_2 变量是指向VLA 的指针,所以*vla 是函数期望的VLA。
输出:
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