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

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

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

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

Q&A

解決済

4回答

1364閲覧

C言語でほぼ同じ2か所の部分を1つにまとめたい

marchan

総合スコア4

C

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

0グッド

0クリップ

投稿2022/01/03 04:36

編集2022/01/03 08:45

前提・実現したいこと

void nexthen(int* i,int* j,int plus);はペア(i,j)の次のペアが何か計算しi,jに代入する、というプログラムです
ただし、引数のi,jは常に0<=i<j<vです。
イメージとしては
(0,1),(0,2),(0,3),...,(0,v-1),(1,2),...,(v-2,v-1)
という列があってその(i,j)の1つ手前や1つ奥のを知りたい、みたいな感じです。
ここで、nexthen(int* i,int* j,int plus);内の

c

1if(plus==1){ 2 if(*j+1==v){ 3 *i+=1; 4 *j=*i+1; 5 }else{ 6 (*j)++; 7 } 8} 9

C

1if(plus==-1){ 2 if(*j-1<=*i){ 3 *i-=1; 4 *j=v-1; 5 }else{ 6 (*j)--; 7 } 8}

がほぼ同じ内容なので、1つにまとめたいです。
何かうまいやり方があれば教えたください。
よろしくお願いします。

該当のソースコード

C

1#include <stdio.h> 2int v=6; 3void nexthen(int* i,int* j,int plus){ 4 //if(0<=*i&&*i<*j&&*j<v){ 5 if(plus==1){ 6 if(*j+1==v){ 7 *i+=1; 8 *j=*i+1; 9 }else{ 10 (*j)++; 11 } 12 } 13 if(plus==-1){ 14 if(*j-1<=*i){ 15 *i-=1; 16 *j=v-1; 17 }else{ 18 (*j)--; 19 } 20 } 21 //} 22} 23int main(){ 24 int i=3; 25 int j=4; 26 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 27 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 28 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 29 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 30 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 31 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 32 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 33 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 34 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 35 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 36 nexthen(&i,&j,1);printf("iは%d, jは%d\n",i,j); 37 printf("\n",i,j); 38 i=2; 39 j=3; 40 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 41 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 42 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 43 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 44 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 45 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 46 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 47 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 48 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 49 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 50 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 51 nexthen(&i,&j,-1);printf("iは%d, jは%d\n",i,j); 52} 53 54

実行結果

iは3, jは5 iは4, jは5 iは5, jは6 iは5, jは7 iは5, jは8 iは5, jは9 iは5, jは10 iは5, jは11 iは5, jは12 iは5, jは13 iは5, jは14 iは1, jは5 iは1, jは4 iは1, jは3 iは1, jは2 iは0, jは5 iは0, jは4 iは0, jは3 iは0, jは2 iは0, jは1 iは-1, jは5 iは-1, jは4 iは-1, jは3

補足情報(FW/ツールのバージョンなど)

実行結果について
入力がi=5, j=6

i=-1, j=5
になることは想定されていないので途中から一見するとおかしな値が出力されていますが、それは仕様でありプログラムは正常に動作しています。

暫定的な解決策

回答してくれた方々を参考に、自分なりにコードを書いてみました。条件分岐の代わりに膨大な四則演算を用いていてかっこ悪いですが......

C

