0

これは私が書いた関数です:

uint32_t file_list(char *path, char ***ls){
    DIR *dp;
  //uint32_t i;
  struct stat fileStat;
  struct dirent *ep = NULL;
  uint32_t len, count = 0;
  int file = 0;
  *ls = NULL;
  dp = opendir (path);
  if(dp == NULL){
    fprintf(stderr, "no dir: %s\n", path);
    exit(1);
  }

  ep = readdir(dp);
  while(NULL != ep){
    count++;
    ep = readdir(dp);
  }
  rewinddir(dp);

  *ls = calloc(count, sizeof(char *));
  count = 0;
  ep = readdir(dp);
  while(ep != NULL){
    if((file = open(ep->d_name, O_RDONLY)) < 0){
      perror("apertura file");
      exit(1);
    }
    if(fstat(file, &fileStat) != 0){
      perror("filestat");
      free(*ls);
      close(file);
      exit(EXIT_FAILURE);
    }
    close(file);
    if(S_ISDIR(fileStat.st_mode)){
      len = strlen(ep->d_name);
      (*ls)[count] = malloc(len+5); /* lunghezza stringa + "DIR \n" */
      strcpy((*ls)[count], "DIR "); /* copio DIR */
      strcat((*ls)[count++], ep->d_name); /* concateno la stringa DIR con il nome della dir */
      ep = readdir(dp);
    }
    else{
      (*ls)[count++] = strdup(ep->d_name);
      ep = readdir(dp);
    }
  }
  /*for(i=0; i<count; i++){
    free((*ls)[count]);
  }*/
  (void)closedir(dp);
  return count;
}

私が持っているメインプログラムに入り、char **files次にカウントを取得する部分count = file_list("./", &files);
は私の問題は何ですか? 彼ら(ポインター)が参照する可能性のある動的に割り当てられたメモリを解放する必要があることは
誰もが知っていますが、ポインターを(forループで)解放すると、メインプログラムでファイルリスト中に予期しない動作が発生しました(ファイル名の重複、ファイル名なしなど)。実際、ポインターを解放しないと、すべてが完全に機能します。 だから私の質問は:これらのポインタを解放する方法は? 前もって感謝します!


4

4 に答える 4

2

ポインターを解放する必要があることは誰もが知っていますが、(for ループを使用して) ポインターを解放すると、メイン プログラムで、ファイル リスト中に予期しない動作が発生しました (ファイル名が重複している、ファイル名がないなど)。

あなたの問題は、同じ関数で割り当てと解放を行うことです。これにより、関数は基本的に役に立たなくなります(とにかく正しく理解している場合)。同じ関数で解放した後、(つまり、「メイン プログラム」で) 解放すると、オペレーティング システムに解放されたメモリ セグメントにアクセスすることになりますが、これは未定義の動作です。

2 つの関数が必要です。1 つは割り当て用 (上記のもの) で、もう 1 つは完了したら解放するためのものです。

char** files;
uint32_t count = file_list("./", &files);
// do something with files here
file_list_free(&files, count);

countfree 関数は、バッファ オーバーランを防ぐために を知る必要があることに注意してください。

コードには他にも問題があります (例: の戻り値をチェックしていないcallocなど) が、ここですべてをカバーするには長すぎます (実際の質問とは必ずしも関係ありません)。

于 2012-08-09T16:28:35.727 に答える
1

追加の関数を定義する必要があります。これにより、呼び出し元は、データの使用が完了したときにデータを解放できます。

void free_file_list(char ***ls, int count) {
    for(int i=0; i<count; i++){
        free((*ls)[i]);
    }
    free(*ls);
}

次に、ドキュメントで、への各呼び出しをへfile_listの呼び出しと一致させる必要があることを説明する必要がありますfree_file_list

countただし、次のような構造体に格納します。

struct {
    char ***ls;
    int count;
} FILE_LIST;
于 2012-08-09T16:28:52.997 に答える
1

手始めに、あなたの ls パラメーターは であるため、それが目的である場合は、他のそれぞれを解放する前にchar***( ) すべての内部ポインターを解放する内部ループが必要です( )。で二重間接参照のみが必要な場合は、パラメーター宣言で * の 1 つを削除します。**ls*lsls

(ところで、ポインタを解放するためにループ内で配列表記を使用する必要はありません(または で割り当てられた要素にアクセスする他の場所ls)。free(*(ls + count));通常、より受け入れられているイディオムです。ポインタ演算は、データ型が何であるかに関係なく機能します(他の)よりもvoid、コンパイラがそれを考慮に入れるためです。)

于 2012-08-09T16:16:33.417 に答える
0

使用が終了したら、メインプログラムのポインタを解放します。

あなたも解放する必要があり*lsます(繰り返しますが、それを終えた後)。

于 2012-08-09T16:15:41.387 に答える