Вот моя версия кода. Значение 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;
}
Пример вывода
При запуске под valgrind
3.10.0 в Mac OS X 10.9.5 с GCC 4.9.1 я получил следующий вывод . Заголовок "stderr.h"
находится в $HOME/inc
и объявляет err_syserr()
, а libjl.a
находится в $HOME/lib/64
и обеспечивает реализацию для err_syserr()
, функции, которая сообщает данное сообщение об ошибке и ошибку, идентифицированную errno
, и завершает работу. На этот раз мне лень писать код в этой программе. (Выполните поиск «[c] user: 15168 err_syserr» в SO, чтобы найти Защита сегмента общей памяти с помощью семафора не работает, код которого по существу эквивалентен. В этом ответе я не вызывал 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
; если бы я включил fclose(stdout);
перед возвратом из main()
, он пошел бы. Библиотека времени выполнения Mac OS X также выделяет много памяти, но это использование указано в скрытой информации.
Комментарий и ответ
Я делаю всю инициализацию, как вы видите, в 2 строки. Но проблема не в инициализации; проблема в том, что в каждом кадре значения карты меняются. Поэтому мне нужна просто «карта», которая указывает прямо на «карту границ». map[0][0]
это boundaries_map[20][20]
и так далее. Я попытался объявить глобальный **map
, а затем записать свою вторую строку в основную, но получаю ошибку о приведении. (*map)[dim_x+40]
это **map
не так ли?
Я не уверен, что полностью понимаю, что вам нужно, и это одна из причин, по которой этот ответ занял много времени.
Вы не можете иметь глобальные переменные, которые являются VLA; они могут быть размещены только в функциях, либо в стеке как локальные переменные, либо в куче через malloc()
и др. Исходный код, который я показал, позволяет вам определить массив через глобальную переменную, двойной указатель, доступ к которому можно получить из любого кода, который может прочитать двойной указатель.
Приведенный ниже код можно рассматривать как упражнение по созданию VLA. Он использует malloc()
для создания VLA, записывая место его создания в указатель на VLA. Это можно передать функции так же, как можно передать VLA на основе стека. Код корректно компилируется в GCC 4.9.1 на Mac OS X 10.9.5:
$ 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
person
Jonathan Leffler
schedule
14.10.2014
map_boundaries[0]
будет указывать на массив, который может быть другим измерением, чемmap_boundaries[1]
и т. д. Если это не то, что вы имели в виду, возможно, уточните свой вопрос (и включите строкуcalloc
, которую вы, кажется, оставили вышел без особых причин). - person WhozCraig   schedule 14.10.2014dim_x
должна иметь возможность варьироваться для каждой строки? Это имеет значение. Теперь вы используете объявления VLA, которые подходят для любых данныхdim_x
иdim_y
, которые помещаются в допустимое пространство вашей автоматической переменной, но не будут работать, если вы хотите, скажем, первое чтобы в строке было 3 элемента, во второй — 5 и т. д. Это то, что вам нужно? - person WhozCraig   schedule 14.10.2014map[x][y]
сx
в диапазоне-20 .. x_dim+20
и сy
в диапазоне-20 .. y_dim + 20
. Это правильно? И вам нужно, чтобыx_dim
иy_dim
можно было выбирать во время выполнения, а не константы времени компиляции, а смещения (-20, +20) фиксируются во время компиляции. - person Jonathan Leffler   schedule 14.10.2014