• ベストアンサー

ファイル読み込みとmap処理

Visual C++ 2008 Express Edition 環境です。 入力テキストファイルを読み込み、空白で単語を区切り、単語すべてをmapにいれるという処理のプログラムを書こうとしています。 perlでいうところのsplit, 配列へのpushをC++でstrtokとmapでならかけると思いました。 入力ファイルは input1.txt--------------- cat dog mice human mosquito beetle spider ------------------------- プログラムは #include <stdio.h> #include<iostream> #include <map> #include <vector> int main( ) { FILE *input_file1; input_file1 = fopen("input1.txt", "r"); char str[256]; char *token; std::vector<char *> my_vector; // while (fgets(str, 256, input_file1) != NULL) { token = strtok( str , " " ); while( token != NULL ){ my_vector.push_back(token) ; printf("%s\n",token); token = strtok( NULL , " " ); } } printf("starting vector loop\n"); std::vector<char *>::iterator it = my_vector.begin(); // while( it != my_vector.end() ) // { printf("%s\n",*it); ++it; // } fclose(input_file1); return 0; } というふうにしました。 cat dog mice human mosquito beetle spider というような出力がなされるものと思ったのですが、実行してみると mapを使ったループ(全要素)出力は mosquito uito le mosquito beetle spider というふうに出力されてしまいます。 strtokで単語を分ける部分は問題なく出力で確認できるので、問題はmapの作り方やポインタだと思うのですが原因がわかりません。 問題点、解決策がお分かりになる方、よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • koko_u_u
  • ベストアンサー率18% (216/1139)
回答No.1

map 関係ないですよね。 直接的な原因は strtok で得られたポインタが str 配列の位置を指しているので、行を読むたびに str の中身は書き換えられているためです。 ポインタを vector に入れるのではなくて、文字列をコピーして入れるように変更しましょう。 また、空白で区切られているなら、ファイルから ifstream を作成して operator>> で読み込んだ方が楽だと思います。

hydrozoa
質問者

補足

ありがとうございます。 >ポインタを vector に入れるのではなくて、 >文字列をコピーして入れるように変更しましょう。 strtokのあつかいがまだよくわかっていないのですが、 トークンをstringにコピーというのは token = strtok( NULL , " " ); std::string mojiretu ; mojiretu = token; my_vector.push_back(mojiretu) ; このようにするのでしょうか?

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

それだと my_vector を std::vector<char *> ではなく std::vector<std::string> で定義することになりますよね. で, そうなら実は my_vector の定義を変えればいいだけだと思います. std::string のコンストラクタは push_back で自動的に呼び出されるんじゃないかな.

hydrozoa
質問者

補足

アドバイスありがとうございます。 std::vector<std::string> my_vector; std::string str1 = "*token" ; my_vector.push_back(str1) ; としてみたのですが、 出力が(null)となってしまいます。 perlで非常に適当にやっていたことがC++では私にとっては非常に難しく混乱していますが、もうすこし粘ってみます。

