C言語関係掲示板

過去ログ

No.952 複数の文字列の比較、並び替え

[戻る] [ホームページ]
No.12183

複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 12:09:53)


はじめまして。そうとう格闘しているのですが、
どうしてもわからないので教えてください。

今作っているのは、
人数を入力
  ↓
その人数の名前を入力(文字)
  ↓
辞書順に並び替える
  ↓
ファイルへ書き込む
というプログラムです。

人数分入力してファイルに出力するところまではうまくいくのですが、
どうしても辞書順に並び替わってくれません。
以下にお恥ずかしながらこれまでのプログラムを書きます。
どうもstrcmpの使い方がおかしい気がするのですが、
いかかでしょう。教えてください。



#include<stdio.h>
#include<string.h>


main()

{struct{
char name[2000];
}
data[300];
FILE *fin;
int i,j,n;
fin=fopen("a:\\test.doc","w");

printf("学生数=");
scanf("%d",&n);
printf("名前=\n");

for(i=1;i<=n;i++){
scanf("%s",data[i].name);
}

for(i=1;i<=n;i++){
if(strcmp(data[i].name,data[j].name))

fprintf(fin,"%s\n",data[i].name);
}
fclose(fin);
}

以上です。

No.12186

Re:複数の文字列の比較、並び替え
投稿者---nop(2004/01/27 12:31:19)


>人数分入力してファイルに出力するところまではうまくいくのですが、
>どうしても辞書順に並び替わってくれません。

ちなみに、どこで「並び替え」を行っているつもりですか?

No.12187

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 12:40:51)


>ちなみに、どこで「並び替え」を行っているつもりですか?

ってことは相当おかしいってことですよね(笑)。


for(i=1;i<=n;i++){
if(strcmp(data[i].name,data[j].name))


自分ではこの辺のつもりです…
数字の並び替えまでは習ったんで、応用できるかなぁと思ったのですが…

ひとつの文字列の中の並び替え、つまり
文字列間の並び替えでなければ(一部ですが)、

for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
if(s[i]>s[j]){
t=s[i];
s[i]=s[j];
s[j]=t;
}
}
}

こうなるとわかったのですが…
strcmpのあとには、二つ目に書いたような場合分けが必要なんですか?
初心者ですいませんが、よろしくお願いいたします。


No.12188

Re:複数の文字列の比較、並び替え
投稿者---nop(2004/01/27 12:46:35)


>for(i=1;i<=n;i++){
>if(strcmp(data[i].name,data[j].name))
>自分ではこの辺のつもりです…
>数字の並び替えまでは習ったんで、応用できるかなぁと思ったのですが…

strcmp() は文字列の比較になります。
並び替えるなら、比較した後にそれぞれの文字列を入れ替える必要があります。

No.12191

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 12:59:44)


>strcmp() は文字列の比較になります。
>並び替えるなら、比較した後にそれぞれの文字列を入れ替える必要があります。

はい、複数の文字の入れ替えのような状況がよくわからないので、
参考書を見て、もう少し考えてみます。
たぶん一人で解けないとは思いますが、
またわからなかったら、よろしくお願いします。
ありがとうございました。


No.12195

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 14:06:45)


少し考えてみました。
strcmpを用いるときは、

if (strcmp(a, b) == 0) {
    printf("等しい\n");
} else {
    printf("異なる\n");
}


という場合わけをすることはわかりました。
そして並び替えもですね。

しかしこれを複数の文字列間に応用する方法がわかりません。
複数というのは限りなくしたいのです。
それをひとつひとつ定義づけることはできないので、
やっぱりわかりません。
よろしければ教えてください。お願いします。


No.12197

Re:複数の文字列の比較、並び替え
投稿者---senshou(2004/01/27 14:36:50)


strcmp(文字列1, 文字列2)
としたときの動作は以下の通りです。
文字列1と文字列2が同じとき ー> 0を返す
文字列1が文字列2より小さいとき −> 負の値を返す
文字列1が文字列2より大きいとき −> 正の値を返す

ちなみに文字列は辞書順にしたがって(通常はASCIIコード順で)比較されます。
なので、辞書順で先に来る文字列のほうが小さく、あとにくる文字列のほうが大きいということです。


No.12198

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 14:41:13)


>ちなみに文字列は辞書順にしたがって(通常はASCIIコード順で)比較されます。
>なので、辞書順で先に来る文字列のほうが小さく、あとにくる文字列のほうが大きいということです。

はい。文字列が2つあって、その2つの辞書順の並び替えはできるのですが、
たくさんの文字列になった場合は、strcmp( , )のように定義できなくないですか?
そのようなときにどうやって比較させればいいのかわからないのですが、
教えていただけますか?


No.12202

