C言語関係掲示板

過去ログ

No.1154 入力ファイルから出力ファイルへ並び順を変更して出力したい

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

入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/18 10:54:34)


はじめまして。
最近C言語を勉強しはじめたばかりなのですが
いろいろな書物をみてもどうしても判らないので
申し訳ないですが、どなたかサポートをお願いできますでしょうか?

まず入力ファイルとして以下のようなファイルがあります

名前    男女別(M:男 F:女)   郵便番号
Sakamoto M 272
Yamada M 100
Hashimoto F 456
Doi F 123
Isibashi M 555

これを、
郵便番号   名前    男女別 の順に出力ファイルに出力したいのです。
なお、郵便番号は3桁で固定です。
そして、郵便番号と名前の間には7バイトのブランクをあけ
名前が10バイト目から始まり、男女別が30バイト目にしたいのです。

こんなプログラムをもとに、改良して作ろうと考えているのですが、
このプログラムでは1行読んで、そのまま1行はき出す形なので
うまくいくはずもないです。

#include <stdio.h>
#include <stdlib.h>
main()
{
FILE *fin,*fout;
char s [256];
if((fin=fopen("NYURYOKU.DOC","r")) == NULL){
printf("入力ファイルがオープンできない\n");
exit(1);
}

if((fout=fopen("SHUTURYOKU.DOC","w")) == NULL){
printf("出力ファイルがオープンできない\n");
exit(1);
}
while(fgets(s,256,fin)!=NULL){
fputs(s ,fout);
}

fclose(fin);
fclose(fout);
}

実際簡単なことなのでしょうが、なにせ初心者すぎて、勝手がわからず
本当に困っています。すみませんが、お手すきの方、救いの手をこの
馬鹿者に差し伸べてやってもらえませんでしょうか?


No.14726

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/18 10:58:42)


>これを、
>郵便番号   名前    男女別 の順に出力ファイルに出力したいのです。
>なお、郵便番号は3桁で固定です。
>そして、郵便番号と名前の間には7バイトのブランクをあけ
>名前が10バイト目から始まり、男女別が30バイト目にしたいのです。

すみません、追加があります。↓
男女別表示後、50バイト目までブランクを空け、改行したいです。

ほんと馬鹿です。いろいろ読んでもさっぱり判りません。


No.14754

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---RAPT(2004/06/18 22:31:37)


何かね、ちゃんと教える元気がないからソースだけ貼っとくから理解してね。

Windows2000sp4/VC++6.0sp6/Console-App

#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fin = NULL, *fout = NULL;
  char s[1 + BUFSIZ] = {0};
  char name[21] = {0}, sex = 0, post[3] = {0};

  if((fin = fopen("NYURYOKU.DOC","r")) == NULL){
    printf("入力ファイルがオープンできない\n");
    exit(1);
  }
  
  if((fout = fopen("SHUTURYOKU.DOC","w")) == NULL){
    printf("出力ファイルがオープンできない\n");
    fclose(fin);
    exit(1);
  }
  while(fgets(s, BUFSIZ, fin) != NULL){
    if(3 != sscanf(s, " %20s %c %3s ", name, &sex, post)){
      fprintf(stderr, "入力元データの不整合.\n");
      fcloseall();
      exit(1);
    }
    fprintf(fout, "%-10s%-20s%c%19s\n", post, name, sex, "");
  }
  
  fclose(fin);
  fclose(fout);

  return 0;
}



No.14762

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/19 12:30:26)


RAPT さん ありがとうございました。
まだ初心者で、見ただけでははっきり判らないのですが、
後は本などで勉強したいと思います。


No.14763

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/19 13:15:43)


すみませんがもう一度質問します。
このロジックの内容はよくわかったのですが、
このロジックにあるように、fgetsで1行を取り出す
部分はいいんですけど、sscanfのような便利な関数を
使わず、文字列を切り出す方法はありますでしょうか?
昨日一日考えても判らなくて、困っています。
お暇な方がいらっしゃいましたら、ご指導ねがえれば
幸いです。

