• ベストアンサー

なぜ動かないのかわからないです。

以下のことをしようと思いました。 (1)テキストファイルを読み込む (2)文字列を半角全角を区別しないで済むワイド文字列に変換する (3)デバッグとして、各配列に格納された文字列、文字数、を表示させる この(1)~(3)を行うために以下のようなプログラムを組んでみました。 // ファイルを読み込む #include <stdio.h> #include <string.h> #include <stdlib.h> #include <locale.h> #define LineMax 30000 int main(void){   char FileName[] = "ReadFile.txt";   wchar_t *FileContents[LineMax];  // ワイド文字列格納用配列   char buff[512];  // ファイル読み込み一時領域   int i, buffstrLen;   int FileLineNo = 0;   int FileContentsCharCount[LineMax];   FILE *fp;   // Cロケールカら地域ロケールに変換   setlocale(LC_ALL, "Japanese");   // ファイルを読み込む   fp = fopen(FileName, "r");   if(fp == NULL){     printf("\"%s\"ファイルの読み込みに失敗しました。\n", FileName);     exit(1);   }      // 一行ずつファイルを変数に格納していく   // 無限ループ(ファイルの最後まで)   while(1){     // ファイルから一行読み込み     if(fgets(buff, 512, fp) == NULL){       break;     }     // 一行の長さを計算する(バイト数)     buffstrLen = strlen(buff);     // 領域を確保     FileContents[FileLineNo] = (unsigned short *)malloc(buffstrLen);     if(FileContents[FileLineNo] = NULL){       puts("領域の確保に失敗しました。");       exit(1);     }     // ■間違い?■ワイド文字にした上で、FileContentsポインタ配列に格納する     FileContentsCharCount[FileLineNo] = mbstowcs(FileContents[FileLineNo], buff, buffstrLen);     FileLineNo++;   }   fclose(fp);   /***** ファイル読み込み完了 *****/   FileLineNo--;   printf("ファイルには%d行ありました\n", FileLineNo);   for(i=0; i<FileLineNo; i++){     // i 行目の文字数     printf("DEBUG:FileContents[%03d]の文字数%d文字\n", i, FileContentsCharCount[i]);     // i 行目の文字内容     printf("DEBUG:FileContents[%03d]の内容:%s\n", i, FileContents[i]);   }   return 0; } ■間違い?■で示した部分でFileContents[FileLineNo]の中に、buff配列に一時的に格納した文字列が入っていないように思いました。 文字数は、バイト数ではなく、全角半角区別なく単純な文字数として表示されるのに、読み込み内容が全く表示されないのです(すべて(null)) 無駄な領域をなくすために、毎回バイト数を計算し、その都度mallocで領域を取得して、そこの領域にコピーしているはずなのに… 私の現在の知識量では、解決する策が全く思いつかなかったので、どなたか詳しい方助けてください。 よろしくお願いします。

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

  • ベストアンサー
  • S117
  • ベストアンサー率40% (18/45)
回答No.3

fgetwsを使うことをおすすめします。 fgetwsを使えば、入力と同時に変換してくれます。 つまり、ストリームから直接ワイド文字列を取得できます。 また、"Japanese"で決めうちしていますが、""を渡せば、実行環境の標準的なロケールになります。 日本語版WindowsならWindows-31Jになるでしょう。 UNIX(とその互換OS)ならLANG環境変数に依存するでしょう。 外部からファイルのエンコードを指定できるので、こっちの方が便利です。 さて、見た限りでは重大な誤りが2点あります。 1点目はprintfの書式指定です。 %sを使ってますが、これはMBS(マルチバイト文字列、つまりchar*)を受け取ります。FileContentsはWCS(ワイド文字列、つまりwchar_t*)なので明らかに型があってません。 %lsを使ってください。%ls以外にも指定する方法はありますが、標準Cでは%lsしか使えませんので注意してください。 2点目はバッファの確保の方法です。 マルチバイト文字列のバイト数を数えて、そのサイズのワイド文字バッファを確保しています。 が、wchar_tは通常char型の2倍か4倍の幅を持ちます。 mallocする際にはsizeof(wchar_t)をかけなくてはなりません。 また、NUL文字の領域を忘れていますし、キャストの型もwchar_t*であるべきです。 そもそもsizeof(wchar_t)をかける方法ではワイド文字に必要なぎりぎりのサイズにできません。無駄が発生します。mbstowcsの戻り値からサイズを受け取ってから確保するか、十分に大きなバッファに変換してから、そのサイズのバッファを確保し、そこへコピーすべきです。入力方法をfgetwsにするのであれば、一度バッファに読み込んでから、メモリ確保、コピーとすればいいでしょう。

