12

私は確かにそれを知っています

function(int *a); function(int a[]);

Cの場合も同じですが、function(int a [])はfunction(int * a)に変換されます

int *a = malloc(20);
int b[] = {1,2,3,4,5};

これら2つは同じではなく、1つ目はポインター、2つ目は配列です。function(b)を呼び出すとどうなりますか?(function(int * a))bがスタック上にあることがわかっているので、その関数にどのように渡されますか?

第二に、文字列:

char *c1 = "string";
char c2 [] = "string";

この場合、c1がどこにあるかわかりません。また、c2がスタック上にあると思います。関数が次のようになっているとします。function(char * c)、これはfunction(char c [])と同じで、function(c1)およびfunction(c2)を呼び出すとどうなりますか?文字列は参照によって渡されます。価値?

4

6 に答える 6

20

ここで重要なポイントがあります。たとえば、すべてが実際に値によって渡されます。これにより、のコピーが渡さaれますfoo()(これはたまたまメモリへのポインタです)。

int *a = malloc(20);
foo(a);

そのため、このようなことを行うと、ポインタは実際には変更されfoo()ませんが、ローカルコピーが変更されます。amain()

foo(int *a)
{
  a = NULL; /*changes local copy of the pointer*/
}

つまり、foo()のローカルコピーを使用して、「a」が指すメモリを変更できますが、のポイントを変更することaできません。a main()

ここで、「参照によって」何かを渡すには、ポインターからポインターへのコピーを関数(a-> b-> memoryなど)に渡します。

int *a = malloc(20);
foo(&a);

したがって、に割り当ててfoo()ポインタを変更すると、次のようになりmain()ます。

foo(int **a)
{
  *a = NULL; /*changes the pointer in main */
}

ここで、他のいくつかの質問に答えるために、配列名を使用すると、配列の最初の要素へのポインターに変換されます。

int *a = malloc(20);
int b[] = {1,2,3,4,5};
foo(a);
foo(b);

最後の2つの関数呼び出しは、どちらもメモリの最初の要素へのポインタを渡すという点で同等です。違いは、のメモリがaヒープに割り当てられているのに対し、のメモリはbスタックに割り当てられていることです。

最後に、文字列は、同じ原則が適用されるという点で似ていますが、最初の文字列は定数文字列リテラルであり、として定義する必要があります。どこでも変更しようとしないconstでください。ただし、2番目の文字列は変更できます。

const char *c1 = "string";
char c2 [] = "string";

 

于 2012-11-19T07:38:52.680 に答える
6

K&R2より

When an array name is passed to a function, what is passed is the 
location of the initial element. Within the called function, this 
argument is a local variable, and so an array name parameter is a 
pointer, that is, a variable containing an address.

引数の宣言char c2 [] は、 の単なる構文糖衣ですchar* c2

C のすべてが値として渡されます。詳細については、このリンクを使用してください。

また、Eli Bendersky には、同じことを論じた優れた記事があります。

于 2012-11-19T07:36:40.050 に答える
0
      int *a = malloc(20);
                         ===========
    |a|----------------> | | | | | |  
                         ===========
    a is a pointer          20 bytes on heap each of 4 bytes 
    to int on stack 


    int b[] = {1,2,3,4,5};


     =================================
     |   1 |  2   |  3  |  4  |  5   |
     =================================
     b[0]   b[1]    b[2]  b[3]   b[4]   
Full array is on stack


char *c1 = "string";
char c2 [] = "string";


In case of "string" it's string literal and allocated on readonly memory.

In first case , |c1| ----> |s|t|r|i|n|g|\0|

In second case ,  ============================================
                  | s  |  t   |   r  |  i  |  n  |  g  | \0  |
                  ============================================
                  c2[0] c2[1]   c2[2] c2[3] c2[4] c2[5]  c2[6]

The full char array is on stack.
于 2012-11-19T07:39:38.293 に答える
-1

編集:以下のこの答えは間違っています。
"配列は常に参照によって渡されます。 " これは誤りです。その部分については、 iabdalkaderの回答を参照してくださいwhy。ただし、配列のコピーを関数に渡すために、構造体のトリックでカプセル化するために、この回答を以下に示します。


配列は常に参照 (ポインター) によって渡されます。

値を使用してそれらを渡したい場合は、struct. その結果、元の配列のコピーを操作することになります。以下に例を示します。

foo の最初の引数は、配列のコピーを保持する構造体オブジェクトです。2 番目の引数は配列参照です。

#include <stdio.h>

struct a{
    int i[2]; // An array encapsulated in struct.
};

void foo(struct a b, int j[]){
    b.i[0]=30;
    j[1]=30;
}

int main(){
    struct a c;
    c.i[0]=10;
    c.i[1]=20;
    printf("Before %d %d\n",c.i[0], c.i[1]);
    foo(c, c.i);
    printf("After %d %d \n",c.i[0], c.i[1]);
    return 0;
}


$ ./a.out 
Before 10 20
After 10 30 
于 2012-11-19T07:29:11.373 に答える
-2

配列が参照渡しされるのはなぜですか? ポインターアドレスを値で渡した ので、そのポインターを変更すると、ポインターアドレス自体ではなく、ポイントされたメモリが変更されるため、ポインターを変更しても、関数から元のポインターが置き換えられないため、その関数内に a = ANOTHER_POINTER と入力すると、関数を使用した後、渡された配列を失うことはありません

int a[]はint aと同等で あり、関数 foo(int a) を呼び出すと、ポインター アドレスが取得されます。

ポインター自体を変更したい場合は、参照 foo(int *& a) でポインター アドレスを渡すことができるので、ポインター アドレス a = ANOTHER_POINTERを変更すると、ポインターのアドレスが変更されます。

于 2012-11-19T07:50:57.017 に答える