- ベストアンサー
なぜ動かないのかわからないです。
以下のことをしようと思いました。 (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で領域を取得して、そこの領域にコピーしているはずなのに… 私の現在の知識量では、解決する策が全く思いつかなかったので、どなたか詳しい方助けてください。 よろしくお願いします。
- みんなの回答 (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にするのであれば、一度バッファに読み込んでから、メモリ確保、コピーとすればいいでしょう。
その他の回答 (2)
- titokani
- ベストアンサー率19% (341/1726)
>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)
● > // 一行の長さを計算する(バイト数) > 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したメモリ領域を開放している個所が見当たりません。 使い終わったメモリは解放してあげましょう。
お礼
m(_ _)mありがとうございました。