C言語関係掲示板

過去ログ

No.1153 ファイル中の文字列の個数を数える

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

文字列の表示
投稿者---こういちろう(2004/06/18 02:53:59)


あるプログラムファイルを読み込みforやprintfなどの文字列の回数を数えたいのですが上手くいきません。
 個人的にはgetc(fin)で1文字をcに格納し配列sに保存、再びgetc()で調べていきアルファベット以外にたどり着いたら配列sが根にきて二分木を作成する。以下はアルファベットの長さを調べて次々と木を作っていくようにしたいのです。


#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define N 256

typedef struct node{
char data[N];
int number;
struct node *left,*right;
}*tree;

tree root;

FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *fp);
int getc(FILE *fp);
void initialize(tree *p);
tree search(tree *v,char *key,char *mac,int *j);
void insert(tree *p,char *x,int *i);
void print(tree p,FILE *fin,FILE *fout);
void input_out_file(char [],char [],FILE *fin,FILE *fout);
void copy_str(int,int *i,char []);

main(){
int c,i=0,f,j=0;
char s[256],infile[40],outfile[40],k[256];
FILE *fin,*fout,*fp;

input_out_file(infile,outfile,&(*fin),&(*fout));

initialize(&root);
while((c=getc(fin))!=EOF){
if(isalpha(c) && isspace(c)){
copy_str(c,&i,s);
}
else{
search(&root,s,k,&j);
strcpy(k,s);
}
}
putchar('\n');
print(root,&(*fin),&(*fout));
}
void initialize(tree *p){
*p=NULL;
}

tree search(tree *v,char *key,char *mac,int *j){
int x,m;

if(*v!=NULL){
x=strcmp(&(*key),&(*mac));
}

if(*v==NULL){
insert(&(*v),&(*key),&(*j));
}

else if(x==0){
((*v)->number)++;
}
else if(x < 0){
return search(&((*v)->left),&(*key),&(*mac),&(*j));
}
else if(x >0){
return search(&((*v)->right),&(*key),&(*mac),&(*j));
}

}

void insert(tree *p,char *x,int *j){
if(*p==NULL){
*p=(tree)malloc(sizeof(struct node));
(*p)->data[(*j)++]=*x;
(*p)->left=(*p)->right=NULL;
}
else if(*x<(*p)->data[*j]){
insert(&((*p)->left),&(*x),&(*j));
}
else{
insert(&((*p)->right),&(*x),&(*j));
}
}

void print(tree p,FILE *fin, FILE *fout){

if(p!=NULL){
print(p->left,fin,fout);
fprintf(fout,"%s",p->data);
fprintf(fout," %d\n",p->number+1);
print(p->right,fin,fout);
}
fclose(fin);
fclose(fout);
}


void input_out_file(char infile[],char outfile[],FILE *fin,FILE *fout){
printf("入力ファイル名:");
gets(infile);
printf("出力ファイル名:");
gets(outfile);
if((fin=fopen(infile,"r"))==NULL) {
printf("入力ファイルがオープンできません\n");
exit(1);
}
if((fout=fopen(outfile,"w"))==NULL) {
printf("出力ファイルがオープンできません\n");
exit(1);
}
}

void copy_str(int c,int *i,char s[]){
s[*i]=c;
(*i)++;
}


No.14719

Re:文字列の表示
投稿者---とおり(2004/06/18 03:16:13)


【掲示板ご利用上の注意】を目を凝らして、よく読んで下さい。
ある程度の長さのソースを示すなら、なおのこと。

>管理人さま
【掲示板ご利用上の注意】をもっとでっっかく示してみるのはいかがでしょうか?
あるいは、ちゃんと注意に従うと回答が得られやすいですよーと明示してみるとか…


No.14751

Re:文字列の表示
投稿者---管理人(2004/06/18 21:09:52)


>>管理人さま
>【掲示板ご利用上の注意】をもっとでっっかく示してみるのはいかがでしょうか?
>あるいは、ちゃんと注意に従うと回答が得られやすいですよーと明示してみるとか…

