任意のタイミング,サイズで配列を作る方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
4700
記事: 3
登録日時: 3年前

任意のタイミング,サイズで配列を作る方法

#1

投稿記事 by 4700 » 3年前

gcc 6.3.0
質問です。
呼び出された時に、要素数nの配列を確保して破棄しない(static付けた時のように)関数を作りたいんですけど、以下のようにすると、

コード:

void main(){return;}
void f (int n)
{
	static int a[n];
	return;
}
error: storage size of 'a' isn't constant
サイズが不明でエラーになるみたいです。
任意のサイズとタイミングで確保できれば、別に関数である必要はないのですが、
なんとかこれを実装する方法はありますか。

アバター
usao
記事: 1887
登録日時: 10年前

Re: 任意のタイミング,サイズで配列を作る方法

#2

投稿記事 by usao » 3年前

malloc (C言語) だとか,
new とか STL (C++言語) とか,
そういう方向の話ですか?

4700
記事: 3
登録日時: 3年前

Re: 任意のタイミング,サイズで配列を作る方法

#3

投稿記事 by 4700 » 3年前

回答ありがとうございます。
すみません、あまり知識がないので、これがそういう方向の話なのか分かりません・・・
「メモリを動的に確保する」感じの話ではあると思います。
Cを使いたいので、mallocが使えそうだったので使ってみました。

コード:

#include <stdlib.h>
void main(){return;}
void f (int n)
{
	static int* a;
	a = (int*)malloc(sizeof(int)*n);
	free(a);
	return;
}
無事コンパイル通りました。ありがとうございます。
しかし、なんだか大げさな感じがしてしまいます。
何と言えばいいか分かりませんが、もうすこし質素な、
ヘッダファイルが要らないようなやり方で、どうにかする方法はないのでしょうか。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 任意のタイミング,サイズで配列を作る方法

#4

投稿記事 by みけCAT » 3年前

staticでなくてよければ、gcc拡張、もしくはC99の仕様で可変長配列(VLA : Variable-Length Array)が使えます。

コード:

void main(){return;}
void f (int n)
{
	int a[n];
	return;
}
【追記】
すいません、質問をよく読んでいませんでした。
「確保して解放しない」というのが条件なのですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 任意のタイミング,サイズで配列を作る方法

#5

投稿記事 by みけCAT » 3年前

4700 さんが書きました:
3年前
呼び出された時に、要素数nの配列を確保して破棄しない(static付けた時のように)関数を作りたいんですけど、
どうしてそのようなことがしたいのですか? (The XY Problemの疑いがあります)
4700 さんが書きました:
3年前

コード:

#include <stdlib.h>
void main(){return;}
void f (int n)
{
	static int* a;
	a = (int*)malloc(sizeof(int)*n);
	free(a);
	return;
}
このプログラムは、この質問の回答としては間違っています。
free(a);にとり、せっかく確保した配列が破棄されてしまいます。

コード:

#include <stdlib.h>
void main(){return;}
void f (int n)
{
	static int* a;
	free(a);
	a = (int*)malloc(sizeof(int)*n);
	return;
}
とすると、free(a);により前に確保した配列を破棄し(メモリリーク防止)、新しい配列を残すことができます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
あたっしゅ
記事: 663
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: 任意のタイミング,サイズで配列を作る方法

#6

投稿記事 by あたっしゅ » 3年前

Windows 10 PRO(64bit)
visual studio 2019
mikufree.cpp

コード:

#include <stdlib.h>
//
// https://urashita.com/archives/1271
// Visual Studio C++でメモリリークの検出
//   crtdbg.h CrtSetDbgFlag C言語のアクセス違反の調査 | urashita.com 浦下.com(ウラシタドットコム)(ja)
//
#include <crtdbg.h>
#define malloc(X) _malloc_dbg(X,_NORMAL_BLOCK, __FILE__,__LINE__)
#define new       ::new(_NORMAL_BLOCK, __FILE__,__LINE__ )
//
//
//
void
f(int n)
{
	static int* a;

	free(a);
	a = (int*)malloc(sizeof(int) * n);

	return;
}


