鍵括弧を使わないで順番をいれかえる方法

このQ&Aのポイント
  • 質問文章:鍵括弧を使わないで順番をいれかえる方法。関数hanten()を作り、プログラムを完成させよ。ただし、関数hanten()の中で、配列を宣言してはならない。例えば、入力が1, 8, 2, 6, 7だとすると、出力は、7 6 2 8 1となる。
  • 考え方の指摘:順番を入れ替えるためには、一時的な変数を使用して要素を入れ替える必要があります。また、配列の要素へのアクセスにはポインタを使用することができます。関数hanten()の中で、forループを使って要素を入れ替えることができます。
  • 提案:以下のようなプログラムを試してみてください。 ``` #include <stdio.h> #define MAX 5 void hanten(int *data, int max); int main(void) { int data[MAX], i; for (i = 0; i < MAX; ++i) { scanf("%d", &data[i]); } hanten(data, MAX); for (i = 0; i < MAX; ++i) { printf("%d ", data[i]); } printf("\n"); return 0; } void hanten(int *data, int max) { int i, tmp; for (i = 0; i < max / 2; ++i) { tmp = data[i]; data[i] = data[max - 1 - i]; data[max - 1 - i] = tmp; } } ``` このプログラムでは、関数hanten()内でforループを使用して要素を入れ替える方法が示されています。試してみて、期待通りの結果が得られるか確認してください。
回答を見る
  • ベストアンサー

鍵括弧を使わないで順番をいれかえる方法

講義でこのような問題が出ました /* 関数hanten()を作り、プログラムを完成させよ。 ただし、関数hanten()の中で、配列を宣言してはならない。 (当然引数である配列は除く。) main関数内部を変更してはならない。 例えば、入力が1, 8, 2, 6, 7だとすると、 出力は、 7 6 2 8 1 となる。 */ 自分なりに色々やってみたのですが、できませんでした 正直な話答えをそのまま聞きたいのですが それだけでは習得したといえないので どういう考えでやればいいのかご指摘いただくとうれしいです。 入れ替えということは変数を別に用意してあげてそこに読み込んでから 順番に入れ替えるということだと思うのですが・・・ 参考書(やさしいC,第3版)などを色々見たのですが なんかポインタを使うような・・・気はするのですが 配列はポインタでもあるのはわかっているのですが・・・ ネットで色々探したのですが、わかったのが*((data)...etcみたいなことができるということです。 ちなみに自分で色々やった結果はこれです。 コンパイルしたら入れ替えはされてない #include <stdio.h> #define MAX 5 void hanten(int [MAX],int); int main(void) { int data[MAX], i; for (i = 0; i < MAX; ++i) { scanf("%d", &data[i]); } hanten(data, MAX); for (i = 0; i < MAX; ++i) { printf("%d ", data[i]); } printf("\n"); return 0; } void hanten(int data[MAX],int max) { int i,tmp,*data2; for(i=0;i<max;i++){ tmp = *((data)+(i)); *((data)+(i)) = *((data2)+(i)); *((data2)+(i)) = tmp; } }

質問者が選んだベストアンサー

  • ベストアンサー
  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.4

>入力が1, 8, 2, 6, 7 ということであれば、 1)先頭と最後とを入れ替える(結果:7,8,2,6,1) 2)先頭から2番目と最後から2番目とを入れ替える(結果:7,6,2,8,1) 要素数が5個の場合は、ここまで行なうと要求を満たすプログラムができあがります。 一般に、 ・いちばん最初といちばん最後とを入れ替える ・先頭から2番目と最後から2番目とを入れ替える ・先頭から3番目と最後から3番目とを入れ替える ・先頭から4番目と最後から4番目とを入れ替える ... ・先頭からn番目と最後からn番目とを入れ替える この操作を繰り返すと逆順にできますが、nをいくつにすればよいかは もともとの要素数によって異なります。考えてみてください。

izupawapuro
質問者

お礼

一番わかりやすいと思いました。 なるほど・・・そういう手順で入れ替えることもできるのですね・・・ ありがとうございました!

その他の回答 (3)