最近すっかりROM専門の管理人です。申し訳ありません。
とりあえず、「掲示板ご利用上の注意」を目一杯大きくしました。
(なんて、品のない…。悲しいけど仕方がない…。)

画面いっぱいに広がるので嫌でも読んでいただけるものと思います。
でも、常連の皆様には鬱陶しくてすみません。

これでしばらく様子を見たいと思います。
よろしくご理解お願いいたします。



No.14721

Re:文字列の表示
投稿者---YuO(2004/06/18 07:53:50)


>あるプログラムファイルを読み込みforやprintfなどの文字列の回数を数えたいのですが上手くいきません。

「うまくいかない」をちゃんと説明してください。
あなたの書いたプログラムは,あなたの思ったようには動いていないかもしれませんが,
あなたの書いたようには動いているはずです。


ざっと眺めて気になった点をいくつか。


>FILE *fopen(const char *filename, const char *mode);
>int fclose(FILE *fp);
>int getc(FILE *fp);

stdio.hをインクルードしているので,これらは不要です。


> input_out_file(infile,outfile,&(*fin),&(*fout));

&(*fin)はfinに等しいです。


> while((c=getc(fin))!=EOF){

finには値が設定されていません。


> if(isalpha(c) && isspace(c)){

isalphaの定義から,このif文の条件式は常に偽です。



No.14749

Re:文字列の表示
投稿者---こういちろう(2004/06/18 20:21:32)


掲示板の注意、大変申し訳ございません。

じつは以下のようにファイルに出力してるはずなんですがSegmation faultになってしまいます。


出力例:

printf 4
scanf 3

   ・
   ・
   ・
とまあこのように出力してるはずなんです。

一番疑問に思うことはファイルから文字を一文字ずつ読み込んで配列に書き込んでいきスペースや改行コードとかに出会ったら、一つの文字列として2分木を作成していく方法が僕がやっている方法でいいのかが疑問です。

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define N 256

typedef struct node{
char data[N];
int number;
struct node *left,*right;
}*tree;

tree root;

int fclose(FILE *fp);
int getc(FILE *fp);
void initialize(tree *p);
tree search(tree *v,char key,char mac,int *j);
void insert(tree *p,char x,int *i);
void print(tree p,FILE *fin,FILE *fout);
void input_out_file(char [],char [],FILE *fin,FILE *fout);
void copy_str(char,int *i,char []);

main(){

int c,i=0,f,j=0;
char s[256],infile[40],outfile[40],k[256];
FILE *fin,*fout,*fp;

printf("入力ファイル名:");
gets(infile);
printf("出力ファイル名:");
gets(outfile);
if((fin=fopen(infile,"r"))==NULL) {
printf("入力ファイルがオープンできません\n");
exit(1);
}
if((fout=fopen(outfile,"w"))==NULL) {
printf("出力ファイルがオープンできません\n");
exit(1);
}
initialize(&root);
while((c=fgetc(fin))!=EOF){
if(isalpha(c) && isspace(c)==0){
copy_str(c,&i,s);
}
else if(isspace(c)){
search(&root,&s,&k,&j);
strcpy(k,s);
}
}
putchar('\n');
print(root,fin,fout);
fclose(fin);
fclose(fout);
}

void initialize(tree *p){
*p=NULL;
}

tree search(tree *v,char *key,char *mac,int *j){ /*同じ文字列があったらnunberをインクリメント*/
int x,m;

if(*v!=NULL){
x=strcmp(&key,&mac);
}

if(*v==NULL){
insert(&(*v),key,&(*j));
}

else if(x==0){
((*v)->number)++;
}
else if(x < 0){
return search(&((*v)->left),key,mac,&(*j));
}
else if(x >0){
return search(&((*v)->right),key,mac,&(*j));
}

}

void insert(tree *p,char x,int *j){ /*2分木を作成していく*/
if(*p==NULL){
*p=(tree)malloc(sizeof(struct node));
(*p)->data[(*j)++]=x;
(*p)->left=(*p)->right=NULL;
}
else if(x<(*p)->data[*j]){
insert(&((*p)->left),x,&(*j));
}
else{
insert(&((*p)->right),x,&(*j));
}
}

void print(tree p,FILE *fin, FILE *fout){ /* ファイルに書き込んでいく*/

if(p!=NULL){
print(p->left,fin,fout);
fprintf(fout,"%s",p->data);
fprintf(fout," %d\n",p->number+1);
print(p->right,fin,fout);
}

}



void copy_str(char c,int *i,char s[]){ /*読込んだ文字を配列に格納*/
s[*i]=c;
(*i)++;
}





No.14752

Re:文字列の表示
投稿者---管理人(2004/06/18 21:15:10)


>こういちろうさん

上記、HTML変換ツールをお使いいただくと、ソースはこのように字下げされます。

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define   N    256

typedef struct node{
  char data[N];
  int number;
  struct node *left,*right;
}*tree;

tree root;

int fclose(FILE *fp);
int getc(FILE *fp);
void initialize(tree *p);
tree search(tree *v,char key,char mac,int *j);
void insert(tree *p,char x,int *i);
void print(tree p,FILE *fin,FILE *fout);
void input_out_file(char [],char [],FILE *fin,FILE *fout);
void copy_str(char,int *i,char []);

main(){

  int c,i=0,f,j=0;
  char s[256],infile[40],outfile[40],k[256]; 
  FILE *fin,*fout,*fp;

  printf("入力ファイル名:");
  gets(infile);
  printf("出力ファイル名:");
  gets(outfile);
   if((fin=fopen(infile,"r"))==NULL) {
      printf("入力ファイルがオープンできません\n");
      exit(1);
    }
   if((fout=fopen(outfile,"w"))==NULL) {
      printf("出力ファイルがオープンできません\n");
      exit(1);
    }
  initialize(&root);
  while((c=fgetc(fin))!=EOF){
    if(isalpha(c) && isspace(c)==0){
      copy_str(c,&i,s);
    }
    else if(isspace(c)){
      search(&root,&s,&k,&j);
      strcpy(k,s);
  }
  }
  putchar('\n');
  print(root,fin,fout);
  fclose(fin);
  fclose(fout);
}

void initialize(tree *p){        
  *p=NULL;
}

tree search(tree *v,char *key,char *mac,int *j){   /*同じ文字列があったらnunberをインクリメント*/
  int x,m;

  if(*v!=NULL){
    x=strcmp(&key,&mac);
  }

  if(*v==NULL){
    insert(&(*v),key,&(*j));
  }

  else if(x==0){
    ((*v)->number)++;
  }
  else if(x < 0){
    return search(&((*v)->left),key,mac,&(*j));
  }
  else if(x >0){
    return search(&((*v)->right),key,mac,&(*j));
  }

}

void insert(tree *p,char x,int *j){       /*2分木を作成していく*/
  if(*p==NULL){
    *p=(tree)malloc(sizeof(struct node));
    (*p)->data[(*j)++]=x;
    (*p)->left=(*p)->right=NULL;
  }
  else if(x<(*p)->data[*j]){
    insert(&((*p)->left),x,&(*j));
  }
  else{
    insert(&((*p)->right),x,&(*j));
  }
}

void print(tree p,FILE *fin, FILE *fout){    /* ファイルに書き込んでいく*/

  if(p!=NULL){
    print(p->left,fin,fout);
    fprintf(fout,"%s",p->data);
    fprintf(fout,"  %d\n",p->number+1);
    print(p->right,fin,fout);
  }
  
}



void copy_str(char c,int *i,char s[]){   /*読込んだ文字を配列に格納*/
   s[*i]=c;
   (*i)++;
}




No.14770

Re:文字列の表示
投稿者---こういちろう(2004/06/19 19:53:15)


すいません。ふと思ったのですが、

char s[256];
int i=0;

while((c=getchar())!=EOF){
if(isalpha(c))
s[i++]=c;
}

のように一文字ずつ読み込んだのをchar型の配列に一つ一つ格納していく事はできるのでしょうか??

gets(s)は使わない方法です。最終的にはファイルから一文字ずつ英字だけ読みこみたいので。。。。。



No.14771

Re:文字列の表示
投稿者---あかま(2004/06/19 20:30:57)



>のように一文字ずつ読み込んだのをchar型の配列に一つ一つ格納していく事はできるのでしょうか??
できます。提示されたソースで動くと思います。
文字列の最後に'\0'だけ加えるのを忘れずに。


No.14781

Re:文字列の表示
投稿者---こういちろう(2004/06/20 01:39:58)


返信レスありがとうございます。それをヒントに問題をやってみました。しかし85行目で左オペランドは左辺値でなければなりません。警告されてしまいます。どういうことなんでしょうか? 
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define   N    256

typedef struct node{
  char data[N];
  int number;
  struct node *left,*right;
}*tree;

tree root;

int fclose(FILE *fp);
int getc(FILE *fp);
void initialize(tree *p);
tree search(tree *v,char key,char mac);
void insert(tree *p,char x);
void print(tree p,FILE *fin,FILE *fout);
void input_out_file(char [],char [],FILE *fin,FILE *fout);

main(){

  int c,i=0,f,j=0;
  char s[256],infile[40],outfile[40],k[256]; 
  FILE *fin,*fout,*fp;

  printf("入力ファイル名:");
  gets(infile);
  printf("出力ファイル名:");
  gets(outfile);
   if((fin=fopen(infile,"r"))==NULL) {
      printf("入力ファイルがオープンできません\n");
      exit(1);
    }
   if((fout=fopen(outfile,"w"))==NULL) {
      printf("出力ファイルがオープンできません\n");
      exit(1);
    }

  initialize(&root);
  while((c=getc(fin))!=EOF){
    if(isalpha(c) && isalnum(c)==0){
      s[i++]=c;
    }
    else if(isalpha(c)==0 && isalnum(c)){
      search(&root,s,k);
      strcpy(k,s);
      i=0;
  }
  }
  putchar('\n');
  print(root,fin,fout);
  fclose(fin);
  fclose(fout);
}

void initialize(tree *p){
  *p=NULL;
}

tree search(tree *v,char key,char mac){
  int x,m;

  if(*v==NULL){
    insert(&(*v),key);
  }

  else if(strcmp(key,mac)==0){
    ((*v)->number)++;
  }
  else if(strcmp(key,mac) < 0){
    return search(&((*v)->left),key,mac);
  }
  else if(strcmp(key,mac) >0){
    return search(&((*v)->right),key,mac);
  }

}

void insert(tree *p,char x){
  if(*p==NULL){
    *p=(tree)malloc(sizeof(struct node));
    (*p)->data=x;
    (*p)->left=(*p)->right=NULL;
  }
  else if(x<(*p)->data){
    insert(&((*p)->left),x);
  }
  else{
    insert(&((*p)->right),x);
  }
}

void print(tree p,FILE *fin, FILE *fout){

  if(p!=NULL){
    print(p->left,fin,fout);
    fprintf(fout,"%s",p->data);
    fprintf(fout,"  %d\n",p->number+1);
    print(p->right,fin,fout);
  }
  
}



No.14785

Re:文字列の表示
投稿者---YuO(2004/06/20 04:10:43)


>しかし85行目で左オペランドは左辺値でなければなりません。警告されてしまいます。

その警告メッセージにダウト。
左オペランドは「変更可能な左辺値」でなければなりません,と警告すべきです。
#って,コンパイラに文句言ってもしょうがないですが。

左辺値とか変更可能な左辺値とかは,過去ログで探せば定義が見つかります。

    (*p)->data=x;

85行目とはここでしょうか?
であれば,(*p)->dataの型がちゃんとわかっていれば,
(*p)->dataが変更可能な左辺値ではないことはわかるはずです。



No.14794

Re:文字列の表示
投稿者---こういちろう(2004/06/20 16:29:28)


プログラムファイルを読み込みforやprintfなどの文字列の回数を数えてその回数をファイルに出力するプログラムの続きなんですが、今度は51行目にキャストなしにポインタから整数型への受け渡しがある。70,92,95行目に引数が互換ポインタではないと警告されてしまいます。

char型キャストの受け渡しで怒られるのはなぜでしょうか?
さっぱりです。

3日間このプログラムを考えてるのですが今だに解けないです。

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define   N    256

typedef struct node{
  char data[N];
  int number;
  struct node *left,*right;
}*tree;

tree root;
int *i;

int fclose(FILE *fp);
int getc(FILE *fp);
void initialize(tree *p);
tree search(tree *v,char key,char mac);
void insert(tree *p,char x,int *i);
void print(tree p,FILE *fin,FILE *fout);
void input_out_file(char [],char [],FILE *fin,FILE *fout);

main(){

  int c,f,j=0;
  char s[256],infile[40],outfile[40],k[256]; 
  FILE *fin,*fout,*fp;

*i=0;

  printf("入力ファイル名:");
  gets(infile);
  printf("出力ファイル名:");
  gets(outfile);
   if((fin=fopen(infile,"r"))==NULL) {
      printf("入力ファイルがオープンできません\n");
      exit(1);
    }
   if((fout=fopen(outfile,"w"))==NULL) {
      printf("出力ファイルがオープンできません\n");
      exit(1);
    }

  initialize(&root);
  while((c=getc(fin))!=EOF){
    if(isalpha(c) && isalnum(c)==0){
      s[j++]=c;
    }
    else if(isalpha(c)==0 && isalnum(c)){
      search(&root,s,k);
      strcpy(k,s);                          /* <-ここ*/
      j=0;
  }
  }
  putchar('\n');
  print(root,fin,fout);
  fclose(fin);
  fclose(fout);
}

void initialize(tree *p){
  *p=NULL;
}

tree search(tree *v,char key,char mac){
  int x,m;

  if(*v==NULL){
    insert(&(*v),key,&i);                 /*ここ*/
  }

  else if(strcmp(&key,&mac)==0){        /*ここもstrcmp(&,&) の&でキャストする意味がわからない*/
    ((*v)->number)++;
  }
  else if(strcmp(&key,&mac) < 0){
    return search(&((*v)->left),key,mac);
  }
  else if(strcmp(&key,&mac) >0){
    return search(&((*v)->right),key,mac);
  }

}

void insert(tree *p,char x,int *i){
  if(*p==NULL){
    *p=(tree)malloc(sizeof(struct node));
    (*p)->data[*i++]=x;
    (*p)->left=(*p)->right=NULL;
  }
  else if(x<(*p)->data[*i]){
    insert(&((*p)->left),x,&i);               /*ここ*/
  }
  else{
    insert(&((*p)->right),x,&i);              /*ここ*/
  }
}

void print(tree p,FILE *fin, FILE *fout){

  if(p!=NULL){
    print(p->left,fin,fout);
    fprintf(fout,"%s",p->data);
    fprintf(fout,"  %d\n",p->number+1);
    print(p->right,fin,fout);
  }
  
}



No.14797

Re:文字列の表示
投稿者---RAPT(2004/06/20 18:08:57)


ポインタが分かっていないようですが、それ以前に仕様がよく分からりません。
main()内の s, k という char[256]型の変数は一体何でしょうか?
初期化もされずに使用されていますが?

strcmp() は (const char *) 型を引数に取るが、key, mac は char 型。
char 型同士の比較は普通に =, < , > でできます。
文字列なら、仮引数の型を変更するべきだと思います。

解析を続けたけど、やっぱり何をしたいのか分かりませんでした。

「文字」と「文字列(文字の配列)」を明確に区別する必要があります。
# それにしても、tree *root; はポインタにする必要はないかと。
# tree root = NULL; で充分だと思う。
# struct node ** 型にすると、色々と面倒だし。 



No.14799

Re:文字列の表示
投稿者---とおり(2004/06/20 18:18:37)


RAPTさんが既に回答されてますが、補足というか。

> strcpy(k,s);

1つ目のエラーはこれじゃなくて、

> search(&root,s,k);

こちらでは?
まあ、ポインタの基礎を勉強し直す必要があるでしょうね…


No.14800

Re:文字列の表示
投稿者---あかま(2004/06/20 20:39:36)


>プログラムファイルを読み込みforやprintfなどの文字列の回数を数えてその回数をファイルに出力するプログラム

面白そうだったので、こんなんがしたいのかなーと思いつつ書いてみた。
アルファベットと数字のみを読み込むので、ファイルに2バイト文字が含まれていると多少変な出力に。

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define   N    256

typedef struct node{
  char data[N];
  int number;
  struct node *left,*right;
}*tree;

tree root;

void initialize(char *);
int insert(char *);
void print(tree ,FILE *fout);
tree new_node(char *s);

int get_token(char *token,FILE *fp){//アルファベットか数字で綴られたトークンを返す
    int i=0,c;
    
    for(;;){
        c=getc(fp);
        if(isalnum(c)){//アルファベットか数字のとき
            token[i] = c;
            i++;
        }
        else{//それ以外で
            if(i == 0){//空文字列のとき
                if(c == EOF) return 0;//ファイルが終了なら0を返す
                continue;//違うなら続ける
            }
            //空文字列でないときは
            token[i] = '\0';
            break;//ループを抜けて1を返す
        }
    }
    return 1;
}

tree new_node(char *s){//新しいノードを確保する
    tree p;
    p = (tree)malloc(sizeof(struct node));
    strcpy(p->data,s);
    p->number = 1;
    p->left = NULL;
    p->right = NULL;
    return p;
}

void initialize(char *s){
    root = new_node(s);
}

int insert(char *s){
    int i;
    tree p = root;
    
    for(;;){
        i = strcmp(p->data,s);
        if(i < 0){
            if(p->right == NULL){
                p->right = new_node(s);
                return 1;
            }
            p = p->right;
        }
        else if(i > 0){
            if(p->left == NULL){
                p->left = new_node(s);
                return 1;
            }
            p = p->left;
        }
        else{
            p->number++;
            return 0;
        }
    }
    
}

void print(tree p,FILE *fout){

  if(p!=NULL){
    print(p->left,fout);
    fprintf(fout,"%s",p->data);
    fprintf(fout,"  %d\n",p->number);
    print(p->right,fout);
  }
  
}

main(){
    
  char infile[40],outfile[40];
  char s[N]; 
  
  FILE *fin,*fout;
  
  printf("入力ファイル名:");
  gets(infile);
  printf("出力ファイル名:");
  gets(outfile);
  if((fin=fopen(infile,"r"))==NULL) {
      printf("入力ファイルがオープンできません\n");
      exit(1);
  }
  if((fout=fopen(outfile,"w"))==NULL) {
      printf("出力ファイルがオープンできません\n");
      exit(1);
  }
  
  if(get_token(s,fin) == 0) exit(0);
  initialize(s);
  
  while(1){
    if(get_token(s,fin) == 0) break;
    insert(s);
  }
  
  print(root,fout);
  fclose(fin);
  fclose(fout);
  return 0;
}



No.14803

Re:文字列の表示
投稿者---RAPT(2004/06/20 22:01:08)


malloc()されてるとfree()したくなりますな。

void DeleteTree(tree p)
{
  if(p == NULL){
    return;
  }
  DeleteTree(p->left);
  DeleteTree(p->right);
  free(p);
}