2

それは私の前の質問の拡張です:どうすればcのディレクトリからtxtファイルだけを取得できますか?。次に、これらのファイル名(dirにいくつあるかはわかりません)をchar **配列に保存します。私は解決策(一種)を見つけましたが、それから私は必要ではないことに気づきましたchar*char **(私は知っています、私は愚かです:])

とにかく、私はこのコードでセグメンテーション違反[コアダンプ]を取得しました:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdbool.h>

char* allocMemory(int n)
{
    char *tab = (char *) malloc(n*sizeof(char));
    return tab;
}

void freeMemory(char **tab, int n, int m)
{
    int i=0;
    for(i=0; i<m; i++)
        free(tab[i]);
    free(tab);
    tab = NULL;
}

bool hasTxtExtension(char const *filename)
{
    size_t len = strlen(filename);
    return len > 4 && strcmp(filename + len - 4, ".txt") == 0;
}

char** getTxtFilenames(const char *dirname)
{
    DIR *directory = NULL;
    struct dirent *ent = NULL;
    int fileCounter = 0;

    char **txtFiles = allocMemory(1);
    char **moreTxtFiles = allocMemory(1);

    directory = opendir (dirname);
    if(directory == NULL)
        return NULL;
    int i = 0;

     while ((ent = readdir (directory)) != NULL)
     {
         if(hasTxtExtension(ent->d_name))
         {
             fileCounter ++;
             moreTxtFiles = (char**) realloc (txtFiles, fileCounter * sizeof(char*));

             if(moreTxtFiles[i] != NULL)
             {
                 txtFiles = moreTxtFiles;
                 txtFiles[i] = allocMemory(strlen(ent->d_name));
                 txtFiles[i][fileCounter - 1] = ent->d_name;
             }
             else
             {
                 freeMemory(txtFiles, 1, fileCounter);
                 return NULL;
             }
         }
         i ++;
     }

     if(closedir(directory) < 0)
        return NULL;

    return txtFiles;
}

int main(int argc, char **argv)
{
    char **txtFilenames = getTxtFilenames("dir");
    if(txtFilenames == NULL)
        return -1;
    printf("%s\n", txtFilenames[0][1]);
    return 0;
}

編集:

私もこれを試しました:(ImがCの素敵ではないchar配列と少し混同されていることに注意してください、argh:/)

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdbool.h>

char* allocMemory(int n)
{
    char *tab = (char *) malloc(n*sizeof(char));
    return tab;
}

void freeMemory(char *tab)
{
    free(tab);
    tab = NULL;
}

bool hasTxtExtension(char const *filename)
{
    size_t len = strlen(filename);
    return len > 4 && strcmp(filename + len - 4, ".txt") == 0;
}

char* getTxtFilenames(const char *dirname)
{
    DIR *directory = NULL;
    struct dirent *ent = NULL;
    int fileCounter = 0;

    char *txtFiles = NULL;
    char *moreTxtFiles = NULL;

    directory = opendir (dirname);
    if(directory == NULL)
        return NULL;

     while ((ent = readdir (directory)) != NULL)
     {
         if(hasTxtExtension(ent->d_name))
         {
             fileCounter ++;
             moreTxtFiles = (char*) realloc (txtFiles, fileCounter * sizeof(char));

             if(moreTxtFiles != NULL)
             {
                 txtFiles = moreTxtFiles;
                 txtFiles[fileCounter - 1] = ent->d_name;
             }
             else
             {
                 freeMemory(txtFiles);
                 return NULL;
             }
         }
     }

     if(closedir(directory) < 0)
        return NULL;

    return txtFiles;
}

int main(int argc, char **argv)
{
    char **txtFilenames = getTxtFilenames("dir");
    if(txtFilenames == NULL)
        return -1;
    printf("%s\n", txtFilenames[0]);
    return 0;
}
4

2 に答える 2

3
  • txtFilenames[0][1]文字列ではなく文字です。
  • txtFiles[i][fileCounter - 1]ent->d_name文字ですが、文字列です。

i2 つのインデックス (と)を使用している理由がわかりませんfileCounter。文字列の配列を使用するだけです。も含める必要があります<string.h>

解決策はより簡単です:

#include <direct.h>
#include <stdlib.h>
#include <string.h>

char **f(const char *s)
{
    char **p = NULL;
    DIR *dir;
    struct dirent *ent;
    size_t i = 0;

    dir = opendir(s);

    while ((ent = readdir(dir)) != NULL) {
        if (hasTxtExtension(ent->d_name)) {
            p = realloc(p, (i + 1) * sizeof(char *));
            p[i] = malloc(strlen(ent->d_name) + 1);
            strcpy(p[i], ent->d_name);
            ++i;
        }
    }

    closedir(dir);
    return p;
}

以下は、このコードを改善するための非網羅的なリストです。

  • 再割り当てエラーを処理reallocします。失敗した場合は、メモリ リークが発生しています。
  • sディレクトリ エラーの処理: 特に、 が不適切なディレクトリ パスである場合を処理します。
  • 再割り当てを最適化します (反復ごとに使用しないでくださいrealloc)。
于 2012-10-19T17:18:09.203 に答える
2

Kirilenko が指摘した疑わしいインデックス作成は別として、最初の (そしてコア) エラーは次のとおりです。

char **txtFiles = allocMemory(1);
char **moreTxtFiles = allocMemory(1);

これは無害に思えますが、allocMemory は次のように定義されています。

char* allocMemory(int n)
{
    char *tab = (char *) malloc(n*sizeof(char));
    return tab;
}

txtFiles と moreTxtFiles はどちらもポインタへのポインタです。文字へのポインタではありません。割り当てられた単一の char へのポインターを返し、それをポインターへのポインターであると予想されるポインターに格納します

あなたの場合、リストエントリの割り当てに allocMemory を使用しないでください。文字列の割り当てに使用してください。

于 2012-10-19T17:39:11.960 に答える