C言語関係掲示板

過去ログ

No.594.メモ帳を読み込んでソートするプログラム

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

メモ帳を読み込んでソートするプログラム
投稿者---C++(2003/03/30 05:13:43)


エディタ(メモ帳)で

13  氏名
24  氏名
18  氏名
30  氏名

を書いてファイル名を”data.txt”とします。
読み込むにはfp = fopen( "data.txt", "r")を使ってください。
このデータを使って昇順に並び変えるプログラムを教えてください。
どんなソートを使ってもかまいません。
お願いします。

No.5653

Re:メモ帳を読み込んでソートするプログラム
投稿者---はお(2003/03/31 13:13:12)


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

 main()
{
    int i,j;
    char data[4][256];
    char dummy[256];

    FILE *fp;

    if ( (fp=fopen("data.txt","w")) != NULL )
    {
        fgets( data[0], 256, fp );
        fgets( data[1], 256, fp );
        fgets( data[2], 256, fp );
        fgets( data[3], 256, fp );

        for ( i = 0; i < 3; i++ )
        {
            for ( j = i; j < 4;j++ )
            {
                if ( (strcmp( data[i], data[j] )) > 0 )
                {
                    strcpy( dummy, data[i] );
                    strcpy( data[i], data[j]);
                    strcpy( data[j], dummy);
                }
            }
        }

        fclose(fp);
    }
    else
    {
        printf("ファイルオープンエラー\n");
    }
}


No.5656

Re:メモ帳を読み込んでソートするプログラム
投稿者---麗(2003/03/31 18:33:23)


ちょっと長くなってしまいましたが。

#include <stdio.h>

typedef struct node_ {
  int key;
  char name[BUFSIZ];
  struct node_ *next;
} node_t;

node_t head;

void
insert(int key, const char *name)
{
  node_t *pnext = head.next, *pprev = &head;

  while (NULL != pnext && (key > pnext->key)) {
    pprev = pnext;
    pnext = pnext->next;
  }

  {
    node_t *p = (node_t *)malloc(sizeof(node_t));
    if (NULL == p) {
      fprintf(stderr, "malloc err.\n");
      return;
    }
    p->key = key;
    snprintf(p->name, sizeof(p->name), name);

    p->next = pnext;
    pprev->next = p;
  }
}

int
main(int argc, char *argv[])
{
  char buf[BUFSIZ];
  FILE *fpr = NULL;

  head.next = NULL;

  if (2 != argc) {
    fprintf(stderr, "cmd arg err.\n");
    return 1;
  }

  fpr = fopen(argv[1], "r");
  if (NULL == fpr) {
    fprintf(stderr, "fopen err.\n");
    return 1;
  }

  while (NULL != fgets(buf, sizeof(buf), fpr)) {
    int tmpKey;
    char tmpName[BUFSIZ];

    if (2 != sscanf(buf, "%d%s", &tmpKey, tmpName)) continue;
    insert(tmpKey, tmpName);
  }

  {
    node_t *ptr;
    for (ptr = head.next; ptr != NULL; ptr = ptr->next) {
      printf("%-8d %s\n", ptr->key, ptr->name);
      free(ptr);
    }
  }
  fclose(fpr);
  return 0;
}


No.5657

Re:メモ帳を読み込んでソートするプログラム
投稿者---C++(2003/03/31 22:56:19)


皆さんありがとうございました。
大変勉強になりました。

No.5667

Re:メモ帳を読み込んでソートするプログラム
投稿者---shelly(2003/04/02 11:51:03)


> snprintf(p->name, sizeof(p->name), name);

この書き方危ないですよ。
nameの中に「%s」とかが含まれてたりしたら・・・


No.5668

了解です。
投稿者---麗(2003/04/02 12:10:21)


>nameの中に「%s」とかが含まれてたりしたら・・・

御意。
strncpy(p->name, name, sizeof(p->name));
でどうでしょう?
# strcpy系関数が要る理由がわかりました(汗)。

他にもヘッダファイルのインクルードを忘れたり…。

No.5669

Re:了解です。
投稿者---shelly(2003/04/02 12:22:05)


>strncpy(p->name, name, sizeof(p->name));
>でどうでしょう?

nameの文字列長がp->nameのバッファより大きかったら?