while(fgets(s, BUFSIZ, fin) != NULL){
    if(3 != sscanf(s, " %20s %c %3s ", name, &sex, post)){
      fprintf(stderr, "入力元データの不整合.\n");
      fcloseall();
      exit(1);
    }




No.14764

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/19 13:37:41)


>部分はいいんですけど、sscanfのような便利な関数を

sscanfを使わないならstrtokを使います。
関数全般を使いたくないなら自分でstrtokに近いもの実装すればいいです。


No.14765

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ZAQ(2004/06/19 16:12:12)


関数を使わないのなら文字と文字の間にはスペースもしくは改行があるはずだから、それを読み込んでから(スペースまたは改行)から次のスペースまたは改行に、はさまれた文字列を配列に入れれば、関数を使わないでできますが、面倒なので関数を使うほうがいいかと思います。(その他にもいろいろあります。)
その次に、読み込んだ文字列をを並び替えれば、関数を使わずにできます。
(個人的にはsscanfが一番簡単でいいのですが・・・・)


No.14769

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/19 19:49:36)


>関数を使わないのなら文字と文字の間にはスペースもしくは改行があるはずだから、それを読み込んでから(スペースまたは改行)から次のスペースまたは改行に、はさまれた文字列を配列に入れれば、関数を使わないでできますが、面倒なので関数を使うほうがいいかと思います

レスありがとうございます。おっしゃる通り、面倒なのですが、今回は
関数を極力使わない面倒なやり方をしたいのです。

fgetsで当然ですがこのような並びでsに格納されますよね。↓
名前    男女別   郵便番号

仮に、これらにスペースの部分も含めて番号を振ります↓
 1   2   3   4   5
名前     男女別   郵便番号

これらを切り出して配列に
name[]= 1
space1[] = 2
sex[] = 3
space2[]=4
post[]=5

 みたいな感じでスペースの部分も切り出して格納すればいいという
 ことでしょうか?違いますか?

 できれば具体的な例を示していただけるとありがたいのですが・・・
 教えてばっかりで本当にすみません。せっかく教えていただいたのに
 こちらの理解が足りないばっかりで・・・
      





No.14773

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/19 20:56:18)


>レスありがとうございます。おっしゃる通り、面倒なのですが、今回は
>関数を極力使わない面倒なやり方をしたいのです。
> できれば具体的な例を示していただけるとありがたいのですが・・・
勉強のために面倒なやり方をしたいのだと思いますが、自分でやらないと意味ないのでは?
自分で作ってみてうまく動作しないというのならアドバイスのしようもありますが。
わざわざ「面倒な」プログラムを書いてくれる人も少ないと思いますよ。


> みたいな感じでスペースの部分も切り出して格納すればいいという
> ことでしょうか?違いますか?
スペースの部分は使わないので、配列に格納しないで捨てればいいと思いますよ。
「スペースを読み込んで、次のスペースがくるまでの間の文字を配列に読み込む関数」を作ったらどうでしょうか。
スペースが2回続いたときは問題ですが、文字列長が0なので検出は簡単でしょう。
すぐ近くのスレッド「文字列の表示」のNo.14770が役に立つと思います。
http://www2.realint.com/cgi-bin/tarticles.cgi?pointc+14770


No.14774

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---RAPT(2004/06/19 21:38:35)


勉強のために面倒なやり方をしたいのだと思いますが、自分でやらないと意味ないのでは?
自分で作ってみてうまく動作しないというのならアドバイスのしようもありますが。
同感です。既に「普通の方法」が提示されているので、通常はヒントまで
貰ったら後は自分でやるべきでしょう。

