C言語関係掲示板

過去ログ

No.1047 単語の出現頻度をヒストグラムで表示

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

ファイル中の単語の区切りについて
投稿者---みゆき(2004/04/12 12:11:51)


学校で以下の様な課題が出たのですが、
「ファイルを入力として、単語の出現頻度を求めるプログラムを作成せよ。
単語は英字で始まる英数字の列とし、英数字以外の文字は単語の区切りとしてのみ考慮し、単語としては考えない。
頻度表はヒストグラムとして出力する事。」
ファイルの単語を読み込む際の区切りがスペースだけやコンマだけな
らfgetで一行読んでstrtokで分割するのですが
区切りの対象が多く上手くいきません…どのようにしたらいいのでしょうか?


No.13539

Re:ファイル中の単語の区切りについて
投稿者---nop(2004/04/12 12:36:57)


>ファイルの単語を読み込む際の区切りがスペースだけやコンマだけな
>らfgetで一行読んでstrtokで分割するのですが
>区切りの対象が多く上手くいきません…どのようにしたらいいのでしょうか?

isalnum()などを使って、区切り文字列を作成すればよいのでは?

No.13541

Re:ファイル中の単語の区切りについて
投稿者---みゆき(2004/04/12 14:21:29)


>isalnum()などを使って、区切り文字列を作成すればよいのでは?
isalnumは引数がint型になってますが文字なのでchar型を利用したいのですがどのように扱えばいいのでしょうか?ソースで例示していただくとありがたいです。

No.13542

Re:ファイル中の単語の区切りについて
投稿者---Cマニア(2004/04/12 14:53:43)


#include<stdio.h>
#include<ctype.h>

int main(void)
{
    char buff[] = {"abc@def,ghi.123*567"};
    int i;

    for( i = 0 ; buff[i] != '\0' ; i++ ){
        if( isalnum(buff[i]) ){
            printf("%c", buff[i]);
        }
    }

    return 0;
}

実行結果
abcdefghi123567


No.13543

Re:ファイル中の単語の区切りについて
投稿者---NykR(2004/04/12 14:55:32)


>>isalnum()などを使って、区切り文字列を作成すればよいのでは?
>isalnumは引数がint型になってますが文字なのでchar型を利用したいのですがどのように扱えばいいのでしょうか?

についてはこちら、
少し詳しい型変換の説明
char型を引数にとる標準関数はありませんが、int型を受け取る関数であれば char型をそのまま渡せばいいです。

あと、strtokは複数の文字を区切り文字に指定できるので、ファイルに含まれる文字の種類が限定してあれば、課題のプログラムはfgetsとstrtokの組み合わせで書けます。

No.13546

Re:ファイル中の単語の区切りについて
投稿者---みゆき(2004/04/12 15:30:31)


>char型を引数にとる標準関数はありませんが、int型を受け取る関数であれば char型をそのまま渡せばいいです。
大変参考になりました!!
>あと、strtokは複数の文字を区切り文字に指定できるので、ファイルに含まれる文字の種類が限定してあれば、課題のプログラムはfgetsとstrtokの組み合わせで書けます。
英数字以外を区切りたいのでソレ以外を全部列挙するわけにはいきませんよね・・・?

No.13547

Re:ファイル中の単語の区切りについて
投稿者---RiSK(2004/04/12 15:41:23)


>英数字以外を区切りたいのでソレ以外を全部列挙するわけにはいきませんよね・・・?

if (!isalnum(i)) {
  /* : */
}


でどう?

No.13549

Re:ファイル中の単語の区切りについて
投稿者---みゆき(2004/04/12 16:32:08)


>>英数字以外を区切りたいのでソレ以外を全部列挙するわけにはいきませんよね・・・?
>
>
if (!isalnum(i)) {
  /* : */
}

>
>でどう?
strtok(buf,!isalnum(i));なんてナシですよね?

No.13548

Re:ファイル中の単語の区切りについて
投稿者---NykR(2004/04/12 16:00:03)


