2

次のコードは、人の名前の紹介を単純に出力したものです。

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

typedef struct {
    char* firstname;
    char* lastname;
}Person;

void intro(void *person){
    printf("The person you are looking for is %s %s\n", ((Person *)person)->firstname, ((Person *)person)->lastname);
}

int main()
{
    Person *a = NULL;
    a = (Person *)malloc(sizeof(Person));

    char *first = NULL, *last = NULL;
    first = (char *)malloc(sizeof(char)*20);
    strncpy(first,"Bob", 20);
    last = (char *)malloc(sizeof(char)*20);
    strncpy(last,"Newmonson", 20)
    a->firstname = first;
    a->lastname = last;

    intro(a);

    return 0;
}

出力を生成します

The person you are looking for is Bob Newmonson

ただしintro(a)intro(&a)プロデュースに変更

The person you are looking for is �@ Newmonson

GDBで最初の試行を開き、10行目を中断すると、のアドレスが見つかりますperson=0x601010。名と姓の両方が、私が期待する場所に格納されます。これは、スタックの前の方で宣言されているためです0x04006b90x4006bd

に変更を加えてGDBを実行すると、何が得られますかintro(&a)。のアドレスはperson0x7fffffffffdd38なりました。0x601010名はを指し、姓はを指し0x4006dbます。

誰かが何が起こっているのか、そしてなぜ私が2番目のテストで姓の正しいアドレスにアクセスできるのかを説明するのを手伝ってもらえますか?

編集 :

誰もがそれについて尋ね続けているように見えるのでvoid *、私が含めなかったこのコードのスレッド部分のためでした。

4

4 に答える 4

4

これaは、がすでにPerson構造体へのポインタであるためです。したがってintro(&a)、そのポインタへのポインタを渡しますが、そのintro()引数をへのポインタとして扱いますPerson

また、intro()Personでの作業を目的としている場合はPerson *、ではなく引数を宣言する必要がありますvoid *

于 2012-12-05T03:11:50.723 に答える
3

ポインタ変数内に保持されてaいるアドレスは、によって使用されている実際のメモリ位置のアドレスと同じではありませんa

そして、like0x601010のアドレスは「低」メモリアドレスであり、通常はヒープのどこかにあります。のようなアドレス0x7fffffffffdd38は非常に「高い」アドレスであり、通常はスタック上にあります。つまり、スタック上&aの変数の実際のアドレスを提供し、aその値を関数に渡します0x601010。ポインタ変数内に格納されている値ではなく、aから返された割り当てられたメモリバッファの最初のアドレスを表しますmalloc

于 2012-12-05T03:13:12.363 に答える
0

初めに:

/* allocate space for 20 characters and make 'first' point to that space. */
first = (char *)malloc(sizeof(char)*20);
/* now make 'first' point to the string Bob. Leak the memory that was allocated before. */
first = "Bob";
/* Rinse, lather, repeat. */
last = (char *)malloc(sizeof(char)*20);
last = "Newmonson";

intro(&a)次に、使用すると予期しない結果が生じる理由を説明します。

introタイプの構造体を指すと想定するポインタを期待しますPerson。へのポインタを作成し、Personそれにスペースを割り当てます。

呼び出すintro(a)と、ポインターがイントロPersonへのポインターとして渡され、voidイントロはそれをイントロへのポインターとして扱いPerson、すべてが正常に行われます。

intro(&a)ただし、呼び出しはのアドレスa取得して渡します。ここでも、introへのポインタとして処理しようとしPersonますが、渡したのはへのポインタであるため、これは機能しませんPerson。オレンジを取得していると思われる関数にトマトを渡します。どちらも果物で、ジュースを手に入れることができますが、朝食においしいオレンジジュースの代わりにおいしいトマトジュースを添えると、あまり幸せにならないでしょう。

呼び出しによって名が壊れて姓が出力される理由を尋ねる場合intro(&a)、答えは運が良かったためです。姓の文字列がたまたまメモリ内の正しい位置にあったからです。

于 2012-12-05T03:22:49.000 に答える
0

これを試して:

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

typedef struct {
    char* firstname;
    char* lastname;
}Person;

void intro(Person *person){
    printf("The person you are looking for is %s %s\n", (person)->firstname,   (person)->lastname);
}

int main()
{
    Person *a = NULL;
    char *first = NULL, *last = NULL;
    a = (Person *)malloc(sizeof(Person));


    first = (char *)malloc(sizeof(char)*20);
    first = "Bob";
    last = (char *)malloc(sizeof(char)*20);
    last = "Newmonson";
    a->firstname = first;
    a->lastname = last;

    intro(a);

    return 0;
}

それが役に立てば幸い...

于 2012-12-05T03:23:45.210 に答える