わざわざ「面倒な」プログラムを書いてくれる人も少ないと思いますよ。
ええ、少ないでしょうね。でも折角書いたので掲載しておきます(^^;

とりあえず、サンプルってことで、バッファのオーバーフロー等は考慮していません。
Windows2000sp4/VC++6.0sp6/Console-App

#include <stdio.h>

void copy_token(char *pszBuff, char *pszString)
{
  static char *p = NULL;
  if(pszString){
    p = pszString;
  }
  while(*p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')){
    p++;
  }
  while(*p && !(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')){
    *pszBuff++ = *p++;
  }
  *pszBuff = '\0';
}

int main()
{
  char *str = "abc de fg  hij k\nlmn\top q";
  char buff[BUFSIZ] = {0};

  printf("<%s>\n\n", str);
  copy_token(buff, str);
  while( *buff ){
    printf("[%s]\n", buff);
    copy_token(buff, NULL);
  }
  return 0;
}

出力結果は以下のとおり。
<abc de fg  hij k
lmn     op q>

[abc]
[de]
[fg]
[hij]
[k]
[lmn]
[op]
[q]



No.14775

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/19 21:46:05)


>勉強のために面倒なやり方をしたいのだと思いますが、自分でやらないと意味ないのでは?
>自分で作ってみてうまく動作しないというのならアドバイスのしようもありますが。
>わざわざ「面倒な」プログラムを書いてくれる人も少ないと思いますよ。

いろいろありがとうございます。確かにおっしゃることも判ります。
なのですが、sに格納された行の、よい切り出し方の出来るロジックが
思いつかなかったのです。

配列を準備するのはいいとして、どうやって名前 性別 郵便番号の
配列にsの内容を切り出して格納すればいいものか・・・・

もし、暇のある方がいましたら、お願いできないものかなと思って
例を示してほしいと書きました。勉強にならないというかもしれませんが、サンプルをみて勉強の参考にしたかったのです。


No.14780

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---かずま(2004/06/20 00:49:02)


> もし、暇のある方がいましたら、お願いできないものかなと思って
> 例を示してほしいと書きました。勉強にならないというかもしれませんが、
> サンプルをみて勉強の参考にしたかったのです。

では、次のサンプルの場合、どういうところが参考になったのかを詳しく説明
してみてください。
#include <stdio.h>

int main(void)
{
    char buf[1024], *str[3], *p;  int i;

    while (fgets(buf, sizeof buf, stdin)) {
        p = buf;
        for (i = 0; i < 3; i++) {
            while (*p == ' ' || *p == '\n') p++;
            str[i] = p;
            while (*p && *p != ' ' && *p != '\n') p++;
            if (*p) *p++ = 0;
        }
        printf("%-10s%-20s%-20s\n", str[2], str[0], str[1]);
    }
    return 0;
}



No.14779

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ZAQ(2004/06/20 00:18:53)


#include<stdio.h>
int main(void)
{
    char a[30]="abc    def   gb  g  ",b[3][10];
    int x,y=0,i=0,z=0;
    for(x=0;a[x]!='\0';x++)
    {
        if(a[x]==' ' && z==0 || a[x]=='\t' && z==0)
        {
            b[i][y]='\0';
            i+=1;y=0;z=1;
        }
        if(a[x]!=' ' && a[x]!='\t')
        {
            b[i][y++]=a[x];z=0;
        }
    }
    printf("%s\n",b[0]);
    printf("%s\n",b[1]);
    printf("%s\n",b[2]);
    printf("%s",b[3]);
    return 0;
}

これで、スペースに囲まれた文字列を分割できます。今回はaに入っている文字列を4個に分割しています。
ただ、aの一つ目がスペースのときは、だめです。コンパイルすれば分かります。
<実行結果>
abc
def
gb
g
誰か改良してください。


No.14787

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ぽこ(2004/06/20 07:23:17)


> char a[30]="abc def gb g ",b[3][10];
と定義されている配列bに対して、

> printf("%s",b[3]);
↑これはまずいかと。



No.14789

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/20 08:50:56)


>誰か改良してください。
どぞ。

#include<stdio.h>
int main(void)
{
    char a[30]="  abc    def   gb  g  ",b[4][10];
    int x,y=0,i=0;
    for(x=0;a[x]!='\0';x++)
    {
        if(a[x]==' ' || a[x]=='\t')
        {
            b[i][y]='\0';
            if(y != 0) i+=1;
            y=0;
            
        }
        else
        {
            b[i][y++]=a[x];
        }
    }
    printf("%s\n",b[0]);
    printf("%s\n",b[1]);
    printf("%s\n",b[2]);
    printf("%s",b[3]);
    return 0;
}



No.14792

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ZAQ(2004/06/20 11:42:20)


ありがとうございました。