>>あと、strtokは複数の文字を区切り文字に指定できるので、ファイルに含まれる文字の種類が限定してあれば、課題のプログラムはfgetsとstrtokの組み合わせで書けます。
>英数字以外を区切りたいのでソレ以外を全部列挙するわけにはいきませんよね・・・?

isalnumで判定できるような、英数字以外の文字はそれほど多くはありません。

"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "

この(ispunctかisspaceが真を返す文字で構成されている)文字列定数を第2引数に渡せばいいです。

#ファイルに多バイト文字が含まれている場合は使えませんが、そういうことを気にしなければならないような状況では、isalnumも使えない可能性があります。

No.13552

区切りについて
投稿者---みゆき(2004/04/12 16:50:41)


こんな感じで作成してみましたが(全く未完全ですが・・・)
うまくいきません・・・そもそもコレだと単語分け出来ませんね(汗)
どの様に改善すれば良いのでしょうか?
#include<stdio.h>
#include<ctype.h>
int main(void)
{
  FILE *fp;
  const char *seps[] ="#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ";
  const char *token;
  char buf[1024];
  char line[1024];
  int i,b;
  int a = 0;
  fp = fopen("text.txt","r");/*ファイルオープン*/
  fgets(buf,sizeof(buf),fp);/*ファイルの文字を配列に代入*/
  token = strtok(buf,seps);
  while(token != NULL){
    sscanf(token,"%s",&line);
    token =strtok(NULL,seps);
  }
  //for( b = 0 ; line[b] != '\0' ; b++ ){
  //printf("%c", line[b]);
  //}
}


No.13555

Re:区切りについて
投稿者---あかま(2004/04/12 18:10:49)


一文字ずつ読み込むと書きやすいかなーと思い単語抽出まで書いてみました。
とりあえずisalnumを使う方向で。
>単語は英字で始まる
は満たしてません。

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

int main(void){
    FILE *fp;
    char tango[128];
    int c,i;
    
    fp = fopen("text.txt","r");
    
    for(i=0;(c = getc(fp)) != EOF;){
        if(isalnum(c)){
            tango[i] = c;
            i++;
        }
        else{
            tango[i] = '\0';
            if(strlen(tango)) printf("%s\n",tango);
            i = 0;
        }
    }
    tango[i] = '\0';
    if(strlen(tango)) printf("%s\n",tango);
    
    fclose(fp);
    return 0;
}


No.13561

1文字づつとは盲点・・・
投稿者---みゆき(2004/04/12 18:42:39)


>一文字ずつ読み込むと書きやすいかなーと思い単語抽出まで書いてみました。
>とりあえずisalnumを使う方向で。
>>単語は英字で始まる
>は満たしてません。

なるほど!!文字列でなく単語で読んで行けば確かに分かりやすいですね♪
トライしてみます。

No.13574

Re:ファイル中の単語の区切りについて
投稿者---nop(2004/04/13 08:54:09)


>英数字以外を区切りたいのでソレ以外を全部列挙するわけにはいきませんよね・・・?

私の

>>isalnum()などを使って、区切り文字列を作成すればよいのでは?

は、まさにそのことを言っていた訳ですが?
手で列挙しても、プログラムで列挙しても何の問題もないはずですが?

No.13544

Re:ファイル中の単語の区切りについて
投稿者---RiSK(2004/04/12 15:03:00)


# 他の方々と重複していますが…

>isalnumは引数がint型になってますが文字なのでchar型を利用したい

/* C において文字は int 型 */
#include <stdio.h>

int main(void)
{
  printf("sizeof(char) == %u\n", (unsigned)sizeof(char));
  printf("sizeof(int) == %u\n", (unsigned)sizeof(int));
  printf("sizeof('a') == %u\n", (unsigned)sizeof('a'));

  return 0;
}


/* isalnum の使い方 */
#include <stdio.h>
#include <ctype.h>