inada_star
質問者

お礼

m(_ _)mありがとうございました。

その他の回答 (2)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.2

>if(fgets(buff, 512, fp) == NULL){ >break; >} >// 一行の長さを計算する(バイト数) >buffstrLen = strlen(buff); >// 領域を確保 >FileContents[FileLineNo] = (unsigned short *)malloc(buffstrLen); mbstowcsは、最初の引数がNULLの時に、必要なバイト数を返してくれるので、一行の長さの計算は、 buffstrLen=mbstowcs(NULL,buff,512); とするのがいいかと。

  • Yanch
  • ベストアンサー率50% (114/225)
回答No.1

● >    // 一行の長さを計算する(バイト数) >     buffstrLen = strlen(buff); >     // 領域を確保 >     FileContents[FileLineNo] = (unsigned short *)malloc(buffstrLen); の部分ですが、 wchar_tを格納するには、領域のサイズが少ないのではないでしょうか。 そして、 FileContents は >   wchar_t *FileContents[LineMax];  // ワイド文字列格納用配列 の様に宣言しているのですから、「(unsigned short *)」にキャストしているのは、 危険です。     FileContents[FileLineNo] = (wchar_t *)malloc((buffstrLen + 1) * sizeof(wchar_t)); としては、いかがでしょう。 ● 環境とか書かれていないみたいですが、開発環境は、何を使われていますか? ● 入力ファイルのエンコーディングは何を使われているでしょうか? ● mallocしたメモリ領域を開放している個所が見当たりません。 使い終わったメモリは解放してあげましょう。