No.14804

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---かずま(2004/06/21 02:02:11)


>> 誰か改良してください。
> どぞ。

そのプログラムでは、a[30] の中の g の次の空白をみて、
b[4][0] に '\0' を書き込んでしまいますよ。

また、元のプログラムもそうですが、g の次に空白がない場合、
b[3][0] に 'g' がはいったあと、b[3][1] に '\0' が入りません。
さらに、a[30] にない、'\t' を考慮するなら '\n' も加えたほうが、
最初の問題の fgets との整合性がよくなるでしょう。

#include <stdio.h>

int main(void)
{
    char a[30] = " abc    def   gb  g", b[4][10];
    int x, y = 0, i = 0;

    for (x = 0; a[x] != '\0'; x++)
        if (a[x] != ' ' && a[x]!='\t' && a[x] != '\n')
            b[i][y++] = a[x];
        else if (y != 0)
            b[i++][y] = '\0', y = 0;
    if (y != 0) b[i][y] = '\0';
    printf("%s\n%s\n%s\n%s\n", b[0], b[1], b[2], b[3]);
    return 0;
}



No.14806

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/21 12:47:59)


いろいろなアドバイスありがとうございます。
たくさん試してみたのですが、未だうまくいきません。

そして、今回配列を使うのではなく、このように構造体を使ってやりたい
と思うのです。

#include <stdio.h>
#include <stdlib.h>

struct meibo {
    char  name[20];
    char  danjo;
    int  postNo;
};

main()
{
  FILE *fin,*fout;
  char  s [256];
  int  i;
  struct meibo member[30];

  if((fin=fopen("SV.ADR","r")) == NULL){
      printf("入力ファイルがオープンできない");
      exit(1);
  }

  if((fout=fopen("ADR.SV","w")) == NULL){
      printf("出力ファイルがオープンできない");
      exit(1);
  }

  for(i=0;fscanf(fin,"%s\t%c\t%d\n", member[i].name,&member[i].danjo,&member[i].postNo)!=EOF;
      i++){
      fprintf(fout,"%-10d\t%-20s\t%19c\n",member[i].postNo,member[i].name,member[i].danjo);
      }
  fclose(fin);
  fclose(fout);
}



このロジックをできるだけ崩さず(for文のところはかなり変える必要があると
は思いますが)、fscanfなどの関数を使わないで
並び順を変更して、ファイルにはき出す方法はないものでしょうか?
いろいろ考えても判りません。どなたか救いの手を差し伸べてやって
ください。馬鹿で本当にすみません。


No.14808

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---REE(2004/06/21 13:03:35)


>たくさん試してみたのですが、未だうまくいきません。

どれをどう試して、どううまくいかなかったのでしょうか?

>そして、今回配列を使うのではなく、このように構造体を使ってやりたい
>と思うのです。

そういう条件は、最初から提示してください。
また、配列で求めてから、構造体に移すのではいけないのですか?

>fscanfなどの関数を使わないで

fscanfは決して特別な関数ではなく、
fopen, fcloseなどと同じく極めて一般的な標準ライブラリ関数です。
fopenはよくて、fscanfは駄目ということであれば、どの関数なら使ってよいのでしょうか?
基準を明確にしてください。


No.14810

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/21 13:25:08)


>たくさん試してみたのですが、未だうまくいきません。
なにを試したのかを書かなければ、こちらにはわかりません。
一番簡単なのは試したソースコード(とある程度の説明)を貼り付けることです。

>そして、今回配列を使うのではなく、このように構造体を使ってやりたい
>と思うのです。
構造体を使って1レコードを管理するのは良い方法です。
前のプログラムと違いは大してありません。別々の配列に読み込むところを構造体に読み込むだけです。

>並び順を変更して、ファイルにはき出す方法はないものでしょうか?
並び替えは一度すべてのデータを読み込まないとまず無理です。
ですからまず1レコードを読み込む関数を作ってみてください。
並べ替えはその後です。

>fscanfなどの関数を使わないで
すでにスペース区切りで文字列を読み込むプログラムは出ているのですから、
それを改良したらいいのではないでしょうか?