No.5670

strncpyって'\0'を付けてくれない?
投稿者---麗(2003/04/02 12:38:41)


>nameの文字列長がp->nameのバッファより大きかったら?

nameの内容が削れます…って
ひょっとしてstrncpyって文字幅越えたとき
自動的に'\0'を付けてくれない、ということですか?

うーむ。調べます。

No.5671

strncpyって'\0'を付けてくれない!
投稿者---麗(2003/04/02 12:52:31)


私のところのstrncpyは以下のように実装されていました。

char *
strncpy(dst, src, n)
  char *dst;
  const char *src;
  register size_t n;
{
  if (n != 0) {
    register char *d = dst;
    register const char *s = src;

    do {
      if ((*d++ = *s++) == 0) {
        /* NUL pad the remaining n-1 bytes */
        while (--n != 0)
          *d++ = 0;
        break;
      }
    } while (--n != 0);
  }
  return (dst);
}


'\0'ターミネートなんてしてくれないのですね。
(実装に基づくことで仕様/規格がどうなっているかはわかりませんが…)

となると、先ほど書いたstrncpyだけでは駄目で

strncpy(p->name, name, sizeof(p->name));
p->name[sizeof(p->name)-1] = '\0';


とすれば…いいのでしょうか?
他に良い手がありそうな、なさそうな。

No.5672

Re:strncpyって'\0'を付けてくれない!
投稿者---shelly(2003/04/02 13:10:09)


自分は先に0で埋めることが多いです。
memset(p->name, '\0', sizeof(p->name));
strncpy(p->name, name, sizeof(p->name) - 1);
無駄な事して遅くなってるのは承知の上です。
一回綺麗に埋めといたほうがなんか安心するんです。
速度にシビアな時にはお勧めできません。

#その前にmallocじゃなくてcalloc使うかな。


No.5674

Re:strncpyって'\0'を付けてくれない!
投稿者---麗(2003/04/02 17:17:02)


>strncpy(p->name, name, sizeof(p->name) - 1);

strncpyの第三引数で予め1引いておくのに
ショックを受けました。確かにその方が簡素ですね。

>#その前にmallocじゃなくてcalloc使うかな。

!!
私のところみたいに'\0' == 0な環境なら
node_t *p = (node_t *)calloc(1, sizeof(node_t));
strncpy(p->name, name, sizeof(p->name) - 1);

と書けますね。簡素です。

御指摘ありがとうございました。
# 指摘されることから学べるのでいい感じです。

No.5675

Re:strncpyって'\0'を付けてくれない!
投稿者---通りすがり(2003/04/02 18:14:33)


>私のところみたいに'\0' == 0な環境なら

どうでもいいことですが、
'\0' != 0 な環境は存在しないかと。
'\5' == 5ですし、
'\x20' == 0x20ですから。

No.5677

'\0'について
投稿者---麗(2003/04/02 18:52:28)


> \0' != 0 な環境は存在しないかと。

え!
そうなのですか?
'\0'は文字列を終端する文字であって
実際どのような値かは環境に依存するものと思っていました。
# だったら何で0と'\0'を区別するのだろう?
# うーん…。

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

No.5679

Re:'\0'について
投稿者---麗(2003/04/02 19:07:55)


となると…

char string[LEN] = {0, };

と書いておけばLENより小さい文字列を
このstring配列に入れる場合
'\0'終端を意識しなくても良い、となりますか?

…便利かもしれない。
# スレッドの頭から見たら
# 内容がかなりズレてきたな。

No.5680

Re:'\0'について
投稿者---通りすがり(2003/04/02 19:34:18)


>char string[LEN] = {0, };
>と書いておけばLENより小さい文字列を
>このstring配列に入れる場合
>'\0'終端を意識しなくても良い、となりますか?

なりますね。
文字列の終端としての0ですから
char string[LEN] = {'\0', };
のほうがいいかもしれません。
でもなるべく終端は意識しましょう。

No.5688

Re:'\0'について
投稿者---麗(2003/04/03 12:34:08)


'\0'と0は等しいけれども慣習によって
書き方をかえているようですね。
# 慣習って本に書いてあるのかな…?

些細なことなのかもしれませんが
勉強になりました。

>でもなるべく終端は意識しましょう。

御意。

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