1#include <stdio.h> 2void nexthen(int v,int* i,int* j,int plus){ 3 int k=(*j+plus==((v+*i)+(v-*i)*plus)/2); 4 *i+=plus*k; 5 *j=*j*(1-k)+((v+*i)-(v-*i)*plus)/2*k+plus; 6} 7int main(){ 8 int v=6; 9 int i=3; 10 int j=4; 11 nexthen(v,&i,&j,1);if(i!=3||j!=5)printf("iは%d, jは%d\n",i,j); 12 nexthen(v,&i,&j,1);if(i!=4||j!=5)printf("iは%d, jは%d\n",i,j); 13 nexthen(v,&i,&j,1);if(i!=5||j!=6)printf("iは%d, jは%d\n",i,j); 14 nexthen(v,&i,&j,1);if(i!=5||j!=7)printf("iは%d, jは%d\n",i,j); 15 nexthen(v,&i,&j,1);if(i!=5||j!=8)printf("iは%d, jは%d\n",i,j); 16 nexthen(v,&i,&j,1);if(i!=5||j!=9)printf("iは%d, jは%d\n",i,j); 17 nexthen(v,&i,&j,1);if(i!=5||j!=10)printf("iは%d, jは%d\n",i,j); 18 nexthen(v,&i,&j,1);if(i!=5||j!=11)printf("iは%d, jは%d\n",i,j); 19 nexthen(v,&i,&j,1);if(i!=5||j!=12)printf("iは%d, jは%d\n",i,j); 20 nexthen(v,&i,&j,1);if(i!=5||j!=13)printf("iは%d, jは%d\n",i,j); 21 nexthen(v,&i,&j,1);if(i!=5||j!=14)printf("iは%d, jは%d\n",i,j); 22 printf("\n"); 23 i=2; 24 j=3; 25 nexthen(v,&i,&j,-1);if(i!=1||j!=5)printf("iは%d, jは%d\n",i,j); 26 nexthen(v,&i,&j,-1);if(i!=1||j!=4)printf("iは%d, jは%d\n",i,j); 27 nexthen(v,&i,&j,-1);if(i!=1||j!=3)printf("iは%d, jは%d\n",i,j); 28 nexthen(v,&i,&j,-1);if(i!=1||j!=2)printf("iは%d, jは%d\n",i,j); 29 nexthen(v,&i,&j,-1);if(i!=0||j!=5)printf("iは%d, jは%d\n",i,j); 30 nexthen(v,&i,&j,-1);if(i!=0||j!=4)printf("iは%d, jは%d\n",i,j); 31 nexthen(v,&i,&j,-1);if(i!=0||j!=3)printf("iは%d, jは%d\n",i,j); 32 nexthen(v,&i,&j,-1);if(i!=0||j!=2)printf("iは%d, jは%d\n",i,j); 33 nexthen(v,&i,&j,-1);if(i!=0||j!=1)printf("iは%d, jは%d\n",i,j); 34 nexthen(v,&i,&j,-1);if(i!=-1||j!=5)printf("iは%d, jは%d\n",i,j); 35 nexthen(v,&i,&j,-1);if(i!=-1||j!=4)printf("iは%d, jは%d\n",i,j); 36 nexthen(v,&i,&j,-1);if(i!=-1||j!=3)printf("iは%d, jは%d\n",i,j); 37 printf("end\n"); 38}

実行結果

end

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

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

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

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

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

actorbug

2022/01/03 12:00

細かいことを言うと、元のコードと同じ動作をすることが仕様なのであれば、「暫定的な解決策」のコードはその仕様を満たしません。 元のコードは v が INT_MAX でも動作しますが、「暫定的な解決策」のコードだとオーバーフローして未定義動作となります。 それを言うなら、元のコードもいずれ *j が INT_MAX を超えてオーバーフローして未定義動作となるのですが。
marchan

2022/01/04 07:11

確かに、それは全く気づきませんでした。ありがとうございます。 四則演算するときはオーバーフローにかなり気を付けないといけないようですね。
guest

回答4

0

ベストアンサー

仕様では無くコードだけを見てということであれば、例えば if 文の中の式で plus を使えないか…と考えてみては如何でしょうか。


仕様から見ると、まずグローバル変数は使わないほうが良いですのでパラメータに加えておきます。
そして、要は j の変化をさせる関数ですので、真っ先に j を plus で変化させ、その結果を補正するようにします。

c

1void nexthen(int v,int* i,int* j,int plus){ 2 (*j)+=plus; 3 if(*j<=*i){ 4 (*i)--; 5 *j=v-1; 6 }else if(*j==v){ 7 (*i)++; 8 *j=*i+1; 9 } 10}

これだけでも大分違うと思いますが・・・不十分であればここからさらにコードで見ます。
+1 や -1 している部分で plus を使い、後は式の中で条件で切り替えます。

c

1void nexthen(int v,int* i,int* j,int plus){ 2 (*j)+=plus; 3 if(*j<=*i||*j==v){ 4 (*i)+=plus; 5 *j=(*j==v?*i:v)+plus; 6 } 7}

大体、これはやりすぎです。


ついでに。
テストする場合は、print して結果を目で確認するのではなく、確認自体もコード化したほうが良いです。

c

