2

プログラムの何が問題なのですか。値を出力しようとすると、セグ フォールトが発生します。

私の目的は、sample_function にいくつかの値を割り当てることです。

メイン関数では、構造を別の構造にコピーしたいと考えています。

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

typedef struct
{
    char        *name;
    char        *class;
    char        *rollno;
} test;

test *
sample_function ()
{
    test *abc;
    abc = (test *)malloc(sizeof(test));

    strcpy(abc->name,"Microsoft");
    abc->class = "MD5";
    abc->rollno = "12345";
printf("%s %s %s\n",abc->name,abc->class,abc->rollno);
return abc;

}

int main(){

test   *digest_abc = NULL;
   test   *abc = NULL;

abc = sample_function();

digest_abc = abc;
printf(" %s  %s  %s \n",digest_abc->name,digest_abc->class,digest_abc->rollno);

return 1;

}

ポインターは私にとって常に悪夢でした。理解できませんでした。

4

3 に答える 3

7
test * sample_function ()
{
    test *abc;

    strcpy(abc->name,"Surya");

abcここで何を指していると思いますか?答えは、実際には何も指していないということです。何かに初期化する必要があります。この場合は、メモリを割り当てることを意味します。

それでは、最初の問題を修正しましょう。

test * sample_function ()
{
    test *abc = malloc(sizeof(*abc));

    strcpy(abc->name,"Surya");

さて、abc何かを指すと、そこに物を保管できます!

しかし ...もポインターであり、それは何abc->name指していると思いますか? 繰り返しますが、実際には何も指していません。文字列を保存できる場所を指しているとは限りません。

それでは、2 番目の問題を修正しましょう。

test * sample_function ()
{
    test *abc = malloc(sizeof(*abc));

    abc->name = strdup("Surya");
    /* ... the rest is ok ... */
    return abc;
}

さて、最後の問題が 1 つあります。割り当てたばかりのメモリを決して解放しません (これはおそらくここでは問題ではありませんが、フルサイズのプログラムではバグになります)。

したがって、メインの最後に、次のようなものが必要です

    free(abc->name);
    free(abc);
    return 1;
}

最後の問題は設計の問題です。構造体には 3 つのポインターがあり、どれが動的に割り当てられ (そして解放する必要があります)、どれが文字列リテラルを指している (そして解放してはならない) かを思い出すのに役立つ唯一の規則です。

この規則がどこでも守られている限り、それは問題ありません。classまたはを動的に割り当てるとすぐにrollno、メモリ リークが発生します。文字列リテラルをポイントするとすぐにname、クラッシュやヒープの損傷が発生します。

japreissがコメントで指摘しているように、規則を強制する良い方法は、次のような専用の関数を作成することです。

void initialize_test(test *obj, const char *name, char *class, char *rollno) {
    obj->name = strdup(name);
    ...
}
void destroy_test(test *obj) {
    free(obj->name);
}
test *malloc_test(const char *name, ...) {
    test *obj = malloc(sizeof(*obj));
    initialize_test(obj, name, ...);
    return test;
}
void free_test(test *obj) {
    destroy_test(obj);
    free(obj);
}
于 2013-06-14T15:23:10.207 に答える
1

関数sample_functionでは、へのポインターを返しますabcアクティベーション レコードの編成方法が原因で、C でこれを行うことはできません。

アクティベーション レコードは、関数呼び出し、パラメーター、リターン アドレス、ローカル変数のアドレスなどに関連するすべての情報を含むデータ構造です。

関数を呼び出すと、新しいアクティベーション レコードがスタックにプッシュされ、次のようになります。

// Record for some function f(a, b)
| local variable 1  | <- stack pointer  (abc in your case)
| local variable 2  |
| old stack pointer | <- base pointer
| return address    |   
| parameter 1       |
| parameter 2       |
---------------------
| caller activation | 
|   record          |

関数から戻ると、この同じアクティブ化レコードがスタックからポップされますが、古いレコードにあった変数のアドレスを返すとどうなりますか?

// popped record
| local variable 1  | <- address of abc   #
| local variable 2  |                     #
| old stack pointer |                     # Unallocated memory, any new function
| return address    |                     # call could overwrite this
| parameter 1       |                     #
| parameter 2       |                     # 
--------------------- <- stack pointer 
| caller activation | 
|   record          |

ここで abc を使用しようとすると、割り当てられていないメモリ領域にアクセスしていると見なされるため、プログラムは正しくクラッシュします。

割り当てにも問題がありますが、他の回答で既にカバーされています。

于 2013-06-14T15:38:39.847 に答える
0

構造体へのポインターとしてsample_function宣言しますが、初期化することはありません。どこかの雑草を指しているだけです。次に、それを逆参照して値を保存しようとします-BOOM。abctest

プログラムにはポインターはまったく必要ありません。C では構造体を値で渡すことができます。

現在のものと同様のインターフェイスを維持したい場合は、構造体が実際に割り当てられ、ポインターが実際にそれらを指していることを確認するために、いくつかの動的割り当て ( malloc/呼び出し) を追加する必要があります。free

于 2013-06-14T15:22:40.520 に答える