回答編集履歴

3

バグの修正とassertの追加

2016/05/06 15:03

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -194,6 +194,8 @@
194
194
 
195
195
  ```C
196
196
 
197
+ #include <assert.h>
198
+
197
199
  #include <stdio.h>
198
200
 
199
201
  #include <stdlib.h>
@@ -224,7 +226,7 @@
224
226
 
225
227
  int size;
226
228
 
227
- int mem_size;
229
+ size_t mem_size;
228
230
 
229
231
  void *mem;
230
232
 
@@ -236,13 +238,17 @@
236
238
 
237
239
  {
238
240
 
241
+ assert(0 <= size);
242
+
239
243
  struct data_all dd;
240
244
 
241
245
  dd.size = size;
242
246
 
243
247
  dd.mem_size = sizeof(struct head) + sizeof(struct data) * size +
244
248
 
245
- sizeof(int) * 3 * 4 * size;
249
+ sizeof(int) * 3 * 4 * size;
250
+
251
+ assert(0 <= dd.mem_size);
246
252
 
247
253
  dd.mem = calloc(1, dd.mem_size);
248
254
 
@@ -266,6 +272,8 @@
266
272
 
267
273
  {
268
274
 
275
+ assert(dd.mem != NULL);
276
+
269
277
  return (struct head *)dd.mem;
270
278
 
271
279
  }
@@ -274,9 +282,13 @@
274
282
 
275
283
  {
276
284
 
285
+ assert(dd.mem != NULL);
286
+
287
+ assert(0 <= n && n < dd.size);
288
+
277
289
  return (struct data *)(dd.mem + sizeof(struct head) +
278
290
 
279
- sizeof(struct data) * n);
291
+ sizeof(struct data) * n);
280
292
 
281
293
  }
282
294
 
@@ -286,9 +298,21 @@
286
298
 
287
299
  {
288
300
 
301
+ assert(dd.mem != NULL);
302
+
303
+ assert(0 <= n && n < dd.size);
304
+
305
+ assert(0 <= x && x < 4);
306
+
307
+ assert(0 <= y && y < 3);
308
+
289
- return (int *)(dd.mem + sizeof(struct data) * dd.size +
309
+ size_t forward = sizeof(struct head) + sizeof(struct data) * dd.size +
290
-
310
+
291
- sizeof(int) * (n + dd.size * x + dd.size * 4 * y));
311
+ sizeof(int) * (n + dd.size * x + dd.size * 4 * y);
312
+
313
+ assert(forward < dd.mem_size);
314
+
315
+ return (int *)(dd.mem + forward);
292
316
 
293
317
  }
294
318
 
@@ -322,6 +346,14 @@
322
346
 
323
347
  dd = data_all_create(rec_size);
324
348
 
349
+ if (dd.mem == NULL) {
350
+
351
+ fprintf(stderr, "Failed to allocate memory.\n");
352
+
353
+ return 1;
354
+
355
+ }
356
+
325
357
  // 既にあるデータ構造を入れる場合は、次のようにする。
326
358
 
327
359
  // memcpy(dd.mem, ○○, dd.mem_size);
@@ -348,9 +380,9 @@
348
380
 
349
381
  // data[y][x][n] = ...
350
382
 
351
- data_all_set_value(dd, n, x, y,
383
+ data_all_set_value(
352
-
384
+
353
- n * (y + 1) - x);
385
+ dd, n, x, y, n * (y + 1) - x);
354
386
 
355
387
  }
356
388
 
@@ -360,17 +392,17 @@
360
392
 
361
393
  printf("%d: %s\n", data_all_data(dd, 3)->no,
362
394
 
363
- data_all_data(dd, 3)->name);
395
+ data_all_data(dd, 3)->name);
364
396
 
365
397
  printf("%d: %s\n", data_all_data(dd, 99999)->no,
366
398
 
367
- data_all_data(dd, 99999)->name);
399
+ data_all_data(dd, 99999)->name);
368
-
400
+
369
- printf("%d\n", data_all_get_value(dd, 0, 0, 0));
401
+ printf("%d\n", data_all_get_value(dd, 0, 0, 0)); // 最小値
370
402
 
371
403
  printf("%d\n", data_all_get_value(dd, 42, 1, 1));
372
404
 
373
- printf("%d\n", data_all_get_value(dd, 99999, 2, 3));
405
+ printf("%d\n", data_all_get_value(dd, 99999, 3, 2)); // 最大値
374
406
 
375
407
  data_all_destroy(dd);
376
408
 

2

2\.の条件が抜けていた。

2016/05/06 15:03

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -177,3 +177,209 @@
177
177
  Q: これってCの標準仕様?
178
178
 
179
179
  A: だと思ったけど、調べ切れてないです。わかる人は教えてください。
180
+
181
+
182
+
183
+ ---
184
+
185
+
186
+
187
+ > 2.入れ子の構造体の領域は、使用している独自処理のため、連続したメモリ領域である必要がある。
188
+
189
+
190
+
191
+ という制限があったのですね。struct data_allの構造を変えずにするとなると、普通に構造体や配列としてアクセスする方法では無理です。メモリを自分で確保して、直接計算してアクセスするしかないと思います。ということで、書き直しました。
192
+
193
+
194
+
195
+ ```C
196
+
197
+ #include <stdio.h>
198
+
199
+ #include <stdlib.h>
200
+
201
+
202
+
203
+ struct head {
204
+
205
+ int size;
206
+
207
+ char ver[10];
208
+
209
+ };
210
+
211
+
212
+
213
+ struct data {
214
+
215
+ int no;
216
+
217
+ char name[30];
218
+
219
+ };
220
+
221
+
222
+
223
+ struct data_all {
224
+
225
+ int size;
226
+
227
+ int mem_size;
228
+
229
+ void *mem;
230
+
231
+ };
232
+
233
+
234
+
235
+ struct data_all data_all_create(int size)
236
+
237
+ {
238
+
239
+ struct data_all dd;
240
+
241
+ dd.size = size;
242
+
243
+ dd.mem_size = sizeof(struct head) + sizeof(struct data) * size +
244
+
245
+ sizeof(int) * 3 * 4 * size;
246
+
247
+ dd.mem = calloc(1, dd.mem_size);
248
+
249
+ return dd;
250
+
251
+ }
252
+
253
+ void data_all_destroy(struct data_all dd)
254
+
255
+ {
256
+
257
+ free(dd.mem);
258
+
259
+ dd.mem = NULL;
260
+
261
+ }
262
+
263
+
264
+
265
+ struct head *data_all_head(struct data_all dd)
266
+
267
+ {
268
+
269
+ return (struct head *)dd.mem;
270
+
271
+ }
272
+
273
+ struct data *data_all_data(struct data_all dd, int n)
274
+
275
+ {
276
+
277
+ return (struct data *)(dd.mem + sizeof(struct head) +
278
+
279
+ sizeof(struct data) * n);
280
+
281
+ }
282
+
283
+ // data[y][x][n]のこと
284
+
285
+ int *data_all_value(struct data_all dd, int n, int x, int y)
286
+
287
+ {
288
+
289
+ return (int *)(dd.mem + sizeof(struct data) * dd.size +
290
+
291
+ sizeof(int) * (n + dd.size * x + dd.size * 4 * y));
292
+
293
+ }
294
+
295
+ int data_all_get_value(struct data_all dd, int n, int x, int y)
296
+
297
+ {
298
+
299
+ return *data_all_value(dd, n, x, y);
300
+
301
+ }
302
+
303
+ void data_all_set_value(struct data_all dd, int n, int x, int y, int value)
304
+
305
+ {
306
+
307
+ *data_all_value(dd, n, x, y) = value;
308
+
309
+ }
310
+
311
+
312
+
313
+ struct data_all dd; // 可変部分があるため静的に作ることはできない
314
+
315
+
316
+
317
+ int main(int argc, char *argv[])
318
+
319
+ {
320
+
321
+ int rec_size = 100000;
322
+
323
+ dd = data_all_create(rec_size);
324
+
325
+ // 既にあるデータ構造を入れる場合は、次のようにする。
326
+
327
+ // memcpy(dd.mem, ○○, dd.mem_size);
328
+
329
+
330
+
331
+ // ダミーで値を入れてみる
332
+
333
+ for (int n = 0; n < dd.size; n++) {
334
+
335
+ struct data *d = data_all_data(dd, n);
336
+
337
+ d->no = n;
338
+
339
+ sprintf(d->name, "%08d", n);
340
+
341
+ }
342
+
343
+ for (int n = 0; n < dd.size; n++) {
344
+
345
+ for (int x = 0; x < 4; x++) {
346
+
347
+ for (int y = 0; y < 3; y++) {
348
+
349
+ // data[y][x][n] = ...
350
+
351
+ data_all_set_value(dd, n, x, y,
352
+
353
+ n * (y + 1) - x);
354
+
355
+ }
356
+
357
+ }
358
+
359
+ }
360
+
361
+ printf("%d: %s\n", data_all_data(dd, 3)->no,
362
+
363
+ data_all_data(dd, 3)->name);
364
+
365
+ printf("%d: %s\n", data_all_data(dd, 99999)->no,
366
+
367
+ data_all_data(dd, 99999)->name);
368
+
369
+ printf("%d\n", data_all_get_value(dd, 0, 0, 0));
370
+
371
+ printf("%d\n", data_all_get_value(dd, 42, 1, 1));
372
+
373
+ printf("%d\n", data_all_get_value(dd, 99999, 2, 3));
374
+
375
+ data_all_destroy(dd);
376
+
377
+ return 0;
378
+
379
+ }
380
+
381
+ ```
382
+
383
+ C++でクラス作っているような感じで実装すればできるかなと思います。
384
+
385
+

1

Clangで試したことと、Q&AにVLAISを追加

2016/04/29 09:30

投稿

raccy
raccy

スコア21735

test CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- 下記の機能を使っており、GCCでしか試していません。
5
+ 下記の機能を使っており、gcc(GCC 5.3.0)とclang(LLVM 7.3.0)でしか試していません。
6
6
 
7
7
  [Zero Length - Using the GNU Compiler Collection (GCC)](https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)
8
8
 
@@ -156,7 +156,7 @@
156
156
 
157
157
  Q: `[]`でいいの?
158
158
 
159
- A: GCCとVCでは0サイズと見なして大丈夫のようです。ただ、それ一つだけだと構造体全体が0サイズになるため、他に何か必要になります。
159
+ A: GCCとVCでは0サイズと見なして大丈夫のようです。ただ、それ一つだけだと構造体全体が0サイズになるため、他に何か必要になります。`[1]`とする書き方もあるようですが、正式なドキュメントが見つけられませんでした。
160
160
 
161
161
  Q: `int value[3][4][]`とはできないの?
162
162
 
@@ -170,6 +170,10 @@
170
170
 
171
171
  A: 違います。全く別の機能です。
172
172
 
173
+ Q: 構造体可変長配列(VLAIS)ってこれのこと?
174
+
175
+ A: 違います。これまた別の機能です。
176
+
173
177
  Q: これってCの標準仕様?
174
178
 
175
179
  A: だと思ったけど、調べ切れてないです。わかる人は教えてください。