関連するQ&A

  • 次のソースの使い方(strtok()関数)

     次のソースプログラムについてです。 (“□”は、タブを表します) ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ #include <stdio.h> #include <stdlib.h> /* EXIT_SUCCESS */ #include <string.h> /* strtok() */ int main(void) { □int i, n; □char str[10], *token1, *token2; □scanf("%d", &n); □for (i=0; i<n; i++) { □□scanf("%s", str); □□token1 = strtok(str, ","); □□token2 = strtok(NULL, ","); □□printf("hello = %s , world = %s\n" ,token1 ,token2); □} □return EXIT_SUCCESS; } ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆  これを実行すると、入力待ち画面になって、何を入力すれば何が得られるのか、てんで分からないのですが、どなたか、このプログラムの使い方と意味について、解説をお願いします。  ちなみに、“1”を入力した後、[Ctrl]+[c]で抜けると、結果は、 ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ hello = ヒヒz@俳・, world = (null)◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ となりました。

  • ファイルの入出力を行っての文字列反転

    入力した文字列を反転させて出力したいのですが どうしたらよいでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> /* 定数 */ #define DELIMITER "/ ," /* 区切り文字 */ int main(void) { FILE *fin,*fout; char infile[40],outfile[40],s[256],s2[256]; char *token; char *strch[50]; int count = 0; int i; printf("入力ファイル名="); gets(infile); printf("出力ファイル名="); gets(outfile); if( (fin=fopen(infile,"r"))==NULL) { /* 入力ファイルオープン */ printf("入力ファイルがオープンできません\n"); exit(EXIT_FAILURE); } if( (fout=fopen(outfile,"w"))==NULL) { /* 出力ファイルオープン */ printf("出力ファイルがオープンできません\n"); exit(EXIT_FAILURE); } while(fgets(s,256,fin)!=NULL) { /* 入力ファイルから読み込んだデータを */ token = strtok(s, DELIMITER); while (token != NULL) { strch[count] = token; token = strtok(NULL, DELIMITER); count++; } for(i = count; i > 0; i--) { strcat(s2, strch[i]); } fputs(s2,fout); /* 出力ファイルに書き込み */ } fclose(fin); /* 入力ファイルクローズ */ fclose(fout); /* 出力ファイルクローズ */ return 0; }

  • fgetsで読み込んだ値のvector処理

    Visual C++ 2008でc++プログラミングの勉強をしています。 ファイルから文字列をfgetsで読み込み、vectorにいれる処理をプログラミングしようとしているのですが、うまくいきません。 input.txt------------------ sumday monday tuesday ------------------------- このような入力ファイルをfgetsで読み込み、各行を文字列としてvectorにpush_backし、 読み込みが終わった後にvectorの全要素をループで出力するというシンプルなものなのですが、以下のようにコーディングしました。 #include <stdio.h> #include <stdlib.h> #include <vector> int main(void){ using namespace std; FILE *fp; fp = fopen("input.txt","r"); std::vector<char *> my_vector; char buff[16]; while(fgets(buff, 256, fp) != NULL) { char copy_of_buff[16]; std::strcpy(copy_of_buff, buff); my_vector.push_back(copy_of_buff); printf("output from fgets..... %s \n", copy_of_buff); } vector<char *>::iterator it = my_vector.begin(); // while( it != my_vector.end() ) // { printf("output from vector.... %s \n", *it); ++it; // } fclose(fp); return 0; } 以下のような出力がなされるものと思っていたのですが、 outputs from fgets .... sunday outputs from fgets .... monday outputs from fgets .... tuesday output from vector .... sunday output from vector .... monday output from vector .... tuesday 実際は以下のように、vectorからの出力分がすべて最後にpush_backした"tuesday"となりました。 outputs from fgets .... sunday outputs from fgets .... monday outputs from fgets .... tuesday output from vector .... tuesday output from vector .... tuesday output from vector .... tuesday fgetsしたあとの処理が問題だと思うのですが、原因がよく分かりません。非常に基本的なことだと思うのですがwebで調べてもいまいちわかりません。 原因が分かる方、よろしくお願いします。

  • 大規模データの処理について困っています

    掲題の通り、大規模データの処理で悩んでおります。 行ベクトル150万、列ベクトル14のCSVファイルを読み込もうとしているのですが、データ数が10万以上になるとVisual C++が勝手に動作を停止してしまいプログラムを実行することができません。 具体的には、CSVファイル上の4列目に記載されている都道府県名のデータを配列で取り、画面に表示しようと、次のようなプログラムを書いているのですが、 #include<stdio.h> #include<string.h> #include<stdlib.h> #define FNAME "data.csv" #define NUM 10000 int main(void) { FILE *fp; char buf[256]; char *p_token; char dat[14][100]; int n; int i; long int j; char *place[NUM][15]; place[NUM][15]=(char*)malloc(sizeof(char)*NUM); fp = fopen(FNAME,"r"); if (fp == NULL) { printf("ファイルをオープンできませんでした\n"); return 0; } for(j=0;j<=NUM;j++){ fgets(buf,256,fp) !=NULL; p_token = strtok(buf, ","); strcpy(dat[0],p_token); n=1; while(-1) { p_token = strtok(NULL,","); if(p_token == NULL) { break; } strcpy(dat[n],p_token); n++; } if(j!=0) { place[j-1][10]=dat[3]; printf("%s \n",place[j-1][10]); } } fclose(fp); free(place[NUM][15]); return 0; } NUMの数を10万以上にすると、実行してもプログラムが勝手に停止してしまいます。書籍もネットも大分読み漁ったのですが、処置がまったくわからず途方にくれています。 どなたかこうした処理に詳しい方、アドバイスをいただけないでしょうか。よろしくお願い申し上げます。 追記:(1)都道府県名を二次元配列で取っているのは、都道府県名が「大阪府」などと、CSVファイル上で日本語で記載されているからです。 (2)プログラムを実行する際にデータ数を10万以上にすると、CSVファイルをフォルダ内においていなくてもプログラムが停止します(ただしコンパイルエラーはでません)。つまり、メモリの確保に問題があるということになるのでしょうか?

  • ファイルの読み込み

    以下のデータが入ったファイルを読み込んで、出力するプログラムを 作成したのですが、旨くデータを出力できません。どなたか教えていただけないでしょうか?  E | 1 3 | 1 E | 2 | 1 2 E | 3 | 0 E | E | 0 #include<stdio.h> #include<string.h> #include<stdlib.h> #define NFA_STATE_MAX 128 typedef struct nlist{ int c; int to; int from; }nlist_t; main() { char line[255]; FILE *fp; int i,j; if((fp = fopen("data.txt", "r")) == NULL) { printf("Can't Open This File.?n"); exit(1); } char atranbysymbol[100]; char *tranofsymbol; int ntran = 0; int nstate=4, nsymbol=2; nlist_t nfa[NFA_STATE_MAX]; for(i=0; i<nstate; i++) { int ns = 0; fgets(line,255,fp); tranofsymbol = strtok(line,"|"); while(tranofsymbol != NULL) { atranbysymbol[ns++] = *tranofsymbol; tranofsymbol = strtok(NULL,"|"); } for(j=0; j<=nsymbol;j++) { char *sto; strcpy(line, &atranbysymbol[j]); sto = strtok(line," "); while(sto != NULL) { if(strcmp(sto, "E")!= 0) { nfa[ntran].to = atoi(sto); nfa[ntran].from = i; nfa[ntran++].c = j - 1; } sto = strtok(NULL, " "); } } } for(i=0; i<ntran; i++) { printf("From: %d ", nfa[i].from); printf("To: %d ", nfa[i].to); printf("on Symbol: %d ?n", nfa[i].c); } return 0; }

  • vectorの中にmap

    vectorの中にmapを入れて 添字:ノードID [どのノードから来たのか|それまでのコスト] を表現しようと考えています. #include<iostream> #include<vector> #include<map> #include<list> // MACROS #define UNDEF -1 // PROTOTYPE DCLARE void init_path(std::vector<std::map<char, int> >, int size); int main(void) { //source -> source node // //size -> the number of node // //path -> store path infomation // ex: // path[1]: 1 is node id // char : from node id // cost : how cost from source to here // //adj -> show adjacency list eace node int source; int size; std::vector<std::map<char, int> > path; std::vector<std::list<char> > adj; size = 5; std::cout << "before" << std::endl; init_path(path, size); std::cout << "after" << std::endl; std::map<char, int>::iterator it; for(int i = 0; i < size; i++) { it = path[i].begin(); // std::cout << it->first << ":" << it->second << std::endl; } return 0; } void init_path(std::vector<std::map<char, int> > path, int size) { std::map<char, int> init; init.insert( std::map<char, int>::value_type('-', UNDEF) ); for(int i = 0; i < size ; i++) { path.push_back(init); } return; } *結果 before after Segmentation fault となり初期化をする所までは正常に動いたっぽいのですが どこが悪いのかわかりません(おそらくイテレータあたりかと思うのですが・・・・ 具体的にどうしたらいいのか分からないのでご指導ねがいます.

  • c#でC言語のstrtokに相当する関数は何か

    文字列から指定した文字でデータを区切る関数strtokがC言語にはある これに相当するC#の関数は何か 例えばCでは以下のように書く。 char data1[]= " 123 , 456 Yamada " ; char *token ; strtok( data, " ," ) ; /* スペースとカンマを区切りに文字列を抽出 */ token = strtok( str, " ." ); printf(" token chat = %s\n", token ) ; while ( token != NULL ) { token = strtok( NULL," ." ); if ( token != NULL ) printf(" token chat = %s\n", token ) ; } これに相当するc#のSplit関数を使用すると 不要な空白を取り出しているようである 知っている方がおりましたら、教えて下さい。

  • トークンで分けた文字列をさらにトークンで分ける

    初心者です。よろしければご教授下さい。 temp.c:12: warning: useless keyword or type name in empty declaration というような文字列がg_str02[0]に格納されている時に、まずは「 」(半角スペース)を区切り文字としてトークンごとに分け最初の2つのトークンをmretsu1[0]とmretsu1[1]の中に格納し、さらにmretsu1[0](上記で言う「temp.c:12:」)を「:」を区切り文字としてトークンごとに分けmretsu2[0]とmretsu2[1]に格納するような関数を作りたいのですが、コンパイルは成功するのですが、できた実行ファイルを実行するとエラーが起きて強制終了されてしまいます。 現在ソースは以下のようになっています。 ////////// char mretsu1[255][255]; char mretsu2[2][255]; char *token1 = " "; char *token2 = ":"; strcpy(mretsu1[0], strtok(g_str02[0], token1)); strcpy(mretsu1[1], strtok(NULL, token1)); strcpy(mretsu2[0], strtok(mretsu1[0], token2)); strcpy(mretsu2[1], strtok(NULL, token2)); ////////// デバッグをしてみた所、どうもmretsu1[0]をさらに分解しているところにエラーがあるようです。 よろしくお願いします。

  • C言語でファイルの内容を strtok関数 を使って数字と文字を分けて

    C言語でファイルの内容を strtok関数 を使って数字と文字を分けて配列に格納したいのですが、うまくできません。 どこが駄目なのかご指摘をお願いします! ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int i=0; int num[10]; char na[10]; fp=fopen(argv[1],"r"); while(fgets(str,sizeof str,fp)!=NULL); tp = strtok ( str, " " ); while(tp != NULL ) { num[i]=atoi(tp); tp = strtok( NULL," "); if ( tp != NULL ){ na[i]=*tp; } i++; } printf("%d\n%s",num[0],na[0]); printf("%d\n%s",num[1],na[1]); fclose(fp); return 0; }

  • 長い文字列を配列に入れるには?

    VBから長い文字列を送って,c言語で受け取りたいのですが,うまく配列に入れることが出来ません.文字列サイズは最低でも4000バイト必要です. #include <stdio.h> #include <stdlib.h> #include <string.h> //VBから送られてくるデータ char getch[4000]="start1T\tpose 0 0 -5 0 -5 0 -5 0 -5 0 0 0 0 0\ ..省略.. 25\t\n"; void main(void){ char *token; char seps[]="\t\n"; FILE *pose; pose=fopen("pose.txt","a"); if((token=strtok(getch,"\t"))==NULL){ printf("Error File1\n"); exit(1); } printf("%s\n",token); while(strcmp(token,"\n")!=0){ token=strtok(NULL,"\t"); fputs(token,pose); fputs("\n",pose); printf("%s\n",token); } fclose(pose); }

専門家に質問してみよう