質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

2846閲覧

C言語 関数形式マクロ swapについて

C_beginner

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2016/07/06 16:58

C

1#include <stdio.h> 2#include <time.h> 3#include <stdlib.h> 4 5#define swap(type, x, y) do{ type t = x; x = y; y= t; }while(0) 6 7int main(void){ 8 int num[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 9 int i; 10 11 srand(time(NULL)); 12 for( i = 9; i >= 1; i-- ){ 13 swap( int, num[i], num[ rand() % (i + 1)] ); 14 } 15 16 for( i = 0; i < 10; i++ ){ 17 printf("%d", num[i]); 18 } 19 putchar('\n'); 20 return 0; 21}

例として、FisherYatesのアルゴリズムを用いて配列要素をシャッフルするプログラムを挙げました。
実行例は、
6553000982
のように数値が重なってしまいます。

rnd = rand() % (i + 1);
のように先に乱数を代入しておき、
swap(int, a[i], a[rnd]);
を呼び出すと、(本来はif(i != rnd){/* ... */}の条件を付けていますが、仮に付けなくても)
正しくシャッフルされた形の配列が得られます。

上記プログラムのような引数の渡し方の場合、どのような処理が起こって
別の添字要素に影響を及ぼしているのかいまいち分かりません。

ご教授のほど、よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

C言語のマクロは、あくまで文字列として展開されます。そのため、展開後は

C

1do{ int t = num[i]; num[i] = num[ rand() % (i + 1)]; num[ rand() % (i + 1)]= t; }while(0)

となって、rand()が2回実行されてしまいます。関数呼び出しでなくても、i++のようなものをマクロ引数にすると似たようなことになってしまいます。

投稿2016/07/06 22:23

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C

1 for( i = 9; i >= 1; i-- ){ 2 swap( int, num[i], num[ rand() % (i + 1)] ); 3 }

が展開されると

C

1 for( i = 9; i >= 1; i-- ){ 2 do{ 3 int t = num[i]; 4 num[i] = num[ rand() % (i + 1)]; 5 num[ rand() % (i + 1)] = t; 6 }while(0); 7 }

となります。
rand()が2回実行され、別の添え字となっています。

マクロではなく関数にするか、

C

1#define swap(type, x, y) do{ type yt = y; type t = x; x = yt; yt = t; }while(0)

みたくrand()が呼ばれるのが1回になるようにするかでしょうね。

投稿2016/07/06 22:23

MIURA_Yasuyuki

総合スコア306

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2016/07/06 22:26

書き換え後のswapマクロでは、yへの代入がありませんよね…マクロで解決するのは厳しそうな気もします。
MIURA_Yasuyuki

2016/07/06 22:30

maisumakun さん、コメントありがとうございます。ご指摘の通りですね。添え字を覚えておかないといけないので、マクロでやるのは難しいというか、やってもキレイな解決方法にならなそうです。
C_beginner

2016/07/06 22:50

お二方回答ありがとうございます。 マクロの副作用を考慮出来ていなかったことがよく分かりました。 引数に演算子を含む式を渡してしまう可能性がある場合は、関数によって行うのが良いですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問