0

N 個のテキスト ファイル (同様の構造を持つ: 数行、各行には同じ少数の単語が含まれる) から読み取り、読み取った単語を文字列行列に格納したいと思います。ポジション 一言。

ファイルの簡単な例 (2 行、1 行に 3 語) は次のとおりです。

line1word1 line1word2 line1word3
line2word1 line2word2 line2word3

単語の区切り文字はスペースです。

私はこのコードを試みました:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STRING_LENGTH 1000
#define MAX_TOKS 100
#define DELIMITERS " "

// line parsing utility
int parseString(char* line, char*** argv) {

  char* buffer;
  int argc;

  buffer = (char*) malloc(strlen(line) * sizeof(char));
  strcpy(buffer,line);
  (*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));

  argc = 0;  
  (*argv)[argc++] = strtok(buffer, DELIMITERS);
  while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
     (argc < MAX_TOKS)) ++argc;
  return argc; 
}


int main() {

  char S[MAX_STRING_LENGTH];
  char **A;

  int  n,i,j,l;

  FILE *f;
  char file[50];

  char ***matrix;
  matrix = malloc(MAX_TOKS * sizeof(char**));

 //memory allocation for matrix
 for (i = 0; i < MAX_TOKS; i++)
     {
       matrix[i] = malloc(MAX_TOKS * sizeof(char *));
       for (j = 0; j < MAX_TOKS; j++)
           {
           matrix[i][j] = malloc(MAX_TOKS * sizeof(char));
           }
     }

  int NFILE = 10; // number of files to be read

  for(i=0;i<NFILE;i++) 
    {  
    sprintf(file,"file%d.txt",i); 
    f = fopen(file,"r");

    l=0; // line-in-file index
    while(fgets(S,sizeof(S),f)!=NULL) {
          n = parseString(S,&A);
          for(j=0;j<n;j++) {
            matrix[i][l]=A[j];
            printf("%s\t%s\n",matrix[i][l],A[j]); 
            } 
        l++;
        } 
 fclose(f); 
    }

free(matrix);
free(A);    
return(0);  
}

私が解決できない問題は、配列間の対応をチェックするときに(単一の単語を正しく保存していることを確認するために)、

printf("%s\t%s\n",matrix[i][l],A[j]);

ファイル番号に関係なく、各行の最後の単語 (および最後の単語のみ) が に格納されていないことがわかりましたmatrix。つまり、line1word1line1wordsfile0は と に正しく格納されmatrix[0][0][0]ますがmatrix[0][0][1]、フィールドには がありmatrix[0][0][2]ません。line1word3A[2]

私は何をしているのですか?なにか提案を?

よろしくお願いします。

4

2 に答える 2

0

char ***matrix3次元配列を宣言しません。マトリックスはchar *matrix[a][b]、文字列ポインタの2次元配列を保持するようなものである必要があります。配列内のアドレスを計算するには、コンパイラは1つを除くすべての次元を知っている必要があります。あなたがそれについて考えるならば、あなたはおそらく理由を見るでしょう...

2つのアレイがある場合:

1 2 3        1  2  3  4  5  6  7
4 5 6        8  9 10 11 12 13 14
7 8 9       15 16 17 18 19 20 21

あなたはそれが同じアイテムでitem[1][1]ないことがわかります。配列の次元に関係なく、要素は通常、メモリ内で順番に配置され、各行は前の行(または言語によっては可能な列)の後に続きます。ポインタの配列がある場合、実際のコンテンツは他の場所にある可能性があります、しかし、ポイントはこのように配置されます。したがって、上記の例では、メンバーを見つけることができるように、コンパイラーに列数を提供する必要があります(数は可変です)。3次元配列では、コンパイラーが最初の2次元を提供する必要があります。アイテムのオフセットを計算する場合があります。

それがお役に立てば幸いです。

編集:すべての配列項目アクセスを処理する独自の関数を作成することにより、真に動的な配列次元を持つことができます。関数は、適切なアドレスを計算できるように、動的ディメンションとアイテムインデックスを知る必要があります。

于 2013-03-15T10:56:10.397 に答える
0

これは間違っているように見えます:buffer = (char*) malloc(strlen(line) * sizeof(char));

まず、C では malloc をキャストする必要はありません。コードがキャストなしでコンパイルされない場合は、次の 2 つの理由が考えられます。

  1. malloc のプロトタイプはありません。intプロトタイプがないということは、関数がデフォルトの型を返すことを意味するか、エラーが発生するため、明らかにこれは問題を引き起こす可能性があります。これにより、プログラムが誤動作する可能性があります。これを回避するには、#include <stdlib.h>.
  2. C++ コンパイラを使用しています。止まる。C++ でプログラムする (malloc の使用をやめる) か、C コンパイラを使用します。このプロジェクトを C++ プロジェクトで使用する場合は、C コードを C コンパイラでコンパイルし、C++ コンパイラでリンクします。

次に、sizeof(char) は常に 1 です。これを掛ける必要はありません。

3 番目に、文字列は最初の '\0' で終わる一連の文字です。これは、空の文字列であっても、文字列は常に少なくとも 1 文字を占めることを意味します。何をstrlen("")返しますか?とはsizeof("")? '\0': のためのスペースを作るために 1 を追加する必要がありますbuffer = malloc(strlen(line) + 1);

これは少し間違っているように見えます:(*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));

malloc はオブジェクトへのポインタを返します。*argvです。char **これは、 を指していることを意味しchar *ます。ただし、この場合、malloc はchar **オブジェクトへのポインターを返します。表現は同一である必要はありません。これに関連する移植性の問題を回避するには、次のパターンに従ってくださいvariable = malloc(n * sizeof *variable);...この場合、*argv = malloc(MAX_TOKS * **argv);

進むにつれてザラザラしてきます。コードについて知っていると思うことはすべて忘れてください。24 か月後にこれに戻ると仮定します。これについてどう思いますか?

argc = 0;  
(*argv)[argc++] = strtok(buffer, DELIMITERS);
while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
   (argc < MAX_TOKS)) ++argc;

ここにもオフバイワンがあります。を仮定するとargc == MAX_TOKS、ループは に割り当てようとします(*argv)[MAX_TOKS]。このループに問題があると思います。解決策は、できるだけ多くのコードを 1 行に詰め込もうとするのではなく、意図をより明確に表現することです。これをどのように書き換えますか?この状況で私がすることは次のとおりです。

char *arg;
size_t argc = 0;
do {
    arg = strtok(buffer, DELIMITERS);
    buffer = NULL;

    (*argv)[argc] = arg;
    argc++;
} while (argc < MAX_TOKS && arg != NULL);

問題は、strtok が NULL を返したときに解析ループがインクリメントされないことです。したがって、関数は最後のアイテムの位置を返します。トークンが 2 つあると仮定すると、解析関数は 1 を返します。表示ループは、この位置までの項目を表示します: for(j=0;j<n;j++). 提案された改善を使用するか、ループを変更できます: for (j = 0; j <= n; j++). いずれにせよ、これらのオフバイワンを修正する必要があります。

好奇心から、どの本を読んでいますか?

于 2013-03-15T11:26:28.633 に答える