回答No.3

#1さんの回答で必要十分で、足すところがないのですが、人のコードを見るのもいい勉強になると思いますので、参考までにいろいろと余計なことをしつつ書いてみます。ここでは酔狂のために無駄にポインタを使っていますが、最小限題意を満たすように作るなら、やってきた配列以外の新たな配列を作らなくてもいいですし、ポインタ変数を新たに作る必要もありません。ポインタ変数を使わない場合、hanten関数の中でswap関数に相当する処理をやります。 C99が通らないコンパイラだとコンパイルできませんが、こんな感じで。 (gccを使っている場合、-std=c99と書くとコンパイルできるかもしれません) #include <string.h> #include <stdio.h> #define MAX 5 #define STRING_MAX 1024 #define STRING_MAX_STR "1024" void static inline swap(void *x0, void *x1, int size) { unsigned char tmp[size]; memmove(tmp, x0, size); memmove(x0, x1, size); memmove(x1, tmp, size); } void hanten(void *data, int size, int nmemb) { for (int i = 0; i < nmemb / 2; i++) { swap(data + i * size, data + (nmemb - i - 1) * size, size); } } int main(void) { int data[MAX], i; char buf[STRING_MAX]; printf("Please input %d numbers:\n", MAX); for (i = 0; i < MAX; ++i) { scanf("%d", &data[i]); } hanten(data, sizeof(int), MAX); for (i = 0; i < MAX; ++i) { printf("%d ", data[i]); } printf("\n"); printf("Please type string:\n"); scanf("%" STRING_MAX_STR "s", buf); hanten(buf, sizeof(char), strlen(buf)); printf("%s\n", buf); return 0; } とまぁ、hanten関数とswap関数を型によらないように作ってみました。int型だけを受けうる場合、memmoveやらsizeでデータのサイズを渡しているところやらをやらないでいいことがあるので、そこのところをそんな風に書くと最低限題意を満たすものになるかと。

izupawapuro
質問者

お礼

ネットで探すと構造体系みたいなのと似てますね。 この問題の参考として出してくださったんだと思います ありがとうございました

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

講義で何を期待してこの問題を出したか、によります。 ○ 一番単純な方法は次のものになりますよね? ・新規配列data_newを用意 ・data_newに反転したdataを入れる data_new[0] = data[max-1] ; data_new[1] = data[max-2] ; .. data_new[i] = data[max - 1 -i] ; ... data_new[max-1] = data[0] ; // 0 == (max-1)-(max-1) ・dataにdata_newをコピー data[i] = data_new[i] ; この方法を使うには、「配列」data_newが必要です。 配列を宣言するには、大きさを指定する必要があります。 正しく動作させるには、引数max以上である必要があります。 そのため、「配列で宣言」するにはint data_new[500];等と適当に大きな値を使う必要があります。 # 正確には「ありました」。新しい規格に準拠したC言語では int data_new[max];と変数を使うこともできます。 # ただし、新規格に準拠していないコンパイラもまだまだ残っています。 問題の意図が「maxの値に応じた領域を確保する方法を学ぶ」ものであるなら、上記のような「適当に大きな配列を宣言」しないで ・malloc/callocで領域を確保、ポインタに記憶させる ・return前にfreeで解放 とします。 ○(malloc等で領域を確保するものも含め)同じ大きさの配列を用意することはしない、というのが「配列を宣言しない」の意味なら、「別のやりかたを考えろ」というのが、問題の意図となります。 上のやりかたを良く見ると、 data_new[0] = data[max-1] ; data_new[max-1] = data[0] 等と、2つ1組で入れ替わっていることがわかります。 つまり、data_newを用意しなくても、「data中の2つを入れかえる」を繰り返すだけで同等のことができる、というのがわかります。 「同じ組を2回入れかえたら、元にもどってしまう」ということに注意しましょう。 ○なお、質問にあるhantenですが ・ポインタで宣言しても[]が使えます。次のように書いても、まったく一緒です。 tmp = data[i]; data[i] = data2[i]; data2[i] = tmp; // =元のdata[i] 単に data[i]とdata2[i]を入れ替えただけで、順番は何も変わっていないことがわかります。 ・ポインタは宣言しただけでは、どこを指しているかわかりません。 そのまま *data2 などとすると、その「どこかわからないアドレス」にある「なんだかわからない値」が使われます。 別の変数の値を参照しているかもしれないし、OSの領域を参照しているかもしれません。 その結果、なにごともなく動作しているように見えることもあれば、領域違反でエラー終了することもあります。 ややこしいところですが、ポインタと配列はきちんと整理してしっかり勉強しましょう。

