回答編集履歴
3
バグの修正とassertの追加
answer
CHANGED
@@ -96,6 +96,7 @@
|
|
96
96
|
という制限があったのですね。struct data_allの構造を変えずにするとなると、普通に構造体や配列としてアクセスする方法では無理です。メモリを自分で確保して、直接計算してアクセスするしかないと思います。ということで、書き直しました。
|
97
97
|
|
98
98
|
```C
|
99
|
+
#include <assert.h>
|
99
100
|
#include <stdio.h>
|
100
101
|
#include <stdlib.h>
|
101
102
|
|
@@ -111,16 +112,18 @@
|
|
111
112
|
|
112
113
|
struct data_all {
|
113
114
|
int size;
|
114
|
-
|
115
|
+
size_t mem_size;
|
115
116
|
void *mem;
|
116
117
|
};
|
117
118
|
|
118
119
|
struct data_all data_all_create(int size)
|
119
120
|
{
|
121
|
+
assert(0 <= size);
|
120
122
|
struct data_all dd;
|
121
123
|
dd.size = size;
|
122
124
|
dd.mem_size = sizeof(struct head) + sizeof(struct data) * size +
|
123
|
-
|
125
|
+
sizeof(int) * 3 * 4 * size;
|
126
|
+
assert(0 <= dd.mem_size);
|
124
127
|
dd.mem = calloc(1, dd.mem_size);
|
125
128
|
return dd;
|
126
129
|
}
|
@@ -132,18 +135,27 @@
|
|
132
135
|
|
133
136
|
struct head *data_all_head(struct data_all dd)
|
134
137
|
{
|
138
|
+
assert(dd.mem != NULL);
|
135
139
|
return (struct head *)dd.mem;
|
136
140
|
}
|
137
141
|
struct data *data_all_data(struct data_all dd, int n)
|
138
142
|
{
|
143
|
+
assert(dd.mem != NULL);
|
144
|
+
assert(0 <= n && n < dd.size);
|
139
145
|
return (struct data *)(dd.mem + sizeof(struct head) +
|
140
|
-
|
146
|
+
sizeof(struct data) * n);
|
141
147
|
}
|
142
148
|
// data[y][x][n]のこと
|
143
149
|
int *data_all_value(struct data_all dd, int n, int x, int y)
|
144
150
|
{
|
151
|
+
assert(dd.mem != NULL);
|
152
|
+
assert(0 <= n && n < dd.size);
|
153
|
+
assert(0 <= x && x < 4);
|
154
|
+
assert(0 <= y && y < 3);
|
145
|
-
|
155
|
+
size_t forward = sizeof(struct head) + sizeof(struct data) * dd.size +
|
146
|
-
|
156
|
+
sizeof(int) * (n + dd.size * x + dd.size * 4 * y);
|
157
|
+
assert(forward < dd.mem_size);
|
158
|
+
return (int *)(dd.mem + forward);
|
147
159
|
}
|
148
160
|
int data_all_get_value(struct data_all dd, int n, int x, int y)
|
149
161
|
{
|
@@ -160,6 +172,10 @@
|
|
160
172
|
{
|
161
173
|
int rec_size = 100000;
|
162
174
|
dd = data_all_create(rec_size);
|
175
|
+
if (dd.mem == NULL) {
|
176
|
+
fprintf(stderr, "Failed to allocate memory.\n");
|
177
|
+
return 1;
|
178
|
+
}
|
163
179
|
// 既にあるデータ構造を入れる場合は、次のようにする。
|
164
180
|
// memcpy(dd.mem, ○○, dd.mem_size);
|
165
181
|
|
@@ -173,18 +189,18 @@
|
|
173
189
|
for (int x = 0; x < 4; x++) {
|
174
190
|
for (int y = 0; y < 3; y++) {
|
175
191
|
// data[y][x][n] = ...
|
176
|
-
data_all_set_value(
|
192
|
+
data_all_set_value(
|
177
|
-
|
193
|
+
dd, n, x, y, n * (y + 1) - x);
|
178
194
|
}
|
179
195
|
}
|
180
196
|
}
|
181
197
|
printf("%d: %s\n", data_all_data(dd, 3)->no,
|
182
|
-
|
198
|
+
data_all_data(dd, 3)->name);
|
183
199
|
printf("%d: %s\n", data_all_data(dd, 99999)->no,
|
184
|
-
|
200
|
+
data_all_data(dd, 99999)->name);
|
185
|
-
printf("%d\n", data_all_get_value(dd, 0, 0, 0));
|
201
|
+
printf("%d\n", data_all_get_value(dd, 0, 0, 0)); // 最小値
|
186
202
|
printf("%d\n", data_all_get_value(dd, 42, 1, 1));
|
187
|
-
printf("%d\n", data_all_get_value(dd, 99999,
|
203
|
+
printf("%d\n", data_all_get_value(dd, 99999, 3, 2)); // 最大値
|
188
204
|
data_all_destroy(dd);
|
189
205
|
return 0;
|
190
206
|
}
|
2
2\.の条件が抜けていた。
answer
CHANGED
@@ -87,4 +87,106 @@
|
|
87
87
|
Q: 構造体可変長配列(VLAIS)ってこれのこと?
|
88
88
|
A: 違います。これまた別の機能です。
|
89
89
|
Q: これってCの標準仕様?
|
90
|
-
A: だと思ったけど、調べ切れてないです。わかる人は教えてください。
|
90
|
+
A: だと思ったけど、調べ切れてないです。わかる人は教えてください。
|
91
|
+
|
92
|
+
---
|
93
|
+
|
94
|
+
> 2.入れ子の構造体の領域は、使用している独自処理のため、連続したメモリ領域である必要がある。
|
95
|
+
|
96
|
+
という制限があったのですね。struct data_allの構造を変えずにするとなると、普通に構造体や配列としてアクセスする方法では無理です。メモリを自分で確保して、直接計算してアクセスするしかないと思います。ということで、書き直しました。
|
97
|
+
|
98
|
+
```C
|
99
|
+
#include <stdio.h>
|
100
|
+
#include <stdlib.h>
|
101
|
+
|
102
|
+
struct head {
|
103
|
+
int size;
|
104
|
+
char ver[10];
|
105
|
+
};
|
106
|
+
|
107
|
+
struct data {
|
108
|
+
int no;
|
109
|
+
char name[30];
|
110
|
+
};
|
111
|
+
|
112
|
+
struct data_all {
|
113
|
+
int size;
|
114
|
+
int mem_size;
|
115
|
+
void *mem;
|
116
|
+
};
|
117
|
+
|
118
|
+
struct data_all data_all_create(int size)
|
119
|
+
{
|
120
|
+
struct data_all dd;
|
121
|
+
dd.size = size;
|
122
|
+
dd.mem_size = sizeof(struct head) + sizeof(struct data) * size +
|
123
|
+
sizeof(int) * 3 * 4 * size;
|
124
|
+
dd.mem = calloc(1, dd.mem_size);
|
125
|
+
return dd;
|
126
|
+
}
|
127
|
+
void data_all_destroy(struct data_all dd)
|
128
|
+
{
|
129
|
+
free(dd.mem);
|
130
|
+
dd.mem = NULL;
|
131
|
+
}
|
132
|
+
|
133
|
+
struct head *data_all_head(struct data_all dd)
|
134
|
+
{
|
135
|
+
return (struct head *)dd.mem;
|
136
|
+
}
|
137
|
+
struct data *data_all_data(struct data_all dd, int n)
|
138
|
+
{
|
139
|
+
return (struct data *)(dd.mem + sizeof(struct head) +
|
140
|
+
sizeof(struct data) * n);
|
141
|
+
}
|
142
|
+
// data[y][x][n]のこと
|
143
|
+
int *data_all_value(struct data_all dd, int n, int x, int y)
|
144
|
+
{
|
145
|
+
return (int *)(dd.mem + sizeof(struct data) * dd.size +
|
146
|
+
sizeof(int) * (n + dd.size * x + dd.size * 4 * y));
|
147
|
+
}
|
148
|
+
int data_all_get_value(struct data_all dd, int n, int x, int y)
|
149
|
+
{
|
150
|
+
return *data_all_value(dd, n, x, y);
|
151
|
+
}
|
152
|
+
void data_all_set_value(struct data_all dd, int n, int x, int y, int value)
|
153
|
+
{
|
154
|
+
*data_all_value(dd, n, x, y) = value;
|
155
|
+
}
|
156
|
+
|
157
|
+
struct data_all dd; // 可変部分があるため静的に作ることはできない
|
158
|
+
|
159
|
+
int main(int argc, char *argv[])
|
160
|
+
{
|
161
|
+
int rec_size = 100000;
|
162
|
+
dd = data_all_create(rec_size);
|
163
|
+
// 既にあるデータ構造を入れる場合は、次のようにする。
|
164
|
+
// memcpy(dd.mem, ○○, dd.mem_size);
|
165
|
+
|
166
|
+
// ダミーで値を入れてみる
|
167
|
+
for (int n = 0; n < dd.size; n++) {
|
168
|
+
struct data *d = data_all_data(dd, n);
|
169
|
+
d->no = n;
|
170
|
+
sprintf(d->name, "%08d", n);
|
171
|
+
}
|
172
|
+
for (int n = 0; n < dd.size; n++) {
|
173
|
+
for (int x = 0; x < 4; x++) {
|
174
|
+
for (int y = 0; y < 3; y++) {
|
175
|
+
// data[y][x][n] = ...
|
176
|
+
data_all_set_value(dd, n, x, y,
|
177
|
+
n * (y + 1) - x);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
printf("%d: %s\n", data_all_data(dd, 3)->no,
|
182
|
+
data_all_data(dd, 3)->name);
|
183
|
+
printf("%d: %s\n", data_all_data(dd, 99999)->no,
|
184
|
+
data_all_data(dd, 99999)->name);
|
185
|
+
printf("%d\n", data_all_get_value(dd, 0, 0, 0));
|
186
|
+
printf("%d\n", data_all_get_value(dd, 42, 1, 1));
|
187
|
+
printf("%d\n", data_all_get_value(dd, 99999, 2, 3));
|
188
|
+
data_all_destroy(dd);
|
189
|
+
return 0;
|
190
|
+
}
|
191
|
+
```
|
192
|
+
C++でクラス作っているような感じで実装すればできるかなと思います。
|
1
Clangで試したことと、Q&AにVLAISを追加
answer
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
頑張って、たぶん、こうしたいんだろうってのを実装してみました。
|
2
2
|
|
3
|
-
下記の機能を使っており、GCCでしか試していません。
|
3
|
+
下記の機能を使っており、gcc(GCC 5.3.0)とclang(LLVM 7.3.0)でしか試していません。
|
4
4
|
[Zero Length - Using the GNU Compiler Collection (GCC)](https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)
|
5
5
|
ただ、下記の情報もあるので、Visual C++でもいけると思います。
|
6
6
|
[構造体の可変長配列](https://msdn.microsoft.com/ja-jp/library/b6fae073(v=vs.120).aspx)
|
@@ -77,12 +77,14 @@
|
|
77
77
|
|
78
78
|
Q&A
|
79
79
|
Q: `[]`でいいの?
|
80
|
-
A: GCCとVCでは0サイズと見なして大丈夫のようです。ただ、それ一つだけだと構造体全体が0サイズになるため、他に何か必要になります。
|
80
|
+
A: GCCとVCでは0サイズと見なして大丈夫のようです。ただ、それ一つだけだと構造体全体が0サイズになるため、他に何か必要になります。`[1]`とする書き方もあるようですが、正式なドキュメントが見つけられませんでした。
|
81
81
|
Q: `int value[3][4][]`とはできないの?
|
82
82
|
A: できません。`int value[3][4][]`は「intが**可変個**ある型が4個ある型が3個ある型」となり、可変個部分が確定しないと最終的にアクセスできません。なので、`int value[][3][4]`として、「intが4個ある型が3個ある型が可変個ある型」にします。int[3][4]が可変個ある形になるので、いくつあるかわからなくても、n番目にアクセスできます。
|
83
83
|
Q: 可変長部分は最後以外には書けないの?
|
84
84
|
A: 書けません。メモリを確保できても、途中に可変長部分があるとがそこがどこで終わるのかわからなくなるからです。
|
85
85
|
Q: 可変長配列(VLA)ってこれのこと?
|
86
86
|
A: 違います。全く別の機能です。
|
87
|
+
Q: 構造体可変長配列(VLAIS)ってこれのこと?
|
88
|
+
A: 違います。これまた別の機能です。
|
87
89
|
Q: これってCの標準仕様?
|
88
90
|
A: だと思ったけど、調べ切れてないです。わかる人は教えてください。
|