>サンプルをみて勉強の参考にしたかったのです。
とのことですが、参考にならなかったのでしょうか?


1レコードを構造体に格納する関数。

1.fgetsで1レコード分を読み込む
2.スペース区切りで文字列を切り分ける
3.構造体に格納する。
(2.と3.は同時進行でもok)

なんてことをすればうまくいくと思います。


No.14813

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/21 16:33:17)


いろいろやってみてこんなロジックになりました。

#include <stdio.h>
#include <stdlib.h>

struct meibo {
    char  name[20];
    char  danjo;
    int   postNo;
};

main()
{
  FILE *fin,*fout;
  char  s[50]; 
  int  i,x=0;
  
  struct meibo member[30];
  
  if((fin=fopen("SV.ADR","r")) == NULL){
      printf("入力ファイルがオープンできない");
      exit(1);
  }

  if((fout=fopen("ADR.SV","w")) == NULL){
      printf("出力ファイルがオープンできない");
      exit(1);
  }

  while(fgets(s,50,fin)!=NULL){
     i=0; 
     /* 名前の文字列を取得*/
     while(s[i]!=' '||s[i]!='\t'||s[i]!='\n'){
           /*member[x].name = s[i];*/
           i++;
     }
     /* スペース、タブ、改行の場合、文字数カウントアップ*/
     while(s[i]==' '||s[i]=='\t'||s[i]=='\n'){
           i++;                            
     }
     /* 男女別を取得*/ 
     while(s[i]!=' '||s[i]!='\t'||s[i]!='\n'){
          member[x].danjo = s[i];
           i++;
     }
     /* スペース、タブ、改行の場合、文字数カウントアップ*/
     while(s[i]==' '||s[i]=='\t'||s[i]=='\n'){
           i++;
     }
     /* 郵便番号を取得*/    
     while(s[i]!=' '||s[i]!='\t'||s[i]=='\n'){
          member[x].postNo = s[i];
          i++;
     }
     fprintf(fout,"%-10d\t%-20s\t%19c\n",member[x].postNo,member[x].name,member[x].danjo);
     x++;
     
  }
  
  fclose(fin);
  fclose(fout);
}



ですが、このロジックだと、/*member[x].name = s[i];*/
とコメントになっている部分でコンパイルエラーになってしまうのと、

構造体のname[20]の[20]を外せばコンパイルは通るのですが、結果は
限界超過みたいな感じでエラーとなってしまいます。
※セグメント例外(コアダンプしました)と表示される。

whileでスペースにあたるまでの文字列を構造体に入れ、
スペースの最中は文字数のカウントアップのみを行うということを
3回繰り返して、それぞれの構造体に入れるというロジックを作ったつもり
なのですが、うまくいきません。

お暇な方がいらっしゃいましたら、アドバイスをいただければ幸いです。


No.14814

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---REE(2004/06/21 17:05:25)


以下の質問の回答はないのですか?

No.14780の
>では、次のサンプルの場合、どういうところが参考になったのかを詳しく説明
>してみてください。
>(以下略)

No.14808の
>また、配列で求めてから、構造体に移すのではいけないのですか?

>fopenはよくて、fscanfは駄目ということであれば、どの関数なら使ってよいのでしょうか?
>基準を明確にしてください。

特に最後の質問は回答がないと、回答者側が、使ってはいけない関数を使ってしまったり、
または、それを避けるために使える関数を使わなかったりしてしまうことになり、非常に効率が悪いです。


No.14815

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/21 17:19:31)


>以下の質問の回答はないのですか?

No.14780の解答
申し訳ないですが、時間がありませんので、私にとって参考になった。
という解答でいいですか?

No.14808の
>>また、配列で求めてから、構造体に移すのではいけないのですか?
の解答

それはやりたくありません。

>>fopenはよくて、fscanfは駄目ということであれば、どの関数なら使ってよいのでしょうか?
>>基準を明確にしてください。

strtok、sscanf、fscanfは使いたくないです。構造体に入れる為の便利な関数以外はどの関数を使ってもいいです。
要はfgetsで1行を取り出し、その1行を、関数を使わないで構造体に入れ、できた構造体の要素を並べかえてfprintfでファイルに出力したいということです。