Re:複数の文字列の比較、並び替え
投稿者---あかま(2004/01/27 14:53:13)


>はい。文字列が2つあって、その2つの辞書順の並び替えはできるのですが、
>たくさんの文字列になった場合は、strcmp( , )のように定義できなくないですか?
>そのようなときにどうやって比較させればいいのかわからないのですが、
>教えていただけますか?

for文を2重にしてぐるぐる回します。
>if(strcmp(data[i].name,data[j].name))
すでにあなたのプログラムでiとjの添え字が使われてるんですけど
元のプログラムは2重ループになってませんでした?
それともただの誤字?



No.12204

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 15:10:19)


>すでにあなたのプログラムでiとjの添え字が使われてるんですけど
>元のプログラムは2重ループになってませんでした?
>それともただの誤字?

2重ループにはなってないと思うのですが…
勉強不足ですいません。
誤字ではないと思います。コピペなので…

for文でぐるぐるまわすとは、
 for(i=1;i<n;i++){
   for(j=i+1;j<=n;j++){
    if(strcmp(data[i],data[j])

ということですか?
検討違いだったらすいません…。


No.12213

Re:複数の文字列の比較、並び替え
投稿者---あかま(2004/01/27 21:39:35)


そうです。そうです。
あと、添え字は0から使ったほうがいいですよ。
で、そのstrcmpの結果で文字列入れ替えの処理をするのです。

ちなみに文字列のコピーにはstrcpy関数を使いますので。

No.12280

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/29 09:19:26)


返信が遅れて申し訳ありません。
家のパソコンが調子悪くて、外で開いています。

>ちなみに文字列のコピーにはstrcpy関数を使いますので。
というヒントを元に、
 for(i=1;i<=n;i++){
  for(j=i+1;j<n;j++){

  if(strcmp(name[i],name[j])==0){
     strcpy(name[i],name[j]);}
  if(strcmp(name[i],name[j])>0){
     strcpy(name[i],name[j]);}
  if(strcmp(name[i],name[j])<0){
     strcpy(name[j],name[i]);}

  }
 }



となると考えました。
でもこれではまたまた多数のエラーが…
もう少し考えてみます。

>あと、添え字は0から使ったほうがいいですよ。
というアドバイスの指すところがよくわからないのですが、
あまり使わないように書いたほうが良いということなのでしょうか?
勉強不足ですいません。


No.12285

Re:複数の文字列の比較、並び替え
投稿者---あかま(2004/01/29 10:25:44)


>あと、添え字は0から使ったほうがいいですよ。
配列というのはdata[0]のように1ではなく0からはじまります。
ですから配列が300個の要素であればアクセスできるのはdata[0]〜data[299]です。
scanfで文字列を取り込むときにi=0としたほうがいいでしょう。

文字列の入れ替えですが、希望順序と逆の時だけ入れ替えればいいわけですから
すべての場合にstrcpyを書く必要はありません。
あと、構造体メンバへのアクセスの仕方が間違っています。

char buf[2000];

for(i=0;i<=n;i++){
  for(j=i+1;j<n;j++){
     if(strcmp(data[i].name,data[j].name)>0){
        strcpy(buf,data[i].name);//まずbufにi番目の文字列を非難
        strcpy(data[i].name,data[j].name);//j番目をi番目に
        strcpy(data[j].name,buf);//bufをj番目に
     }
  }
}


No.12293

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/29 12:24:09)


すいません!
=がひとつ抜けていました。
無事に自分なりの課題解決いたしました。
前の記事は削除しますね。

勉強不足でいろいろとご迷惑をおかけいたしました。
しかもこんなにたくさんのレスをリアルタイムでいただけるなんて、
本当にびっくりしました。
皆さんの豊富な知識もただただ教えてもらうばかりで、
なんにも返せなくてすいません。
また勉強してレベルアップしたら、今度は教える側になって、
この掲示板に来たいなぁ。何年先だろう…

本当にあかまさんはじめ、皆さんありがとうございました。

No.12201

Re:複数の文字列の比較、並び替え
投稿者---ゆかり(2004/01/27 14:46:43)


>数字の並び替えまでは習ったんで、応用できるかなぁと思ったのですが…

数字の並べ替えまではできたんですよね?
それで、ソートの考え方はわかりませんか?


No.12203

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/27 15:04:30)


えっと、数字の並び替えは

#include<stdio.h>
main()
{FILE *fin;
 int point[50],x1,x2;
 int i,j;

 fin=fopen("a:\\data.doc","r");

 for(i=1;i<=5;i++){
  fscanf(fin,"%d",&point[i]);
 }

  for(i=1;i<5;i++){
   for(j=i+1;j<=5;j++){
    if(point[i]<point[j]){

    x1=point[i];
    x2=point[j];
    point[j]=x1;
    point[i]=x2;

    }
   }
  }
  for(i=1;i<=5;i++){
   printf("%d\n",point[i]);
  }
 fclose(fin);
}