int main(void)
{
  int i;

  puts("英数字文字");
  for (i = 0; i < 256; i++) {
    if (isalnum(i)) {
      putchar(i);
      putchar('\t');
    }
  }
  putchar('\n');

  return 0;
}


No.13557

どうも上手くいきません・・・
投稿者---みゆき(2004/04/12 18:12:11)


#include<stdio.h>
#include<ctype.h>
int main(void)
{
  FILE *fp;
  char *token;
  char buf[1024];
  char line[1024];
  char lin[1024];
  int i,b,c;
  int a = 0;
  fp = fopen("text.txt","r");/*ファイルオープン*/
  while(fgets(buf,sizeof(buf),fp) != NULL){/*ファイルの文字を配列に代入*/
    token = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ");
    strncpy(line, token, 128);
  }
  for( b = 0 ; line[b] != '\0' ; b++ ){
    printf("%c", line[b]);
  }
}

ここまでやったのですが、単語分けが出来ません・・・どうすればよいのでしょうか?
どなたかご教授お願いいたします。

No.13571

Re:どうも上手くいきません・・・
投稿者---RAPT(2004/04/13 00:36:19)


strtok()はループして使う。2回目以降の呼び出しは第一引数をNULLにする。
戻り値がNULLのとき、走査終了。そして次の行を読み込む。。。

No.13572

Re:どうも上手くいきません・・・
投稿者---ともじ(2004/04/13 00:58:54)


>strtok()はループして使う。2回目以降の呼び出しは第一引数をNULLにする。
>戻り値がNULLのとき、走査終了。そして次の行を読み込む。。。

ここもご参考にどうぞ。


No.13575

ヒストグラムに表示されません
投稿者---みゆき(2004/04/13 15:10:12)


皆さんのおかげでどうにか形にしたのですが上手く行きません
何処がわるいのでしょか?何が悪いか分からないため先に進めません(泣)
#include<stdio.h>
#include<ctype.h>

char *search(char *,char *);