すいません。こんなところでよろしいでしょうか?


No.14817

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---REE(2004/06/21 17:58:41)


あなたのプログラムを参考に名前の部分だけ直してみました。
自分のプログラムとどこが違うか確認してみてください。

/* 名前の文字列を取得*/
while(s[i]!=' ' && s[i]!='\t' && s[i]!='\n' && i < 19){
    member[x].name[i] = s[i];
    i++;
}
member[x].name[i] = '\0';






No.14818

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/21 19:01:29)


では、郵便番号の部分を。
fgetsで読み込めるのはあくまで文字列としてですので、文字列を数値に変換してやる必要があります。
それにはatoi関数を使います(文字列末尾に空白文字があるとまずいかもしれない。そのときはstrtolを使う)。

    /* 郵便番号を取得*/
    member[x].postNo =  atoi(s+i);
    
使わないとしたら、こんな感じでしょうか。

    /* 郵便番号を取得*/
    member[x].postNo = 0;
    while(s[i]!=' '||s[i]!='\t'||s[i]=='\n'){
         member[x].postNo = member[x].postNo * 10 + s[i]-'0';
         i++;
    }



No.14819

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/21 20:28:46)


fgetsで読み込めるのはあくまで文字列としてですので、文字列を数値に変換してやる必要があります。
それにはatoi関数を使います(文字列末尾に空白文字があるとまずいかもしれない。そのときはstrtolを使う)。

いろいろありがとうございました。おかげでうまくいきました。
ですが、ちょっと質問があります。

member[x].postNo = atoi(s+i); で
やったらうまくいきませんでした。どうしてなのでしょう?


member[x].postNo = member[x].postNo * 10 + s[i]-'0';
この計算の詳しい意味を教えてもらえたら有難いのですが・・・・




No.14820

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ニタチ(2004/06/21 20:56:47)


>member[x].postNo = atoi(s+i); で
>やったらうまくいきませんでした。どうしてなのでしょう?

 もしかして、ループで何度もatoiをしていませんか?
     while(s[i]!=' '||s[i]!='\t'||s[i]=='\n'){
          member[x].postNo =  atoi(s+i);
          i++;
     }

という風に。もしこのようにしていれば、atoi()の動作を確認して、
どのようになるか考えてみてください。

>member[x].postNo = member[x].postNo * 10 + s[i]-'0';
>この計算の詳しい意味を教えてもらえたら有難いのですが・・・・

 "123" という文字列で考えると、はじめに
 member[x].postNO * 10 + '1'-'0' = 0 * 10 + 1 = 1 となり、
 次に、1 * 10 + '2'-'0' = 1 * 10 + 2 = 12 となり、
 その次に、12 * 10 + '3'-'0' = 12 * 10 + 3 = 123
 となります。
 ちょっとわかりづらいかな・・・。ではがんばってください。


No.14821

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ZAQ(2004/06/21 21:11:27)


>member[x].postNo = member[x].postNo * 10 + s[i]-'0';
この計算の詳しい意味を教えてもらえたら有難いのですが・・・・

アスキーコードというのを知っていますか?
これは文字を標準的なコードであらわしたものです。
文字「0」は10進数では「48」であらわされます。
文字「0」から10進数「48」を引けば10進数「0」が得られます。

>member[x].postNo * 10  ←これは桁数の計算です。

s[i]が一つ目が1、二つ目が0だとします。
member[x].postNo=0* 10 + 1-'0'
これで一回目のループでmember[x].postNoは1になります。
member[x].postNo=1* 10 + 0-'0'
これで二回目のループでmember[x].postNoは10になります。




No.14825

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---REE(2004/06/22 10:38:11)


>ですが、ちょっと質問があります。
>
>member[x].postNo = atoi(s+i); で
>やったらうまくいきませんでした。どうしてなのでしょう?

atoi関数は使ってよいのですか?



No.14828

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/22 13:49:49)


>atoi関数は使ってよいのですか?
それはかまいません。(s+i)のところがよく判らないのです。