1int main(){ 2 int v=6; 3 int i=3; 4 int j=4; 5 nexthen(v,&i,&j,1);if(i!=3||j!=5)printf("iは%d, jは%d\n",i,j); 6 nexthen(v,&i,&j,1);if(i!=4||j!=5)printf("iは%d, jは%d\n",i,j); 7 nexthen(v,&i,&j,1);if(i!=5||j!=6)printf("iは%d, jは%d\n",i,j); 8 nexthen(v,&i,&j,1);if(i!=5||j!=7)printf("iは%d, jは%d\n",i,j); 9 nexthen(v,&i,&j,1);if(i!=5||j!=8)printf("iは%d, jは%d\n",i,j); 10 nexthen(v,&i,&j,1);if(i!=5||j!=9)printf("iは%d, jは%d\n",i,j); 11 nexthen(v,&i,&j,1);if(i!=5||j!=10)printf("iは%d, jは%d\n",i,j); 12 nexthen(v,&i,&j,1);if(i!=5||j!=11)printf("iは%d, jは%d\n",i,j); 13 nexthen(v,&i,&j,1);if(i!=5||j!=12)printf("iは%d, jは%d\n",i,j); 14 nexthen(v,&i,&j,1);if(i!=5||j!=13)printf("iは%d, jは%d\n",i,j); 15 nexthen(v,&i,&j,1);if(i!=5||j!=14)printf("iは%d, jは%d\n",i,j); 16 printf("\n"); 17 i=2; 18 j=3; 19 nexthen(v,&i,&j,-1);if(i!=1||j!=5)printf("iは%d, jは%d\n",i,j); 20 nexthen(v,&i,&j,-1);if(i!=1||j!=4)printf("iは%d, jは%d\n",i,j); 21 nexthen(v,&i,&j,-1);if(i!=1||j!=3)printf("iは%d, jは%d\n",i,j); 22 nexthen(v,&i,&j,-1);if(i!=1||j!=2)printf("iは%d, jは%d\n",i,j); 23 nexthen(v,&i,&j,-1);if(i!=0||j!=5)printf("iは%d, jは%d\n",i,j); 24 nexthen(v,&i,&j,-1);if(i!=0||j!=4)printf("iは%d, jは%d\n",i,j); 25 nexthen(v,&i,&j,-1);if(i!=0||j!=3)printf("iは%d, jは%d\n",i,j); 26 nexthen(v,&i,&j,-1);if(i!=0||j!=2)printf("iは%d, jは%d\n",i,j); 27 nexthen(v,&i,&j,-1);if(i!=0||j!=1)printf("iは%d, jは%d\n",i,j); 28 nexthen(v,&i,&j,-1);if(i!=-1||j!=5)printf("iは%d, jは%d\n",i,j); 29 nexthen(v,&i,&j,-1);if(i!=-1||j!=4)printf("iは%d, jは%d\n",i,j); 30 nexthen(v,&i,&j,-1);if(i!=-1||j!=3)printf("iは%d, jは%d\n",i,j); 31 printf("end\n"); 32}

このようにしておくと、結果が想定した値で無い場合に "iは~ jは~" と表示されますので、逆にそれが一切表示されず最後の "end" だけ表示されたら、全て想定内だったと言えます。
こうすることで、本件のようにコードを書き替えた結果が書き換える前と同じかどうかの確認が、回答側で「 print 結果がご提示のものと同じかどうか」を一つずつ見る必要が無くなり、かつ確実になります。

こんなメソッドを作っておくのも良いかもしれません。

c

1#include <stdarg.h> 2 3//b が false ならメッセージを表示して exit 4void assertFalse(int lineno, int b, char *format, ...) { 5 if(b) return; 6 7 printf("assert 行番号 %d: ", lineno); 8 9 va_list ap; 10 va_start(ap, format); 11 vprintf(format, ap); 12 va_end(ap); 13 14 printf("\n"); 15 exit(1); 16}

c

1 nexthen(v,&i,&j,1); assertFalse(__LINE__, i==3 && j==5, "iは%d, jは%d", i, j);

plain

1assert 行番号 30: iは3, jは4

投稿2022/01/03 05:21

編集2022/01/03 09:31
jimbe

総合スコア13209

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

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

marchan

2022/01/03 06:28

ありがとうございます。 *j=(*j==v?*i:v)+plus; この書き方はカッコいいですね。
marchan

2022/01/03 06:29

確認自体もコード化、は確かにそのとおりですね。参考にします
jimbe

2022/01/03 09:13 編集