int main(void)
{
  FILE *fp;
  char *key;
  char *p;
  char buf[1024];
  char line[1024];
  char lin[1024];
  int i,b,c;
  int d=1;
  int e=1;
  int a = 0;
  fp = fopen("text.txt","r"); /*ファイルオープン*/
  while(fgets(buf,sizeof(buf),fp) != NULL){ /*ファイルの文字を配列に代入*/
    if(e==1){
      key = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "); /*文字区切り*/
      strncpy(line, key, 128);
      p=search(buf,line);
      while (p!=NULL){
    if(d==1){
      printf("%s:",p);
      d++;
    }
    printf("*");/*ヒストグラムに*を表示*/
    p=search(p+strlen(line),line);
      }
    }
    printf("\n");
    d=1;
    e=2;
    key = strtok(NULL,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ");
    strncpy(line, key, 128);
    p=search(buf,line);
    while (p!=NULL){
      if(d==1){
    printf("%s:",p);
    d++;
      }
      printf("*");/*ヒストグラムに*を表示*/
      p=search(p+strlen(line),line);
    }
    printf("\n");
  }
  fclose(fp);/*ファイルを閉じる*/
}

char *search(char *buf,char *line)/*文字列の照合関数*/
{
  int m,n;
  char *p;
  m=strlen(buf);
  n=strlen(line);
  for(p=buf;p<=buf+m-n;p++){
    if(strncmp(p,line,n)==0)
      return p;
  }
  return NULL;
}



No.13576

Re:ヒストグラムに表示されません
投稿者---あかま(2004/04/13 16:45:12)


>皆さんのおかげでどうにか形にしたのですが上手く行きません
>何処がわるいのでしょか?何が悪いか分からないため先に進めません(泣)
質問する時は、どう上手く行かないかと書かないと答えようがないですよ。
タイトルだけの情報ではこちらも判断しかねます。

で、ヒストグラムに出力する以前に単語の切り出しは出来ていますか?
まず単語の出現頻度を集計しなければならないわけですから、ヒストグラムは一番最後です。
まずファイルの単語を読み込み。
読み込みついでにそれぞれの単語ごとにカウント。
そして最後にヒストグラムとして出力です。

まずは単語のカウントを行ってください。
プログラムのヒストグラムの部分はやり方の前提が間違ってますので、全て削除してしまったほうがいいです。

そして最後に
char *search(char *buf,char *line)/*文字列の照合関数*/
ですが、これは何をしているのでしょう?
文字列の照合はstrcmp(たぶんstrncmpでなくていい)でこんな複雑なことをしなくていいかと思います。

No.13579

動的な配列について
投稿者---みゆき(2004/04/14 03:18:47)


>まずファイルの単語を読み込み。
>読み込みついでにそれぞれの単語ごとにカウント。
>そして最後にヒストグラムとして出力です。

ファイルにある文字列を一つの配列(buf)に全ていれるには
while(fgets(buf,sizeof(buf),fp)!=NULL)
みたいにすれば良いとわかるのですがココから単語に分ける際に
key = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ");
strncpy(a, key, 128);
で次に
key = strtok(NULL,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ");
strncpy(b, key, 128);
を繰り返していけば配列に単語を区切って入れていけるのですが、
コレだとファイルの文字列に単語が幾つあるか不明なのが前提なので
単語の為の配列を幾つ用意していいかわかりません…
key = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r ");
strncpy(?, key, 128);
が繰り返される度に配列が動的に増えていくようにすることは可能なのでしょうか?無理ならどのようにすればよいのでしょうか?
コレが可能ならばstrcmpを使ってカウントしヒストグラムに出来そうなのですが…どなたかご教授をお願いいたします。





No.13580

Re:動的な配列について
投稿者---あかま(2004/04/14 06:41:59)


リスト構造あたりでしょうか。
http://www9.plala.or.jp/sgwr-t/c/sec15-5.html

もしくはreallocをつかってだんだんメモリ領域を増やしていくかです。
http://www9.plala.or.jp/sgwr-t/lib/realloc.html

リスト構造は慣れないとちょっと難しいですが、よく使うテクニックですのでこの際憶えてしまうといいかも。


No.13581

ループの脱出について
投稿者---みゆき(2004/04/14 14:01:23)


>リスト構造あたりでしょうか。
リスト構造を使用して以下の様に作成しましたが・・・
#include<stdio.h>
#include<ctype.h>

struct list{
  int kazu;/*単語の数*/
  char name[1024];/*単語*/
  struct list *next;/*次のデータへのポインタ*/
};

struct list *add_list(int kazu,char*name,struct list *head);/*リストにデータを登録*/
void show_list(struct list *p);
void free_list(struct list *p);

int main(void)
{
  FILE *fp;
  struct list *head;/*先頭ポインタ*/
  char *name;
  char buf[1024];
  char line[1024];
  char lin[1024];
  int b,c;
  int a = 0;
  int d = 0;
  int kazu = 1;
  fp = fopen("text.txt","r"); /*ファイルオープン*/
  printf("読み込んだ文字列;");
  while (fgets(buf,sizeof(buf),fp) != NULL){ /*ファイルの文字を配列に代入*/
    for( a = 0 ;buf[a] != '\0' ; a++ ){
      printf("%c", buf[a]);/*配列の中身を表示*/
    } 
  }
  printf("\n");
  name = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "); /*文字区切り*/
  strncpy(line, name, 128);
  if(isalpha(line[0]) != 0)    /*数字で始まる単語を弾く*/
  head = add_list(kazu,name,head); /*リストに単語を登録*/ 
  while(name != NULL){ ←ここの条件が悪いらしくSegmentation faultしてしまいます。
    name = strtok(NULL,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "); /*文字区切り*/
    strncpy(line, name, 128);
    if(isalpha(line[0]) != 0){   /*数字で始まる単語を弾く*/
    head = add_list(kazu,name,head); /*リストに単語を登録*/
    if(name != NULL)puts(name);
    }
  }
  show_list(head);
}

struct list *add_list(int kazu,char*name,struct list *head)    /*リストにデータを登録*/
{
  struct list *p;
  if((p=(struct list *)malloc(sizeof(struct list)))== NULL){      /*領域確保*/
    printf("malloc error\n");         /*エラー処理*/
    exit(1);                 /*強制終了*/
  }
  
  p->kazu = kazu;           /*単語の数登録*/
  strcpy(p->name,name);     /*単語名を登録*/
  
  p->next = head;       /*先頭ポインタを次ポインタに*/
  head = p;            /*新しい領域を先頭ポインタに*/
  
  return head;
}  
  
void show_list(struct list *p)
{
  while(p != NULL){
    printf("%d %s\n",p->kazu,p->name);
    p = p->next;    
  }
}

矢印の場所の条件をfor(a=0;a<7;a++)みたいに単語数だけ回せば上手く行きますが
単語数は毎回ファイルによりかわるのでコレでは駄目です・・・どの様にループ
を脱出すればよいのでしょうか?あぁ締め切りに間に合うかなぁ・・・(泣)

No.13582

Re:ループの脱出について
投稿者---NykR(2004/04/14 14:31:42)


forで書けばよりすっきりすると思いますし多分動きます。

#define PUNCT_AND_SPACE     "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "

    for ( name = strtok(buf, PUNCT_AND_SPACE);
          name != NULL ; name = strtok(NULL, PUNCT_AND_SPACE)
        ) {
        if( !isalpha(name[0]) ) {
            continue;
        }
        head = add_list(kazu,name,head);
    }


No.13586

Re:ループの脱出について
投稿者---NykR(2004/04/14 15:05:57)


抜けてた
#define PUNCT_AND_SPACE     "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "

    for ( name = strtok(buf, PUNCT_AND_SPACE);
          name != NULL ; name = strtok(NULL, PUNCT_AND_SPACE)
        ) {
        if( !isalpha(name[0]) ) {
            continue;
        }
        head = add_list(kazu,name,head);
        puts(name);
    }

それから

> forで書けばよりすっきりすると思いますし多分動きます。

forで書けばよりすっきりすると思いますし、以下のようにすれば多分動きます。

No.13589

Re:ループの脱出について
投稿者---みゆき(2004/04/14 15:17:37)


変更してみましたがやはり実行結果は
読み込んだ文字列;abc defg8 3hij,,kl45m/good abc abcnew def3g
abc
defg8
kl45m
good
abc
abcnew
def3g
1 def3g
1 abcnew
1 abc
1 good
1 kl45m
1 defg8
1 abc
0
Segmentation fault
となってしまいます・・・リスト構造のポインタを渡すあたりが違うのでしょうか?

No.13592

Re:ループの脱出について
投稿者---NykR(2004/04/14 15:40:13)


あなたが作ったリストには、“末尾”が存在しないのです。
最後の要素の メンバ “next”には、NULLでもなく、struct list型オブジェクトへのポインタでもない、意味のない値が入っています。
ですから、show_listで p が最後の要素の次を指していても、

while(p != NULL){

のところで引っかからず、次のprintf()が実行されて、
実際には p はstruct list型のオブジェクトを指していませんから、
pを間接参照するところで(だと思う) segmentation違反になるのです。

とりあえず、headをNULLで初期化しておけば大丈夫でしょう。

# コンパイルするときに-Wallオプション(もしあれば)をつけた方がいいと思う。unused variableが多いし

No.13583

Re:ループの脱出について
投稿者---nop(2004/04/14 14:35:14)


>name = strtok(buf,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "); /*文字区切り*/
>strncpy(line, name, 128);
>if(isalpha(line[0]) != 0) /*数字で始まる単語を弾く*/
>head = add_list(kazu,name,head); /*リストに単語を登録*/
>while(name != NULL){ ←ここの条件が悪いらしくSegmentation faultしてしまいます。
> name = strtok(NULL,"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r "); /*文字区切り*/
> strncpy(line, name, 128);
> if(isalpha(line[0]) != 0){ /*数字で始まる単語を弾く*/
> head = add_list(kazu,name,head); /*リストに単語を登録*/
> if(name != NULL)
> puts(name);
> }
>}

name = strtok( buf, "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r " ); /* 文字区切り */

while( name!=NULL )
{
strncpy( line, name, 128 );

if( isalpha(line[0])!=0 ) /* 数字で始まる単語を弾く */
{
head = add_list( kazu, name, head ); /* リストに単語を登録 */
if( name!=NULL )
{
puts(name);
}
}
name = strtok( NULL, "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r " ); /* 文字区切り */
}


こんなんでどう?

No.13585

Segmentation faultから脱出したいです。
投稿者---みゆき(2004/04/14 14:56:40)


おっしゃる通りに以下直しました
#include<stdio.h>
#include<ctype.h>

struct list{
  int kazu;/*単語の数*/
  char name[1024];/*単語*/
  struct list *next;/*次のデータへのポインタ*/
};

struct list *add_list(int kazu,char*name,struct list *head);/*リストにデータを登録*/
void show_list(struct list *p);
void free_list(struct list *p);

int main(void)
{
  FILE *fp;
  struct list *head;/*先頭ポインタ*/
  char *name;
  char buf[1024];
  char line[1024];
  char lin[1024];
  int b,c;
  int a = 0;
  int d = 0;
  int kazu = 1;
  fp = fopen("text.txt","r"); /*ファイルオープン*/
  printf("読み込んだ文字列;");
  while (fgets(buf,sizeof(buf),fp) != NULL){ /*ファイルの文字を配列に代入*/
    for( a = 0 ;buf[a] != '\0' ; a++ ){
      printf("%c", buf[a]);/*配列の中身を表示*/
    } 
  }
  printf("\n"); 
  name = strtok( buf, "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r " ); /* 文字区切り */
  while( name!=NULL )
    {
      strncpy( line, name, 128 );
      
      if( isalpha(line[0])!=0 ) /* 数字で始まる単語を弾く */
    {
      head = add_list( kazu, name, head ); /* リストに単語を登録 */
      if( name!=NULL )
        {
          puts(name);
        }
    }
      name = strtok( NULL, "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n\t\v\f\r " ); /* 文字区切り */
    }
  show_list(head);
  free_list(head);
}

struct list *add_list(int kazu,char*name,struct list *head)    /*リストにデータを登録*/
{
  struct list *p;
  if((p=(struct list *)malloc(sizeof(struct list)))== NULL){      /*領域確保*/
    printf("malloc error\n");         /*エラー処理*/
    exit(1);                 /*強制終了*/
  }
  
  p->kazu = kazu;           /*単語の数登録*/
  strcpy(p->name,name);     /*単語名を登録*/
  
  p->next = head;       /*先頭ポインタを次ポインタに*/
  head = p;            /*新しい領域を先頭ポインタに*/
  
  return head;
}  
  
void show_list(struct list *p)
{
  while(p != NULL){
    printf("%d %s\n",p->kazu,p->name);
    p = p->next;    
  }
}

void free_list(struct list *p) /*リストの解放*/
{
  struct list *p2;
  while(p != NULL){
    p2 = p->next;
    free(p);
    p = p2;
  }
}


と修正して実行してみた結果
読み込んだ文字列;abc defg8 3hij,,kl45m/good abc abcnew def3g
abc
defg8
kl45m
good
abc
abcnew
def3g
1 def3g
1 abcnew
1 abc
1 good
1 kl45m
1 defg8
1 abc
0
Segmentation fault
となってしまいます・・・どこでいったい引っかかっているのでしょう?(泣)

No.13594

Re:Segmentation faultから脱出したいです。
投稿者---nop(2004/04/14 15:47:14)


>となってしまいます・・・どこでいったい引っかかっているのでしょう?(泣)

デバッガで追ってみましたか?

ポインタが指している先が正しいオブジェクトを指しているか?
自分が思っているオブジェクトを指しているか?

と言う辺りに重点を置いてデバッガで追ってみれば、
どこで起こっているのかわかるはずですよ?

No.13595

Re:Segmentation faultから脱出したいです。
投稿者---あかま(2004/04/14 15:52:50)


>となってしまいます・・・どこでいったい引っかかっているのでしょう?(泣)
まぁ、ぶっちゃけ

struct list *head=NULL;/*先頭ポインタ*/

に直すだけなんだけどね。
ポインタはドツボにハマると時間喰うから;;
これも修行です。耐えて!
自分でがんばった分、力がつきます。


No.13596

Re:Segmentation faultから脱出したいです。
投稿者---あかま(2004/04/14 16:19:31)


あ、あと気になった点がいくつか。
while (fgets(buf,sizeof(buf),fp) != NULL){ /*ファイルの文字を配列に代入*/
    for( a = 0 ;buf[a] != '\0' ; a++ ){
      printf("%c", buf[a]);/*配列の中身を表示*/
    } 
  }
これはwhileの閉じる括弧の位置が違う。閉じ括弧をshow_list(head);の前に持ってけばOK。
これだとファイルの一番最後の行しか分割できないです。
あとforでグリグリ一文字ずつ表示するのではなくて
printf("%s\n",buf);
とかすれば楽なんじゃ?

それから、まだ作ってないだけだと思いますがすでに登録してあるか調べるsearch関数が必要が必要ですね。
strcmpで簡単です。


で、あとは細かいんですが、
strncpy( line, name, 128 );
で単語の長さを128文字に制限してる割に
構造体ではchar line[1024];と1024文字になってたり。
こういうのは

#define TANGO_MAX 128

char line[TANGO_MAX];/*単語*/
strncpy( line, name, TANGO_MAX );

とかしとくと後々変更が楽で便利です。


add_list( kazu, name, head );ですが
kazuは1に決まってますからわざわざ引数で取らないで
struct list *add_list(char*name,struct list *head)    /*リストにデータを登録*/
{
  -省略-
  p->kazu = 1;           /*単語の数登録*/
  -省略-
  return head;
} 
の方がいいですよ。
私も前はこういう拡張性?を気にして色々書いてたんですが、意味があったことはなかったです(泣
ただ複雑になって読みにくくなるだけだった…

そして最後に、使わなくなった変数を地道に消していきましょう。

がんばってー。もう出来たも同然です!


No.13600

Re:Segmentation faultから脱出したいです。
投稿者---みゆき(2004/04/15 00:05:34)


あかまさんありがとう御座います!!締め切りまで時間ないので今夜は徹夜で頑張ります!!詳しくて参考になりました!

No.13598

Re:ファイル中の単語の区切りについて
投稿者---かずま(2004/04/14 21:13:26)


> ファイルの単語を読み込む際の区切りがスペースだけやコンマだけな
> らfgetで一行読んでstrtokで分割するのですが
> 区切りの対象が多く上手くいきません…どのようにしたらいいのでしょうか?

scanf を使うという手もあります。
typedef struct Word { char *word; int count; struct Word *next; } Word;

Word *add(Word *head, const char *word)
{
    Word *p;
    for (p = head; p; p = p->next)
        if (!strcmp(p->word, word)) return p->count++, head;
    p = malloc(sizeof(Word));
    if (p) p->count = 1, p->next = head, p->word = strdup(word);
    if (!p || !p->word) puts("out of memory"), exit(1);
    return p;
}

int main(void)
{
    Word *p = NULL, *t;  char word[256];  FILE *fp = stdin;

    while (fscanf(fp, "%*[^a-zA-Z]"), fscanf(fp, "%255[a-zA-Z0-9]", word) == 1)
        p = add(p, word);
    while (p)
        printf("%5d %s\n", p->count, p->word),
        t = p, p = p->next, free(t->word), free(t);
    return 0;
}