重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【解消】通知が届かない不具合について

講義でこのような問題が出ました
/*
関数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)
{
intdata[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;
}
}

A 回答 (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をいくつにすればよいかは
もともとの要素数によって異なります。考えてみてください。
    • good
    • 0
この回答へのお礼

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

お礼日時:2012/07/02 19:54

#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でデータのサイズを渡しているところやらをやらないでいいことがあるので、そこのところをそんな風に書くと最低限題意を満たすものになるかと。
    • good
    • 0
この回答へのお礼

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

お礼日時:2012/07/02 19:55

講義で何を期待してこの問題を出したか、によります。



○ 一番単純な方法は次のものになりますよね?
・新規配列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の領域を参照しているかもしれません。
その結果、なにごともなく動作しているように見えることもあれば、領域違反でエラー終了することもあります。
ややこしいところですが、ポインタと配列はきちんと整理してしっかり勉強しましょう。
    • good
    • 0
この回答へのお礼

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

お礼日時:2012/07/02 19:56

まずは


 data[x] と data[y] とを入れ替える
コードを書きます。

それができたら、

x = 0, y = MAX-1 を初期値とし、
x < y である間 {
 data[x] と data[y] とを入れ替える
 ++x
 --y
} する。
 
    • good
    • 0
この回答へのお礼

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

お礼日時:2012/07/02 19:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!