> 暫定的な解決策 されるんじゃないかと思った通りに if 文を無くす方向で書かれましたね。ご自身で書かれていますように「かっこ悪い」と私も思います。 なによりもコードがパッと見で「何をしているか分からない」のが一番問題になります。 パソコンの性能が進んだ現在では、ハードウェアの進化やコンパイラの最適化等の進化で、 c のコードの極一部の if 文 1 つの有無程度では性能に全く変化が無いと言ってよい状況です。 とすると、プログラムの質は何で測られるようになるかというと「読み易さ」です。 究極的には、その言語を使える人なら(コメントが無くても)一見して何をしているかが分かる、ということです。 残念ながら nexthen の仕様である「(0,1),(0,2),(0,3),...,(0,v-1),(1,2),...,(v-2,v-1) というデータ列内での、ある位置の前/後の値を出す」ことの "コードによる最適な表現方法" は私にはまだ分かりませんが、ご提示された暫定のコードがパッと見でソレと分かるかというと…かなり難しいように思います。 自身のコードへの"美学"と他人の"読み易さ"(=分かり易さ)をどこまで高いレベルに出来るかは、二律背反する部分もあったりでバランスが難しいです。
marchan

2022/01/03 10:18

おっしゃる通りですね。一応、自分の中では if 文を無くす(減らす)方向で書く、というコンセプトだったので、コンセプト通りのコードは書けましたが、そのコンセプトに何の意味があるんだ、というそもそも論を突っ込まれると、なんとなく天才プログラマーっぽいコードになりそう、とか、難読化(自分のアイディアを他人にとられたくないときに使うことがあるかも?)ぐらいにしか意味がなさそうです。 ちなみに、メソッドに関してはva_listの存在を今初めて知り、かみ砕いている最中です。
jimbe

2022/01/03 11:33

世界的な c のコンテストみたいな方向になりますと teratail の方向性と違ってきますので、ご質問としては推奨されないでしょう。他の回答で言われていますように、やはりエンジニアとしては受け入れがたいことですので。 ただコードを弄るのが好きな個人としては、時には「仕方ないね笑」的に許してほしいネタ(失礼)でもあります。 可変長引数も普通にはほぼ使わないでしょうから、「スゴイっぽい」かもしれません(笑)
guest

0

それはまとめると意味がよくわからなくなるやつなのでまとめない方がいいです。
まとめるといわゆるスパゲッティになります。

投稿2022/01/03 04:47

qqfsdfsafd

総合スコア599

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

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

marchan

2022/01/03 05:00

そうかもしれません。 ただ、好奇心としてこういうのをまとめるうまいテクニックみたいなのはあるのかな、と思ったもので...
guest

0

美しくはないけれど、パズルとして解くなら

C

1void nexthen(int* i, int* j, int diff) { 2 int range = v - *i; 3 if (range != 0 && ((*j + diff - *i) % range) != 0) { 4 *j += diff; 5 } else { 6 *i += diff; 7 *j = diff > 0 ? (*i + 1) : v - 1; 8 } 9}

とか? スパゲティとは違うと思うけど、意図が読みにくいコードにはなりますね。

Text

1iは3, jは5 2iは4, jは5 3iは5, jは6 //以下範囲外 4iは6, jは7 5iは7, jは8 6iは8, jは9 7iは9, jは10 8iは9, jは11 9iは10, jは11 10iは10, jは12 11iは10, jは13 12 13iは1, jは5 14iは1, jは4 15iは1, jは3 16iは1, jは2 17iは0, jは5 18iは0, jは4 19iは0, jは3 20iは0, jは2 21iは0, jは1 22iは-1, jは5 //範囲外 23iは-1, jは4 //範囲外 24iは-1, jは3 //範囲外

投稿2022/01/03 05:53

thkana

総合スコア7703

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

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

thkana

2022/01/03 05:59

別に剰余とることもないか...
guest

0

そこまで似ていないものをまとめられたとしても相当読みづらいコードになってしまうので、まとめないほうがいいと思います。そこまで分量もないし複雑さもないので。


それでもどうしてもやりたかったら、こんな感じで要件を満たすことはできます。

c

1void nexthen(int *i, int *j, int plus) { 2 if ((*j + plus) >= v) { 3 *i += 1; 4 *j = *i + 1; 5 } else if ((*j + plus) <= *i) { 6 *i -= 1; 7 *j = v - 1; 8 } else { 9 *j += plus; 10 } 11}

投稿2022/01/03 04:44

編集2022/01/03 05:11
wsb

総合スコア194

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

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

wsb

2022/01/03 04:51 編集

最初の投稿はコードを読み間違えたものです
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問