izupawapuro
質問者

お礼

後半の部分でご指摘いただいたことが勉強になりました ありがとうございます!

回答No.1

まずは  data[x] と data[y] とを入れ替える コードを書きます。 それができたら、 x = 0, y = MAX-1 を初期値とし、 x < y である間 {  data[x] と data[y] とを入れ替える  ++x  --y } する。  

izupawapuro
質問者

お礼

参考になりました~ありがとうございます!

関連するQ&A

  • プログラミング(C言語)についての質問です

    3つの整数の入力を受け付け、最大と最小を求める関数を作成し得られた結果を表示するプログラミングを作成したつもりなのですが、うまく作動しません。(コンパイルはできますが、結果が無茶苦茶になります。) ご教授宜しくお願いします。 それと、課題文にはポインタを使って最大値と最小値を同時に求めるようにと書いてあったのですが、それもよくわからないです。 今回初めてポインタと配列の受け渡しについて習ったのでよくわかっていない部分も多いと思うのですが、何卒宜しくお願いします。 ちなみに関数の形自体は void minmax(int data[],int *min,int *max){} で決まっています。 #include <stdio.h> void minmax(int data[],int *min,int *max){ int i; *min=*max=data[0]; printf("1st intenger:"); scanf("%d",&data[0]); printf("2st intenger:"); scanf("%d",&data[1]); printf("3st intenger:"); scanf("%d",&data[2]); for(i=1;i<3;i++){ if(*max<data[i]){ *max=data[i]; } if(*min>data[i]){ *min=data[i]; } } } int main(void){ int data[3],min,max; minmax(data,&min,&max); printf("最小値は%dで最大値は%dです",min,max); return 0; }

  • C言語のプログラムについて。

    C言語のプログラミングについて質問です。 入力されたデータの配列とデータ数を渡すと配列に格納された値を逆順にして、格納し直す関数reverse関数を書き結果を出力せよ、というものなのですが下のように書いたのですが、うまく作動しません。どこがいけないのでしょうか...?教えていただきたいです。 #include <stdio.h> void reverse(int *data[], int n); #define MAX 100 int main() { int data[MAX]; int n, i; scanf("%d", &n); if (n >= MAX) n = MAX; for (i = 0; i < n; i ++){ scanf("%d", &data[i]); } reverse(data, n); for (i = 0; i < n; i ++) { printf("%d\n", data[i]); } return 0; } void reverse(int *data[], int n) { int c, i; for (i = 0; i < n; i ++) { c = *data[i]; *data[i] = *data[n - (i + 1)]; *data[n - (i + 1)] = c; } }

  • 引数のみで出力

    問題として main内部を変更してはならない。 関数sub()でmainのループと同じ出力するようにせよ。 ただし、関数subで引数以外の変数を宣言してはならない。 また、広域変数を追加してはならない。 となっていて、色々とforループで出力させようと 配列にしたりポインタにしたりしたのですが forのiに比例する配列をどう組めばいいのか、わからないです。。。 mainの出力は 1 8 15 22 29 36 となっています。 これをsubでもできるように設定するみたいです。 #include <stdio.h> #define MAX 7 void sub(int [MAX]); int main() { int i; int x[MAX]; for (i = 0; i < MAX-1; ++i) { x[i] = 7*i+1; } x[MAX-1] = 0; for (i = 0; x[i] > 0; ++i) { printf("x = %d\n", x[i]); } printf("print again\n"); sub(x); return 0; } void sub(int a[MAX]) { // a[6]=0 // MAX 7 a[MAX-1]=0; for(a[MAX-1];a[MAX-7]<=MAX-1;++a[MAX-1]){ //a[MAX-1] = 7*a[MAX-1]+1; printf("a[%d] = %d\n",a[MAX-1],a[MAX-7]); } }

  • for文

    #include <stdio.h> int main(void) { int i; int sum=0; int num, tmp; printf("整数は何個かな:"); scanf("%d",&num); for(i=0; i<num; i++){ printf("No.%d:",i+1); scanf("%d",&tmp); sum+=tmp; } printf("合計値は:%d\n",sum); printf("平均値は:%.2f\n", (double)sum/num); return(0); } 上の文のforの箇所を for(i=1; i<=num; i++){ printf("No.%d:",i); scanf("%d",&tmp); sum+=tmp;   } としても結果的に同じですよね? どっちでもいいかどうか迷ってます。教えて下さい。

  • 配列の和を求めるプログラム

    キーから入力したデータを配列に入力した後、その和を求めるプログラムを作成したいのですが、プログラミング初心者の私にはさっぱりわかりません。 和を求めたいのに平均値が出てきてしまいます。 どこが間違っているのか教えてください。 #include <stdio.h> float data[5]; float total(int max); void main(void) { int cnt = 0; float d; printf("please input a data: "); scanf("%f", &d); while((cnt < 5) && (d > 0.0)) { data[cnt] = d; cnt++; printf("please input a data: "); scanf("%f", &d); } printf("total data: %5.2f\n", total(cnt)); } float total(int max) { int i; float total = 0.0; for(i = 0; i < max; i++) { total += data[i]; } return total / max; }

  • できているとは、思うのですが。ポインタの配列を

    コンパイラではちゃんと動いてます。 1 2 3 0 1 2 3 という具合です。 気になるのは、printarrayの部分が正しいのか、ちょっと悩んでいます 問題としては main関数では0の値を読み込むまで最大99(MAX-1)個の値を配列 xに読み込んでいる。引数のポインタからの値を、値が0になるまで すべて1行に1つづつ画面に出力する関数printarray()を作成し、 プログラムを完成せよ。 引数はアドレスとして受け取る事。(配列としてでなく) フォーマットは、 "%d¥n" とする。(余計な出力はしない事。) (0は出力しない。) main内部を変更してはならない。 以下がソースです。 ご指摘よろしくお願いします。 #include <stdio.h> #define MAX 5 void printarray(int *); int main() { int x[MAX], i; int *p; x[MAX-1] = 0; for (i = 0, p = x; i < MAX-1; ++i, ++p) { scanf("%d", p); if (*p == 0) { break; } } printarray(x); return 0; } void printarray(int *a) { int i,*p; for(i = 0, p = a; i < MAX-1; ++i,++p) { if(*p == 0){ // continue; break; }else{ printf("%d\n", *(a+i)); } } }

  • Cの素人がやってしまう・・・と言われた使い方

    関数set()を作って、下にコメントアウトされているプログラム と全く同じ動作をするプログラムを完成させよ。 main内部を変更してはならない。 関数set()内では鈎括弧を使用してはならない。 という問題で、終わるときにチェックされたのですが どうもsetでの中身が素人がよくやるやつ、といわれました。 int x[MAX]とやれ?ということなのでしょうか それともやはり&(*(x+i))の部分がおかしいということでしょうか? 確かにアドレスにアドレスを聞いているような理解としか、今は言いようがないのですが そいえば前回&*を使ってる人がいるけど・・・という話を聞きました 何かご指摘あればうれしいです 以下がコードになります。 #include <stdio.h> #define MAX 10 void set(int *x); int main() { int x[MAX]; int j; set(x); printf("KEKKA\n"); for (j = 0; j < MAX; ++j) { printf("%d\n", x[j]); } return 0; } void set(int *x) { int i; for(i = 0; i < MAX; ++i){ scanf("%d",&(*(x+i))); } } /* int main() { int x[MAX]; int j; for (j = 0; j < MAX; ++j) { scanf("%d", &x[j]); } printf("KEKKA\n"); for (j = 0; j < MAX; ++j) { printf("%d\n", x[j]); } return 0; } */

  • プログラミング(ポインタ/文字列処理)を教えて下さい

    プログラミング(ポインタ/文字列処理)を教えて下さい 英単語(最大で15文字まで)を*が現れるまで1つずつ読み込み、読みこんだ英単語の文字数を計算して表示するプログラムです。英単語は文字型配列を使用します。 1、関数の引数及びその中の実行文中で配列を使用 2、関数と引数及びその中の実行文中でポインタ変数を使用する この2つのプログラムを別々に作らなければならないのですが、当方関数をの使い方が今一分らないので以下のプログラムを関数での作成方法を教えて下さい。 これが関数で作らなければいけないプログラムです #include<stdio.h> int main(void) { char mojiretu[15]; int con[15]={0},i,j; printf("課題データ\n"); scanf("%s",mojiretu); while(mojiretu[0]!='*') { for(j=0;mojiretu[j]!='\0'j++) {} con[j-1]++; scanf("%s",mojiretu); } printf("文字数\t出現回数\n") for(i=0;i<=14;i++) printf("%d\t%d\n",i+1,con[i]); } こちらはポインタ変数を用いていますが関数になっていません。 #include<stdio.h> int main(void) { char mojiretu[15],*pmoji int con[15]={0},i,j; pmoji=&mojiretu[0]; printf("課題データ\n"); scanf("%s",mojiretu); while(*pmoji!='*') { for(j=0;*(pmoji+j)!='\0'j++) {} con[j-1]++; scanf("%s",mojiretu); } printf("文字数\t出現回数\n") for(i=0;i<=14;i++) printf("%d\t%d\n",i+1,con[i]); } 2つとも正常に動いてます。どちらか一つでもいいので関数での書き方を詳しくおねがいします。

  • C++ なのですがエラーが消えません

    課題のC++プログラムのエラーが消えません,教えてください. 10個の数値を入力し並び替えるプログラムなのですが並び替え部分以外は先生作成のプログラムです. どうかお願いいたします. #include <stdio.h> #define MAX 10 #define OK 0 void inputnum(int num[]); void sortnum(int num[]); void outputnum(int num[]); main(){ int num[MAX]; printf("番号 氏名\n"); inputnum(num); sortnum(num); outputnum(num); return(OK); } void inputnum(int num[]){ int i; for(i=0;i<MAX;i++,num[i]){ printf("数値%d = ", i+1); scanf("%d",&num[i]); } printf("数値入力完了\n"); } void sortnum(int num[]){ int tmp,p,q; for(p = 0; p < 9; p++){ for(q = p + 1; q < 10; q++){ if(num[p] > num[q]){ tmp = num[p]; num[p] = num[q]; num[q] = tmp; } } } printf("並び替え完了\n"); void outputnum(int num[]){ int i; for(i=0;i<MAX;i++){ printf("数値%d = %d\n",i+1,num[i]); } printf("数値出力完了\n"); }; [エラー  Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland 1142122.c: エラー E2140 1142122.c 46: ここでは宣言はできない(関数 sortnum ) エラー E2141 1142122.c 46: 宣言の構文エラー(関数 sortnum ) エラー E2134 1142122.c 54: 複合文に } がない(関数 sortnum ) *** 3 errors in Compile ***]

  • 処理の流れの説明のしかたがわかりません。

    プログラムの課題が出たのですがソースコードはなんとか穴埋めでできたのですが説明文を簡単につけなければならないのですがあんまり理解してないのでどのように説明したら良いかよくわかりません。お願いします。 10個の整数を配列し保存しそのデータのうちから最大値と最小値を表示するプログラムです。 #include <stdio.h> void main(void) { int data[10]; int i; int max,min; for(i=0;i<10;i++){ printf("input data No. %d ->",i+1); scanf("%d",&data[i]); } max=data[0]; min=data[0]; for(i=1;i<10;i++){ if(data[i]>max){ max=data[i]; } if(data[i]<min){ min=data[i]; } } printf("MAX = %d\n",max); printf("MIN = %d\n",min); } .