2011-01-07 16 views
3

私はいくつかの基本に立ち往生しているようです。関数内の文字列へのポインタ

 
Test1: (null) 

Test2: 1234567890 

Test3: 1234567890 

Test4: 1234567890 

Test1の機能の何が問題になってい:

 
#include <stdlib.h> 

void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

void Test2(char **t) 
{ 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

void Test3(char *t) 
{ 
    strcpy(t, "1234567890"); 
} 

char * Test4(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
    return t; 
} 

int main() 
{ 
    char *t1 = NULL; 
    Test1(t1); 
    printf("\nTest1: %s\n", t1); 

    char *t2 = NULL; 
    Test2(&t2); 
    printf("\nTest2: %s\n", t2); 

    char *t3 = (char *)malloc(11); 
    Test3(t3); 
    printf("\nTest3: %s\n", t3); 

    char *t4 = NULL; 
    t4 = Test4(t4); 
    printf("\nTest4: %s\n", t4); 

    return 0; 
} 

この出力を与える:次のコードは、なぜ誰かが私に説明できますか?そして、なぜTest1とほぼ同じTest4が動作するのでしょうか? より一般的な質問:関数内の文字列を作成し、ポインタを返す正しい方法は何ですか?

+2

あなたがC++とCの両方をタグ付けしました、そして、これが依存あなたが使用しているC++では、 'std :: string'を使用するべきです(いくつかのキーを押す必要がない限り!)。Cでは、最初のアプローチ以外はすべて可能です。 – Nim

+0

はい、私は文字列クラスを使うことができますが、コアを理解したいので、ここでchar *を使用しています。 – clumpter

+0

Cでは、 'malloc()'の結果を* NOT *キャストします。推論のためにここを読んでください:http://stackoverflow.com/a/605858/1701799(基本的に 'void *'は自動的かつ安全に適切な型に昇格するからです)。私はこれがC/C++としてタグ付けされていることを知っていますが、そのような言語 "C/C++"はありません。これがC++の場合は、#include ではなく '#include 'を使用します。 C++では 'malloc()'/'free()'を使うことはほとんどありませんが、代わりに 'new/delete'やそれ以上のスマートポインタなどを使うでしょう.. – RastaJedi

答えて

0

あなたのTest1は、次の動作を行い、考えてみましょう:

char * x1 = NULL; 
Test1 (x1); 

のTest1は、以下の範囲内で行われる:

void test1 (char * t)// t -> x1 -> null 
{ 
    t = (char *) malloc (11); 
    // t now points a different place (the memory allocated), and the reference of x1 continues pointing to null 
    strcpy (t, "1234567890"); // t value is "1234567890" but x1 continues pointing to null 
    // Error, the memory that is pointed by t is never released 
} 
printf ("\nTest1:%s \n", t1);// Print the value of x1 (null) and the reference of t is lost 
+0

Cで 'malloc()'の戻り値をキャストしないように注意してください。 – RastaJedi

1

ことはあなたがこれを書いているので:

void Test1(char *t) 

変更これに:

void Test1(char* &t) 

のみ++ Cで動作します。デモここに:http://www.ideone.com/OYNQo

+2

C++のみでお願いします。 – Benoit

+0

これはデザインが悪く、プログラムの実際の動作が不明瞭です。開発者がポインタを理解していない場合、C++で開発するべきではありません。 –

+2

@PPそれでは、新しい開発者はどうやって学ぶべきですか? – villintehaspam

6

あなたが思うように機能パラメータが動作していません。値が "参照"ではなく "関数"の内部で一度変更された場合、それらの値の変更はその関数だけにローカルなので、関数が終了するとローカルの変更が破棄されます。

これを修正するには、ポインタ(char ** t)へのポインタを渡すか、参照(char & *)でポインタを渡して、一致するように関数コードを変更します。

2

は、機能を考えてみましょう:

 
void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

は今、tは、関数内のローカル変数です。それには何が含まれていますか?ポインタ値。最初にそのポインタ値はNULLを指しています。それはTest1(NULL);のように呼びます。最初の行、t = (char *)malloc(11)は、メモリの新たにmallocさピースにローカル変数tを再割り当てしかしながら

機能は私が前に言った覚えている、ので、あなたのmain()変数t1はまだNULLを指している返すとき、Test1関数は、ポインタの値のコピーを取ります。どの時点でもによって変更されたt1変数はありません。

の場合は、しかし、あなたは次のように機能をコード化:

 
void Test1(char **t) { 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

int main(void) { 
    ... 
    Test1(&t1); 
    ... 
} 

..thingsは異なるだろう。

2

ポインタを関数の引数として渡すと、ポインタは値渡しされます。したがって、ポインティングされたオブジェクトを変更することはできますが、関数内のポインタを変更すると、呼び出し元はそのポインタを認識しません。 Test1をでは

0
void Test1(char*& t) ; // This is a possible method signature. 
+0

@ Downvoter-前回のコメント「これはメソッドシグニチャであるべきです。ありがとう。 – Mahesh

1

t = (char *)malloc(11); 

線は機能のTest1にローカルである変数tに割り当てます。main()の変数t1は変更されないので、NULLポインタはprintfに渡されます。 Test4はmain()のt4を変更するために動作します。

関数で文字列を作成する「正しい」方法は、Test4(ただし、パラメータとしてtを指定する必要はありません)またはTest2(出力パラメータが必要な場合や必要な場合)です。これらの両方の場合、呼び出し側は後で文字列を解放する必要があります。 Test3も同様に動作しますが、呼び出し側はバッファが十分に大きいことを確認する必要があります。未定義の動作やメモリリークを防ぐには、バッファサイズをTest3のパラメータとして渡す必要があります。 Test3を使用する利点は、バッファがスタックに割り当てられ、メモリリークのリスクを排除できることです。

2

Test1には、変数tをポインタに渡します。 関数に渡されたパラメータはスタック内に存在し、関数が完了するとスタックは失われます。 main()でtがNULLになっているのは、mallocの結果をスタックに格納していて、そのスタックが存在しなくなったことです。

3

あなたは char* t1 = NULL; とポインタ変数T1(ないそのアドレス)を渡す Test1(t1); としての機能を呼び出すと、T1を定義しています。

のTest1がcharを期待している機能* void Test1(char *t)

ここtTest1関数にローカルな変数です。 main関数の変数t1ではなく、ローカル変数tを実際に変更していないため、関数内で行う変更は関数の外側には表示されません。

関連する問題