0

基本的に最終的に UNIX ファイル システムをエミュレートすることになっている C プロジェクトをデバッグするために、次のコードを作成しました。私は、一見同じように見える 2 つのコード ブロックが異なる出力を生成する理由を突き止めようと、頭を悩ませてきました。main() ファイルに同じコード行を入力して、関数 mkfs() と同じ動作をシミュレートすると、完全に機能しますが、関数を使用しようとすると (文字通り同じコード行! !!!!!)、単に RUN FAILED と表示されます。現在コメントアウトされている main() 関数内のコードを実行すると、うまく機能し、実際にコンソールに「/」が出力されますが、ファイルシステムへのポインターを作成しようとすると、mkfs() を呼び出してから、同じ文字列を出力しても、うまくいきません。

私は何かを理解していないに違いない。コードは次のとおりですが、構文の強調表示が必要な場合は、pastebin への小さなリンクを次に示します: http://pastebin.com/9yCB1iND

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

typedef struct directory {
    const char *name;
    struct file *f;
    struct directory *dir;
} Directory;

typedef struct file {
    const char *name;
    struct file *next;
    struct file *prev;
    Directory *parent;
} File;

typedef struct filesystem {
    Directory *rt;
    Directory *cd;
} Filesystem;

/* The function mkfs() initializes the Filesystem. It takes a pointer to a 
 * filesystem as its single parameter and allocates the memory needed ( it 
 * allocates the space needed to accomodate the two Directory pointers 
 * that a filesystem has). */
    void mkfs(Filesystem *files){

    /*The first malloc creates enough space for Filesystem itself*/
    files = malloc(sizeof(Filesystem));

    /*The second malloc creates enough space for a root Directory*/
    files->rt = malloc(sizeof(Directory));

    /*We make a character array with a single slash that represents root*/
    char nv[] = "/";
    /* nv is a pointer to the first element in the array nv[]. 
     * We point 'files->rt->name' to the first character in the array nv[]. */
    files->rt->name = nv;
    /* Finally, we set files->cd to point to whatever files->rt pointed too, 
     * which is the current directory "/" */
    files->cd = files->rt;
}


int main(void) {
    /*
    Filesystem *files;
    files = malloc(sizeof(Filesystem));
    files->rt = malloc(sizeof(Directory));
    char nv[] = "/";
    files->rt->name = nv;
    files->cd = files->rt;
    printf("%s", files->cd->name);

        ---------------------------------------------------------------------------
        Why does the FOLLOWING code not work when the ABOVE code should be "the same" ?
        ---------------------------------------------------------------------------
    */

    Filesystem *f;
    mkfs(f);
    printf("%s", f->cd->name);

    return (EXIT_SUCCESS);
}
4

2 に答える 2

2

こんな風に電話したら

mkfs(f);

のコピーがfmkfs に渡されます。そのコピーは変更されたものです (つまり、malloc の戻り値はそのコピーを初期化するために使用されます。ただし、finmainは変更されません。

したがって、あなたがするとき

printf("%s", f->cd->name); 

メイン - 初期化されていないポインターにアクセスしているため、未定義の動作です。

プログラムには他の問題もあります

あなたnvは関数に対してローカルです。人生は関数が戻るまでだけです。それは間違っています。

于 2013-03-29T08:58:46.910 に答える
1

関数mkfs内:

char nv[] = "/";
files->rt->name = nv;

nv自動保存期間を持つ配列であり、実行がこの関数のスコープ外に出ると存続期間が終了し、ダングリング ポインターfiles->rt->nameになり、その逆参照は未定義の動作につながります。動的に割り当てる必要があります。files->rt->name

mkfsまた、 function は へのポインターを受け取ることに注意してくださいFilesystem。これは、渡されたポインターの単なるコピーです。ポインター自体に加えられた変更は呼び出し元には表示されません。つまり、を呼び出すとprintf("%s", f->cd->name);、初期化されていないポインターが逆参照され、未定義の動作が発生します。mkfsメモリを割り当ててポインタを正しく初期化したい場合は、このポインタのアドレスを渡す必要があります。

void mkfs(Filesystem **files) {
    *files = malloc(sizeof(Filesystem));
    (*files)->rt = malloc(sizeof(Directory));
    char nv[] = "/";
    (*files)->rt->name = malloc(strlen(nv) + 1);
    strcpy((*files)->rt->name, nv);
    (*files)->cd = (*files)->rt;
}

int main(void) {
    Filesystem *f = NULL;  // <-- it's good to keep your variables initialized
    mkfs(&f);
    ...
}

そして、関数がこのポインターが指すメモリを変更する必要がないが、ポインター自体は変更しない場合は、次のようになります。

void mkfs(Filesystem *files) {
    files->rt = malloc(sizeof(Directory));
    char nv[] = "/";
    files->rt->name = malloc(strlen(nv) + 1);
    strcpy(files->rt->name, nv);
    (*files)->cd = files->rt;
}

int main(void) {
    Filesystem *f;
    f = malloc(sizeof(Filesystem));
    mkfs(f);
    ...
}
于 2013-03-29T09:00:15.273 に答える