配列を逆順にするプログラムについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Y.N

配列を逆順にするプログラムについて

#1

投稿記事 by Y.N » 10年前

こんにちは!プログラミングの講義に苦戦している大学生です。
課題で、「 大きさが任意のint型の配列の名前一つとその大きさを引数にとり, 呼び出されると配列の要素の並び順を逆順に並び替える関数 a_int_rev2を定義しなさい.
さらに, 実際に値を入れた配列ひとつとその大きさを引数にしてこの関数を呼び出し, 任意の大きさの配列が逆順に並び替わることを確かめるプログラムを 課題2の後に追加し,実行して確かめなさい. 」
というのがでました。自分なりにプログラムを作ったのですが思うような結果が出ません;;
訂正をよろしくお願いします。

int
a_int_rev2(int *q, int n)
{
int k, kari_atai;

for (k = 0; k <= (n-1)/2; k++) {
kari_atai = q[k];
q[k] = q[n-k-1];
q[n-k-1] = kari_atai;
}
return ;
}

int
main(void)
{
int y[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int w;

w = a_int_rev2(y, 10);
printf("%d\n", w);

return 0;
}

LL

Re: 配列を逆順にするプログラムについて

#2

投稿記事 by LL » 10年前

フォーラムルール
http://dixq.net/board/board.html
をよんでない故に起きた悲劇かどうか分かりませんが
まず言えるのは、コードの書き方がまず酷いです。

コード:

int
a_int_rev2(int *q, int n)
{
  int k, kari_atai;
  
  for (k = 0; k <= (n-1)/2; k++) {
    kari_atai = q[k];
    q[k] = q[n-k-1];
    q[n-k-1] = kari_atai;
  }   
  return ;
}

int
main(void)
{
  int y[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  int w;

  w = a_int_rev2(y, 10);
  printf("%d\n", w);
  
  return 0;
}
メソッドの宣言は

コード:

int
main(){
    //中身
}
ではなく、

コード:

int main(){
    //中身
}
です。変な改行をしないようにしましょう。
また、a_int_rev2メソッドは戻り値の指定をしているのに何の値も返していません。
[return (返したい値を直接指定するか、返したい値の格納された変数名); //返す値をちゃんと決めましょう]

Y.N

Re: 配列を逆順にするプログラムについて

#3

投稿記事 by Y.N » 10年前

コードの書き方はおっしゃるとおりの書き方が正しいと思っております。
ただ学校の先生の指導上、そのように書けといわれておりまして;;

以後気をつけたいと思います。

戻り値のところはqに返した際にならなかったので消していました。

ご指摘ありがとうございます。

LL

Re: 配列を逆順にするプログラムについて

#4

投稿記事 by LL » 10年前

コード通ったんで説明します

コード:

#include<stdio.h>            //printf使うならstdio.hを”インクルード”しましょう(http://www9.plala.or.jp/sgwr-t/c/sec05.html)
int a_int_rev2(int *q, int n)
{
  int k, kari_atai;
    //問題無し。だが、引数をバックアップもなしに直接こねくり回すことは感心できない
  for (k = 0; k <= (n-1)/2; k++) {
    kari_atai = q[k];
    q[k] = q[n-k-1];
    q[n-k-1] = kari_atai;
  }   
    //戻り値を指定したのなら(ちゃんと値を)返しましょう
  return kari_atai;
}

int main(void)
{
  int y[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  int w;

  w = a_int_rev2(y, 10);
  printf("%d\n",w);        //標準入出力をつかうなら#include<stdio.h>
    for(int i=0;i<10;i++){
        //ちゃんと配列の中身が入れ替わったか確認の為のprintf
        printf("%d",y[i]);
    }
    
  return 0;
入れ替えの部分には問題ありませんでしたが、ポインタ引数で直接し入れたものをこねくり回すことはあまり感心しません。
大体は関数内に同じ型の物を用意してそっちにコピーをし、コピーしたもので演算を行い、(返り値)で結果を返します。
万が一演算に失敗すると引数の値が書き換わってしまうので大きいプログラムの場合(死ぬほど辛い)デバッグがまっています。(原因特定がややこしくなる)
詳しくはこのサイトを参考にしてください
http://sealsoft.jp/ptr_and_ref.html

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 配列を逆順にするプログラムについて

#5

投稿記事 by h2so5 » 10年前

LL さんが書きました:フォーラムルール
http://dixq.net/board/board.html
をよんでない故に起きた悲劇かどうか分かりませんが
まず言えるのは、コードの書き方がまず酷いです。

コード:

int
a_int_rev2(int *q, int n)
{
  int k, kari_atai;
  
  for (k = 0; k <= (n-1)/2; k++) {
    kari_atai = q[k];
    q[k] = q[n-k-1];
    q[n-k-1] = kari_atai;
  }   
  return ;
}

int
main(void)
{
  int y[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  int w;

  w = a_int_rev2(y, 10);
  printf("%d\n", w);
  
  return 0;
}
メソッドの宣言は

コード:

int
main(){
    //中身
}
ではなく、

コード:

int main(){
    //中身
}
です。変な改行をしないようにしましょう。
戻り値の型の後に改行をするスタイルも存在するので間違いではありません。
このスタイルはIDEではメリットが少ないですが、Emacs系のエディタでは関数名をコピペするときにキー操作が少なくて済むメリットがあります。

https://github.com/mruby/mruby/blob/master/src/compar.c
http://git.savannah.gnu.org/cgit/emacs. ... c/buffer.c

LL

Re: 配列を逆順にするプログラムについて

#6

投稿記事 by LL » 10年前

コンパイル結果を載せ忘れてました。
https://ideone.com/yaeswZ
今cの開発環境が無いのでwebのコンパイラですがご了承ください

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: 配列を逆順にするプログラムについて

#7

投稿記事 by YuO » 10年前

書いている間に返信が付いていますが,せっかく書いたので投稿してしまいます。
Y.N さんが書きました:さらに, 実際に値を入れた配列ひとつとその大きさを引数にしてこの関数を呼び出し, 任意の大きさの配列が逆順に並び替わることを確かめるプログラムを 課題2の後に追加し,実行して確かめなさい. 」
というのがでました。自分なりにプログラムを作ったのですが思うような結果が出ません;;
「思うような結果」と,「実際の結果」を書いてください。
プログラムは書いたとおりに動くのですから,「思うような結果」は書かないと伝わらないです。

で,a_int_rev2で逆順にしたあと,それを確認するコードがないです。
a_int_rev2のコードは引数qが指す配列の要素を逆順に並び替えるものですから,
a_int_rev2の呼び出し前後で,yの各要素の値を出力すれば,「逆順に並び替わること」は確かめられます。
オフトピック
「任意の大きさの配列が」は無茶な問題ですね。
語釈の問題でもありますが,任意の,というのはどんな値でも受け入れることを意味するので,
現実的に確認のしようがない大きさの配列についても調べる必要が出て来ます。
往々にして,そういう値においてエラーが出るのですが……。
LL さんが書きました:ソッドの宣言は

コード:

int
main(){
    //中身
}
ではなく、

コード:

int main(){
    //中身
}
です。変な改行をしないようにしましょう。
何が問題なのでしょうか。
この関数定義のスタイルは,GNU Coding Standardsに則った,通常のスタイルだと思います。
オフトピック
私はこのスタイルが好きではないので使わないですが。

Y.N

Re: 配列を逆順にするプログラムについて

#8

投稿記事 by Y.N » 10年前

コード:

 
    w = a_int_rev2(y, 10);
    printf("%d\n",w);
    for (int i=0;i<10;i++) {
      printf("%d",y[i]);
    }
ご指摘がありましたようにこのようにしてコンパイルしたのですが、出力結果が

4
9876543210

となりました。
なので、

コード:

    w = a_int_rev2(y, 10);
    for (int i=0;i<10;i++) {
      printf("%d",y[i]);
    }
このように書き直したら、9876543210となりました。

ちゃんと逆順になったのでよかったのですが、これではwがなぜ4になってしまったのかがわかりません。

そのところ教えてもらえないでしょうか;;?

LL

Re: 配列を逆順にするプログラムについて

#9

投稿記事 by LL » 10年前

YuOさんへ。
申し訳ございません。そういう記述の方法もあることを知らなかったという己の無知の結果です。
あと、私個人が過剰なまでに改行して行数を増やす書き方を好まないという主観も入ってしまいました。

コード:

int main()
{
    //この括弧の改行も個人的には好きじゃない
}

コード:

int main(){
    //私個人はこれがしっくりくる
}

Y.N

YuOさんへ

#10

投稿記事 by Y.N » 10年前

思うような結果というのは「98765432101」でした。
しかし、実際は「4」となりました。


あ・・・一応正式な書き方なんですね。
ただ私もこの書き方は好きじゃありません 笑

どちらの書き方も覚えて置くようにします。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 配列を逆順にするプログラムについて

#11

投稿記事 by usao » 10年前

>return kari_atai;
これを返すことに何の意味があるのですか?
オフトピック
>ポインタ引数で直接し入れたものをこねくり回すことはあまり感心しません。

一般論として(?)そういう考え方はあるでしょうけど
この内容が講義の課題とされている背景状況というかを考えると,この点を突っ込むのはどうかな…と.

>ちゃんと逆順になったのでよかったのですが、これではwがなぜ4になってしまったのかがわかりません。

あなたが実行したコードでは,関数 a_int_rev2() は何をreturnする形になっているのですか?
(特段返すべき情報が無いのであれば,戻り値無しな関数にしてはいかがでしょう?)

あと,現状の出力結果だと
逆順になっているかどうかは コードと実行結果 の両方を見ないとわからないので,
逆にする前の(元の)内容も表示すると良いように思います.

LL

Re: 配列を逆順にするプログラムについて

#12

投稿記事 by LL » 10年前

Y.N さんが書きました:

コード:

 
    w = a_int_rev2(y, 10);
    printf("%d\n",w);
    for (int i=0;i<10;i++) {
      printf("%d",y[i]);
    }
ご指摘がありましたようにこのようにしてコンパイルしたのですが、出力結果が

4
9876543210

となりました。
なので、

コード:

    w = a_int_rev2(y, 10);
    for (int i=0;i<10;i++) {
      printf("%d",y[i]);
    }
このように書き直したら、9876543210となりました。

ちゃんと逆順になったのでよかったのですが、これではwがなぜ4になってしまったのかがわかりません。

そのところ教えてもらえないでしょうか;;?
これに関してですが、答えは単純で、a_int_rev2メソッドのkari_ataiを返り値として返したからです。
この部分に関してはY.Nさん本人が考えて書いたであろう部分なので詳細は省きます。
最初にプログラムを提示されたとき、a_int_rev2メソッドの返り値が不明だった為にとりあえずkari_ataiを返り値として返したそれだけの理由です。

Y.N

Re: 配列を逆順にするプログラムについて

#13

投稿記事 by Y.N » 10年前

YuOさんへ

私が考えていた関数a_int_rev2()は、y[]の中の配列を変えるだけのプログラムにしていたので戻り値は関係ないとは思っていました。
指摘を受けましたので、実際にreturn kari_atai;の部分を消してみて実行してみたら、ちゃんと「9876543210」となりました。

ありがうございます。

LL

Re: 配列を逆順にするプログラムについて

#14

投稿記事 by LL » 10年前

Y.N さんが書きました:YuOさんへ

私が考えていた関数a_int_rev2()は、y[]の中の配列を変えるだけのプログラムにしていたので戻り値は関係ないとは思っていました。
指摘を受けましたので、実際にreturn kari_atai;の部分を消してみて実行してみたら、ちゃんと「9876543210」となりました。

ありがうございます。
最初に提示されていたプログラムではint型の変数wの代入にint型の戻り値を返す関数a_int_rev2があったので
これは何か理由があるだろうと思って変な値を返すように書いてしまいました。
これらの行為によって無駄な混乱を起こしてしまって申し訳ございません。
ですがされていたプログラムでは

コード:

 w = a_int_rev2(y, 10);
  printf("%d\n", w);
のコードが記載されていましたがこれはただのミスでしょうか?

Y.N

Re: 配列を逆順にするプログラムについて

#15

投稿記事 by Y.N » 10年前

LLさんへ

改めてプログラムを見直していたら、LLさんのおっしゃる通り私のミスでした。

for文でy[]の要素を入れ替えた後に、kari_ataiが4になっているのを考えていませんでした。

なので要素の持たない整数型wに関数a_int_rev2()で入れ替えたyを代入しても「9876543210」とならずに、
kari_ataiの4が代入されることを見落としていました。

ご指摘ありがとうございます。

YuOさんとLLさんへ

たくさんのご指摘ありがとうございました!(^^)

かずま

Re: 配列を逆順にするプログラムについて

#16

投稿記事 by かずま » 10年前

解決になっていますが、よく考えてみましたか?

n が 2 のとき、q[0] と q[[1] を交換しますが、
n が 3 のとき、q[0] と q[2] を交換し、さらに q[1] と q[1] を交換しますよ。
無駄ですね。次のように書いたほうがよいでしょう。

コード:

void a_int_rev2(int *q, int n)
{
  int k, kari_atai;
  
  for (k = 0; k < n/2; k++) {
    kari_atai = q[k];
    q[k] = q[n-k-1];
    q[n-k-1] = kari_atai;
  }   
}


私なら、次のように書くでしょう。

コード:

void a_int_rev2(int *q, int n)
{
  int k, kari_atai;
  
  for (k = 0; k < --n; k++) {
    kari_atai = q[k];
    q[k] = q[n];
    q[n] = kari_atai;
  }   
}


でも、コンパイラによってはこっちの方が遅いコードが生成されたりするようで、
なかかな思うようにはいきません。

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

Re: 配列を逆順にするプログラムについて

#17

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

YuO さんが書きました:
LL さんが書きました:ソッドの宣言は

コード:

int
main(){
    //中身
}
ではなく、

コード:

int main(){
    //中身
}
です。変な改行をしないようにしましょう。
何が問題なのでしょうか。
この関数定義のスタイルは,GNU Coding Standardsに則った,通常のスタイルだと思います。
オフトピック
私はこのスタイルが好きではないので使わないですが。
LL さんが書きました:YuOさんへ。
申し訳ございません。そういう記述の方法もあることを知らなかったという己の無知の結果です。
あと、私個人が過剰なまでに改行して行数を増やす書き方を好まないという主観も入ってしまいました。
蛇足だとは思いますが、C++はフリーフォーマットなので、例えば

コード:

                                          int
       main
                            (
              )
                                                    {
                      // 中身
                                     }
と書いても文法上「正しい」です。
もちろん普通はこんな書き方はしないと思いますが。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

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