というのはわかります。
これはファイルから読み込んで並び替える形ですが…。
これだったら前後の数の大小関係を比較すればいいので、
理解できているとおもわれるのですが…。

なにか勘違いしてますかねぇ。
複数の文字だと上記と同じには比較できないと思っているのですが違いますか?
上記の方法を当てはめているつもりなのですが、いつもエラーになるので、
strcmpの使い方か、考え方自体が間違っていそうです…
あ、ちなみにC++です。Turbo C++というソフトを使っています。


No.12212

Re:複数の文字列の比較、並び替え
投稿者---NykR(2004/01/27 21:10:53)


というのはわかります。
これはファイルから読み込んで並び替える形ですが…。
これだったら前後の数の大小関係を比較すればいいので、
理解できているとおもわれるのですが…。

なにか勘違いしてますかねぇ。
複数の文字だと上記と同じには比較できないと思っているのですが違いますか?
strcmp(str_i, str_j) < 0  +------> str_i < str_j
strcmp(str_i, str_j) > 0  +------> str_i > str_j
strcmp(str_i, str_j) == 0 +------> str_i == str_j

と対応付けられることはわかりますか?
strcmp関数の動作が気になるのでしょうか?

最初の文字コードの大きさを比較 ※等しければ次の文字(※繰り返し)

という風にやっているんだろうと思いますが、関数を使うだけならそんなことは知らなくても
↓が分かっていれば何も問題はありません。

2つの文字列(char[]またはchar*)str1とstr2があったとして

  • str1とstr2の内容が全く同じならstrcmp(str1, str2) == 0
  • そうでない場合 strcmp(str1, str2) != 0 であり、
    • strcmp(str1, str2) > 0 ならば strcmp(str2, str1) < 0
    • strcmp(str1, str2) < 0 ならば strcmp(str2, str1) > 0
細かい大小関係は実装依存なので、実際にどのように判定されているかなんて気にしたって仕方ないです。
#例えばASCIIコードで比較しているなら、

    strcmp("abc", "def") < 0
    strcmp("abc", "Def") > 0

#となり、これは

    "Def" < "abc" < "def"

#に対応しますが、項目がこのように並んでいる辞書は滅多にありませんし、
#あったとしても使いにくいと思います
##まあそれでも辞書順と呼ぶんだろうとは思いますが。

上記の方法を当てはめているつもりなのですが、いつもエラーになるので、
strcmpの使い方か、考え方自体が間違っていそうです…

エラーが、コンパイルエラーの意味だとすれば、他には、例えば、nameメンバを(代入演算子を使って)直接交換しようとしている可能性があります。もし仮にそうなっているとすれば、構造体を丸ごと交換するように書き換えれば大丈夫でしょう

#それかstrcpyを使う

#配列は、代入演算子の左オペランドになることは出来ません

実際には、そのエラーになるソースを見なければ何とも言えませんが





#qsortを使うとか、
#C++ならstring型を使うとか
#そういうのは反則なんでしょうか、やっぱり

No.12281

Re:複数の文字列の比較、並び替え
投稿者---Kana(2004/01/29 10:11:36)


<pre>strcmp(str_i, str_j) < 0 +------> str_i < str_j
strcmp(str_i, str_j) > 0 +------> str_i > str_j
strcmp(str_i, str_j) == 0 +------> str_i == str_j</pre><p>と対応付けられることはわかりますか?

この結果をもとにstrcpyを使って並び替えるというところまではわかりました。
でもほかのところにもエラーが出て動作確認できないでいるのですが…。
複数のプログラムを合わせるのは難しいです。

>エラーが、コンパイルエラーの意味だとすれば、他には、例えば、nameメンバを(代入演算子を使って)直接交換しようとしている可能性があります。もし仮にそうなっているとすれば、構造体を丸ごと交換するように書き換えれば大丈夫でしょう

はい、そのように挑戦してみます…。
ちょっとよくわからないですが、コンパイルエラーだと思います。
TurboC++というソフトを使っていて、エラーは全部文字で表示されます。
コンパイル中にエラーを見つけて、実行できないときはとまるので。

>#qsortを使うとか、
>#C++ならstring型を使うとか
>#そういうのは反則なんでしょうか、やっぱり

qsortは使っちゃいけないと思います… 授業で取り扱ってないので。
string型こそ使ってほしいのだと思います。

実はもう課題の提出期限は過ぎてしまって、単位はもらえないのですが(笑)、
せっかくなので最後まで作りたいと思います。
うーん。まだまだ授業だけでは理解できてないわけですね。
またアドバイスお願いします。