それともう一つなのですが、
出力順を男子が先、女子が後といった感じで出したいと思い、
バブルソートのロジックを組みました。ですが、名前を入れ変える
ところでセグメント例外のエラーがでてしまいます。
どうしてなのかわかりません。こういう形しかバブルソートでやる
方法はないと思うのですが・・・

  /* バブルソート*/
  for (i=0; i<NUM-1; i++){
      for(x=NUM-1; x>i ; x--){
          /* 前の要素の方が小さい場合 */
          if ( member[x-1].danjo < member[x].danjo){
               /*順番を交換する*/
               temp  = member[x].danjo;        
               member[x].danjo   = member[x-1].danjo;
               member[x-1].danjo = temp;
  
               temp2 = member[x].postNo;
               member[x].postNo   = member[x-1].postNo;
               member[x-1].postNo = temp2;
                
               for( y=0; member[x].name[y] !='\0'; y++){
                   temp3[y] = member[x].name[y];
                   member[x].name[y] = member[x-1].name[y];
                   member[x-1].name[y] =  temp3[y];
               }
          }          
      }     
  }

  /* ファイル印字 */
  for(x=0;x<NUM;x++){
     fprintf(fout,"%-10d%-20s%-20c\n",member[x].postNo,member[x].name,member[x].danjo);
  }








No.14829

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/22 13:54:34)


連続ですいません。

バブルソートでつまずいているロジックの全貌です。
for( y=0; member[x].name[y] !='\0'; y++){
temp3[y] = member[x].name[y];
member[x].name[y] = member[x-1].name[y];
member[x-1].name[y] = temp3[y];
} の部分でエラーになります。



#include <stdio.h>
#include <stdlib.h>
#define NUM 10

struct meibo {
    char  name[20];
    char  danjo;
    int   postNo;
};

main()
{
  FILE *fin,*fout;
  char  s[256],temp,temp3[20]; 
  int  i,temp2,x=0,y;
  
  struct meibo member[30];
  
  if((fin=fopen("SV.ADR","r")) == NULL){
      printf("入力ファイルがオープンできない");
      exit(1);
  }

  if((fout=fopen("ADR.SV","w")) == NULL){

      printf("出力ファイルがオープンできない");
      exit(1);
  }

  while(fgets(s,256,fin)!=NULL){
     i=0; 
     /* 名前の文字列を取得*/
     while(s[i]!=' ' && s[i]!='\t'&& s[i]!='\n'&& i<19){
           member[x].name[i] = s[i];
           i++;
     }
     member[x].name[i] = '\0';

     /* スペース、タブ、改行の場合、文字数カウントアップ*/
     while(s[i]==' '||s[i]=='\t'||s[i]=='\n'){
           i++;                            
     }
     /* 男女別を取得*/ 
     while(s[i]!=' '&&s[i]!='\t'&&s[i]!='\n'){
          member[x].danjo = s[i];
           i++;
     }
     /* スペース、タブ、改行の場合、文字数カウントアップ*/
     while(s[i]==' '||s[i]=='\t'||s[i]=='\n'){
           i++;
     }
     /* 郵便番号を取得*/    
     member[x].postNo = 0;
     while(s[i]!=' '&&s[i]!='\t'&&s[i]!='\n'&& s[i]!='\0'){
          member[x].postNo = member[x].postNo * 10 + s[i] - '0'; 
          i++;
     }
     x++;
     
  }

  /* バブルソート*/
  for (i=0; i<NUM-1; i++){
      for(x=NUM-1; x>i ; x--){
          /* 前の要素の方が小さい場合 */
          if ( member[x-1].danjo < member[x].danjo){
               /*順番を交換する*/
               temp  = member[x].danjo;        
               member[x].danjo   = member[x-1].danjo;
               member[x-1].danjo = temp;
  
               temp2 = member[x].postNo;
               member[x].postNo   = member[x-1].postNo;
               member[x-1].postNo = temp2;
                
               for( y=0; member[x].name[y] !='\0'; y++){
                   temp3[y] = member[x].name[y];
                   member[x].name[y] = member[x-1].name[y];
                   member[x-1].name[y] =  temp3[y];
               }
          }          
      }     
  }

  /* ファイル印字 */
  for(x=0;x<NUM;x++){
     fprintf(fout,"%-10d%-20s%-20c\n",member[x].postNo,member[x].name,member[x].danjo);
  }

  fclose(fin);
  fclose(fout);

  return 0;
}