int
main()
{
	_CrtSetDbgFlag(
		_CRTDBG_ALLOC_MEM_DF
		| _CRTDBG_DELAY_FREE_MEM_DF
		| _CRTDBG_CHECK_ALWAYS_DF
		| _CRTDBG_LEAK_CHECK_DF
	);
	f(0);
	return EXIT_SUCCESS;
}


// end.
出力
8<---------------------------
Detected memory leaks!
Dumping objects ->
C:\Users\MrAtassyu\Documents\2020x02\2019H31-01-01Atassyxx86\CBDxlibUnilove0Cuda-2020R02-12-19\MikuFree\MikuFree\MikuFree.cpp(18) : {90} normal block at 0x00B27CF8, 0 bytes long.
Data: <> -P{]ŸØîþÿÿÿˆùo
Object dump complete.
8<---------------------------
やっぱ、static int* a; を free(a); しちゃ、まずいだろ。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

4700
記事: 3
登録日時: 3年前

Re: 任意のタイミング,サイズで配列を作る方法

#7

投稿記事 by 4700 » 3年前

みけCATさん、
回答ありがとうございます
どうしてそのようなことをしたいのですか?
質問を受けて、長々とやりたいことを書き綴って整理しておりましたら、今気づきました。

この構造体が次回呼び出し時まで値を保持しておく必要は無く、
ただ単に確保と破棄を繰り返すのが、「基本グローバル変数しか存在しないような言語」を触っていたせいで気持ち悪かっただけで、
呼び出しのたびに確保する形でも良かったのかも知れません。

確かに、問題は私の思い込みや設計だと思います。
それらを他人に教えて貰う方法について心当たりがなく、c言語の問題まで自分で絞って質問しました。
よく考えず質問してしまいすみませんでした。

回答して頂きありがとうございました。精進します!

確保直後に解放してたのは、何考えてたんでしょうね・・・多分解放してないのが怖かったんだと思います。
サンプルまで添えて頂き、ありがとうございます。

あたっしゅさん、
私にはなにやらよく分かりませんが、みけCATさんのサンプルに問題がある感じですか。

アバター
あたっしゅ
記事: 663
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: 任意のタイミング,サイズで配列を作る方法

#8

投稿記事 by あたっしゅ » 3年前

> 私にはなにやらよく分かりませんが、みけCATさんのサンプルに問題がある感じですか。

そうです。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 任意のタイミング,サイズで配列を作る方法

#9

投稿記事 by みけCAT » 3年前

あたっしゅ さんが書きました:
3年前
やっぱ、static int* a; を free(a); しちゃ、まずいだろ。
static int* a;はヌルポインタに初期化され、
freeにヌルポインタを渡した場合は何もしないと決まっているので、問題ないはずです。

また、#6ではmallocに0を渡しているようですが、malloc(0)が何を返すかは処理系定義です。
#6の例では、malloc(0)はヌルポインタではないポインタを返すタイプの処理系であり、
その返されたポインタをfreeしていないため、メモリリークの発生として検出されているようですね。

以下、N1570より引用

6.7.9 Initialization
If an object that has static or thread storage duration is not initialized
explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
7.22.3.3 The free function
If ptr is a null pointer, no action occurs.
J.3 Implementation-defined behavior
J.3.12 Library functions
Whether the calloc, malloc, and realloc functions return a null pointer or a
pointer to an allocated object when the size requested is zero (7.22.3).
7.22.3 Memory management functions
If the size of
the space requested is zero, the behavior is implementation-defined: either a null pointer
is returned, or the behavior is as if the size were some nonzero value, except that the
returned pointer shall not be used to access an object.
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

返信

“C言語何でも質問掲示板” へ戻る