関連するQ&A

  • 漢字を配列に入れたいのですが

    漢字を配列に入れたいのですが、うまくいきません。 3列、60行のcsvファイルを読み込んで配列に入れようをしているのですが、1列目、2列目、3列目にある漢字をそれぞれ配列に入れようとしているのですが、出力するとうまくいかないんです。誰か教えてください。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXBUFFSIZE 256 #define MAXWORDS 15 int split(char* words[], int length, char* split_ch,char* str){ int i,j; for(i=0;i<length;i++){ if((words[i] = strtok(str,split_ch))==NULL)break; str=NULL; } return(i); } int main(int argc, char* argv[]){ if(argc !=2){ printf("入力エラー"); return(0); } FILE *fp; char *ll, *words[MAXWORDS], ch, buff[MAXBUFFSIZE]; int i,j; unsigned int data1[60], data2[60], data3[60]; if((fp =fopen(argv[1],"r"))==NULL){ printf("ファイルが開けません。\n"); } j=0; ll= fgets(buff,MAXBUFFSIZE,fp); while((ll= fgets(buff,MAXBUFFSIZE,fp)) != NULL){ split(words, MAXWORDS, ",",ll); data1[j] = words[0]; data2[j] = words[1]; data3[j] = words[2]; j++; } printf("%s\n%s\n%s\n", data1,data2,data3); }

  • reallocについて

    現在、領域を拡張しながら、 ファイルを読み込んで呼び元に返却するPGを作成しています。 reallocがうまくいかないので、試しに小さいのを作って みましたが、これだとreallocの2度目で落ちます。 100文字ずつ呼んでいるので、拡張も100文字ずつ行っています。 メモリ確保に失敗なら、まだ分かるのですが、 ちょっと理由がわかりません。 reallocを複数繰り返していることも問題だと思いますが、 まずは正常に処理を流したいと考えています。 よろしくお願いします。 ~~~~~~ソース~~~~~~~~ //ファイルを読み込んでから領域を確保する #include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFF 100 int main() { FILE *fp; char tmp[BUFF+1]; char *str; int len = 0; fp = fopen( "c:/test.txt" , "rb" ); if(fp ==0){ printf("ファイルがありません\n"); return -1; } //領域を初期化 str = (char *)malloc(1); memset(str,'\0',sizeof(str)); while(feof(fp)==0){ memset(tmp,'\0',sizeof(tmp)); fgets(tmp,BUFF,fp); //領域を再確保 len += BUFF+1; if(NULL == ((char *)realloc(str,len))){ printf("メモリ確保エラー"); } //読み込んだ値を変数に追加 strcat(str,tmp); } printf("文字列\n\n%s\n",str); printf("長さ:%d\n",len); fclose(fp); return 0; }

  • 配列のメモリの確保

    先日メモリについてご質問させていただいたものですが、 今ファイルから読み込んだ文字列を配列に格納する作業を行なっています。 今は char buf[1000]; FILE fp; if((fp=fopen("○○.txt","r")) ==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) != NULL){ としてファイルを一行ずつ読み込んでその後単語ごとに配列に組み込みます このときファイルの文字列を格納する配列はbuf[1000]ですが このメモリでは足りないかもしれませんし多すぎるかもしれません。 足りない場合はエラーになるし多すぎる場合はメモリの無駄ですよね。 このような場合はメモリを取り直すべきなのでしょうか?その場合 どのような方法がありますか?調べてもint型の領域確保とかそういうのはあるんですがファイルから読み込んだ文字列の領域確保とかは見つからなかったので教えて下さい。

  • C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問

    C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問です! ファイルを開いた後でエラーとなるのですが、何が足りないのでしょうか? ファイル内容 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 k,i=0; int num[10]; char na[10][20]; fp=fopen(argv[1],"r"); if(fp==NULL){ printf("ファイルを開けません\n"); return 1; }else{ printf("開けた\n"); } while(fgets(str,sizeof str,fp)!=NULL){ tp=strtok(str," "); num[i]=atoi(tp); tp=strtok(NULL," "); strcpy(na[i],tp); i++; } printf("%d\n%s\n",num[0],na[0]); printf("%d\n%s\n",num[1],na[1]); fclose(fp); return 0; }

  • Borland C CSVファイル読み込み

    CSVファイルを読み込み、読み込んだ値で計算を行うプログラムを作っています。 ・環境はWindows VISTA UltimateでBorland C++ Compiler 5.5  ・CSVファイルのデータの形式は 1,4532 4,2131 6,4301 . . ・データ数は決まっていて今のところ全部で12個 そして以下のようにCSVの読み込みプログラムを試しに組んだ所、実行時エラーがでました。 #include <stdio.h> #include <stdlib.h> #include <string.h> void main(void) { int AN[11][1]; int i=0,j=0,c=0; char buff[1024], *tp; FILE *fp; /*配列初期化*/ for(i=0;i<11;i++) { for(j=0;j<2;j++) { AN[i][j]=0; } } fp=fopen("test1.csv","r"); if(fp==NULL) { /* オープン失敗 */ printf("ファイルがオープンできません\n"); exit(1); /* 強制終了 */ } while( fgets(buff, 1024 , fp) != NULL ) { tp=strtok(buff , ","); if (tp !=NULL) {AN[i][j] = atoi(tp);} printf("%d\n",AN[i][j]); tp = strtok(NULL , ","); if (tp !=NULL) {AN[i][j+1] = atoi(tp);} printf("%d\n",AN[i][j+1]); i++; } fclose(fp); } 実行するとファイルクローズの後、問題が発生したためプログラムを終了しましたと出ます。"AN[i][j]=atoi(tp)"の配列部分を単純に変数にするとこのようなエラーは出ないのですが。 なぜエラーが出るのか、どなたかご教授願います。

  • C言語についてアドバイスをください。

    CSVファイルの内容をfreadで読み込み、strtokを使わずにbuffに格納した後、 buffから1文字ずつbuff2へコピーさせていって、コンマがきたら数字、 改行がきたら名前と判別して、自作関数に渡して表示させたいです。 CSVファイルの内容は 『11,名前1(改行) 15,名前2(改行) 18,名前3』 といった感じです。 ------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> #include <string.h> #include <stdlib.h> #define NUM 256 struct kou { short nenrei; char namae[30]; }; void pri(struct kou *o) { printf("%d\n%s\n",o->nenrei,o->namae); } int main(void) { FILE *fp; // ファイルポインタ char buff1[NUM] = {0}; char buff2[NUM] = {0}; char *fname = "text1.csv"; // ファイル名を指定 short i = 0; int n = 0; struct kou p; fp = fopen(fname, "r"); if(fp == NULL) { printf("%sファイルをオープンできませんでした。\n",fname); } fread(buff, 1, NUM, fp); while(buff1[n] != NULL) { buff2[n] = buff1[n]; // buff2[0]からbuff1の中を一文字ずつコピーしていく。 if(buff2[n] == ',') // buff2に格納されていく中にコンマがきたら以下の作業を行う。 { i = (short)atoi(buff2); // char型からshort型への変換 p.nenrei = i; } if(buff2[n] == '\n') { strcpy(p.namae,buff2); // p.namaeにbuff2をコピー。 pri(&p); } n++; } fclose(fp); printf("ファイルをクローズしました。\n"); return 0; } ------------------------------------------------------- 今のままだと 『11 11,名前1 11 11,名前1 15,名前2』 という表示になってしまいます。 while 内で既に読み込んだ部分を読み込ませないよう(表示させないよう)にできたら良いと思うんですが、そういったやり方はあるのでしょうか? むしろやり方を変えたほうが良いでしょうか・・・。 まだC言語を学び始めて日が浅いので、色々間違っている部分もあると思いますが、 そういったことを含めてアドバイスをいただけたらと思います。 よろしくお願いします。

  • テキストファイルの内容を2次元配列に格納したい

    課題で用意されたテキストファイルを読み込み、空白を区切りとする文字列の単位で配列に格納したいのですが、やりかたがわかりません。 ソースプログラムですが #include<stdio.h> #include<string.h> #include<ctype.h> #define MAX 1000 int TextSplit(char *fname, char (*SpStr)[50]); int main(void) { int i, n; char fname[MAX], SpStr[MAX][50]; int Split; FILE *fp; printf("input File =>"); scanf("%s", fname); Split = TextSplit(fname, SpStr); printf("\n %d[文字列数] \n", Split); return 0; } int TextSplit(char *fname, char (*SpStr)[50]) { int i, j, k; char Readstr[MAX]; FILE *fp; fp = fopen(fname, "r"); if(fp == NULL) { printf("ファイルオープン失敗"); return 1; } i = 0; while(fscanf(fp, "%s", SpStr) != EOF) { i++; } fclose(fp); return i; } 以上のソースプログラムですが、内容は「空白で区切る文字列の単位の総数を表示する」ものになっています。 今日の20時までに終わらせないといけないので、ご教授お願いします。 使ってるソフトはMicrosoft Visual Studioです。

  • CSVファイルの内容を構造体に格納したい(Unix使用)。

    こんにちは。私は30代の男性です。 「名前」「身長」「体重」が記載されたCSVファイルの内容を読み取って、構造体の「name」「height」「weight」に格納するプログラムを作っています。CSVの内容は A,175,80 B,167,89 C,155,45 ・ ・ ・ Z,188,70 だと仮定します。数値が読み取れているか、下記のように「tp = strtok(file_image, ",\n" );」の前後に「printf("%s\n", file_image);」を置いてみたら、strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。これでは全てのデータを構造体に格納できないので、困っています。 1.どのようにすれば、数字も取り出せる(読み取れる)でしょうか? 2.効率よく構造体に格納するには、どのようにしたらよいでしょうか? アドバイスを頂ければ幸いです。宜しくお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp = NULL; int rtn = 0; if ((fp = fopen(argv[1], "r")) == NULL) { printf("ファイルオープンに失敗しました。\n"); return 1; } if (argc != 2) { printf("ERROR: オプションの数に過不足があります。\n"); return 1; } rtn = change_csv(fp); return 0; } int change_csv(FILE *fp) { int i; int j; char file_image[256]; /* 読み込んだ先のメモリの領域 */ char *tp; for (i = 0; i <= 256; i++) { if (fgets(file_image, 256, fp) == NULL) { if (ferror(fp) != 0) { printf("ERROR: 読み込みに失敗しました。\n"); return 1; } } if (feof(fp) != 0) { break; } printf("%s\n", file_image); tp = strtok(file_image, ",\n" ); printf("%s\n", file_image); } fclose(fp); return 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; }

  • fopen関数について

    ----------------------------------------- #include<stdio.h> #include<stdlib.h> int main() { FILE *fp; char filename[80],ss[256]; printf("ファイル名="); gets(filename); if((fp=fopen(filename,"r"))==NULL){ printf("ファイルをオープンできません.\n"); exit(1); } while(fgets(ss,256,fp)!=NULL){ printf("%s",ss); } puts(""); fclose(fp); return 0; } ----------------------------------------- 初心者な内容の質問ですいません。 以上のプログラムでまず、「gets(filename);」により、「filename[80]」の配列に「aaa.txt」という文字列を格納し、そのファイルをfopenで読もう込もうとしています。 そこで、 if((fp=fopen(filename,"r"))==NULL) の部分に疑問があるのですが、「filename」という配列名だけで中身の「aaa.txt」と何故認識できるのでしょうか? 配列名ということで、先頭アドレスのみの情報しかないと思いました。 教えていただければ嬉しいです。