No.14832

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ニタチ(2004/06/22 14:48:57)


>member[x].postNo = atoi(s+i); で
>やったらうまくいきませんでした。どうしてなのでしょう?

>member[x].postNo = member[x].postNo * 10 + s[i]-'0';
>この計算の詳しい意味を教えてもらえたら有難いのですが・・・・

 ↑のことについてはわかりましたか?
 構造体は代入が可能ですので、わざわざメンバごとに入れ替える必要はありません。

 struct meibo temp;

  /* バブルソート*/
  for (i=0; i<NUM-1; i++){  ←  -1はいらない。
      for(x=NUM-1; x>i ; x--){
          /* 前の要素の方が小さい場合 */
          if ( member[x-1].danjo < member[x].danjo){
               /*順番を交換する*/
               temp  = member[x];      
               member[x] = member[x-1];
               member[x-1] = temp;
          }          
      }     
  }



No.14833

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/22 15:03:32)


member[x].name[y] !='\0'
だとmember[x].nameの文字列長しかコピーできません。
member[x-1].nameがもっと長い文字列の時に問題でしょう。
長いほうにあわせる必要があります。

あと関係ないですが、temp3はループ1回で1文字分しか使わないので配列である必要はないです。

一番重要なのは、構造体は
member[x] = member[x-1];
で一括代入できるという点です。あんまりがんばって書く必要はありません。



No.14834

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---あかま(2004/06/22 15:19:33)


>それはかまいません。(s+i)のところがよく判らないのです。
配列sのi番目の要素のアドレス(このHPの「配列とポインタ」のあたりを見る)。
郵便番号の最初の文字のアドレスをatoiに渡しています。

配列とアドレスの関係はこんな感じ。
s[0] == *(s+0) == *s
s[1] == *(s+1)
s[i] == *(s+i)

&s[0] == (s+0) == s
&s[i] == (s+i)

*(&s[i]) == *(s+i) == s[i]

わかります?



No.14835

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/22 15:32:29)


>一番重要なのは、構造体は
>member[x] = member[x-1];
>で一括代入できるという点です。あんまりがんばって書く必要はありません。

member[x] = member[x-1];
だけでやると退避ができないので、ソートがうまくいかないんですが・・・


No.14836

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---ニタチ(2004/06/22 15:40:40)


>>一番重要なのは、構造体は
>>member[x] = member[x-1];
>>で一括代入できるという点です。あんまりがんばって書く必要はありません。
>
>member[x] = member[x-1];
>だけでやると退避ができないので、ソートがうまくいかないんですが・・・

 あの〜・・・あかまさんは、一括代入ができるという例を出しただけで、
 ソートするためのコードを載せたわけではありません。
 一応、私が直したコードを載せたんですけど・・・。


No.14837

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---猛蹴士(2004/06/22 15:53:49)


> あの〜・・・あかまさんは、一括代入ができるという例を出しただけで、
> ソートするためのコードを載せたわけではありません。
> 一応、私が直したコードを載せたんですけど・・・。

すいません!! struct meibo temp; を宣言するのを
忘れていまして、何度やってもtempに代入するところでエラーに
なっていました。

きちんと宣言して、やったところ上手くいきました。本当に
ご迷惑おかけしました。そして、いろいろ教えていただいて
本当に勉強になりました。ありがとうございました。




No.14830

Re:入力ファイルから出力ファイルへ並び順を変更して出力したい
投稿者---REE(2004/06/22 14:30:31)


>strtok、sscanf、fscanfは使いたくないです。構造体に入れる為の便利な関数以外はどの関数を使ってもいいです。
>要はfgetsで1行を取り出し、その1行を、関数を使わないで構造体に入れ、できた構造体の要素を並べかえてfprintfでファイルに出力したいということです。

>>atoi関数は使ってよいのですか?
>それはかまいません。(s+i)のところがよく判らないのです。

上記の二つは矛盾していませんか?