指针重新分配

时间:2015-09-17 16:15:44

标签: c pointers

所以我有两个功能:

int main(int argc, char *argv[]) {
    int i = 1;
    printf("Pointer of i in main: %p\n", &i);
    printf("Value of i in main %d\n", i);
    change_pointer(&i);
    printf("Value of i in main %d\n", i); // doesn't change is equal to 1
    printf("Pointer of i in main: %p\n", &i); // doesn't change
    return 0;
}

void change_pointer(int *i) {
    printf("Pointer of i in change_pointer: %p \n", i); // same as main
    int j = 2;
    printf("Pointer of j in change_pointer: %p\n", &j);
    i = &j;
    printf("Pointer of i in change_pointer after i = &j: %p\n", &i); 
    // different to &j memory location it is 4 bytes after it
    printf("Value of i in change_pointer %d\n", *i); // is equal to 2
}

我的问题是:

1)当我将i的地址分配给j的地址时发生了什么,为什么它正好在4个字节之后呢?

2)编译器是否更改i变量的地址,以便ij不具有相同的地址?

3)如果是这样,为什么编制者会这样做而不提醒我呢?

4) *i在该地址处的值如何为NULL,编译器是否会复制j的值?

5 个答案:

答案 0 :(得分:1)

一切都很正常。 C总是按值传递变量。当你拨打change_pointer(&i);时,你传递了i的地址,这意味着通过那个指针你现在可以改变i的值。

但在change_pointer中,i是一个最初包含主i地址的局部变量。当您更改其值以使其指向j时,您只需更改本地指针。所以返回时没有任何改变。

您可以通过以下方式更改i

int main(int argc, char *argv[]) {
    int i = 1;
    printf("Pointer of i in main: %p\n", &i);
    printf("Value of i in main %d\n", i);
    change_value(&i);
    printf("Value of i in main %d\n", i); // is now 2
    printf("Pointer of i in main: %p\n", &i); // doesn't change
    return 0;
}

void change_value(int *i) {
    printf("Pointer to i in change_pointer: %p \n", i); // same as main
    int j = 2;
    printf("Pointer to j in change_pointer: %p\n", &j);
    *i = j;
    printf("Value of i in change_pointer %d\n", *i); // is equal to 2
}

答案 1 :(得分:0)

  

编译器是否更改了i变量的地址,以便i和j不会有相同的地址?

编译器没有更改地址,它们都有不同的地址,因为它们是不同的变量。

j

当然,它将与&i不同,因为i将在指针change_pointer的函数地址中给出。

在你的函数*i -

2的值j不是因为i的值被复制,而是指针j指向2的地址和值{{1}在那个地址。

如果您这样写,请change_pointer -

 *i=j;        // instead of i=&j; 

然后imain的值将更改为2

答案 2 :(得分:0)

  

1)当我将i的地址分配给地址时发生了什么   j,为什么它恰好是4个字节后呢?

我的函数现在指的是本地j的地址,而不是指主要的地址。

  

2)编译器是否改变了i的变量的地址   和j不会有相同的地址?

不,你可能正在看两个不同的值& j和& i,其中正确的值应该是i和& j。

  

3)如果是这样的话,为什么编制者这样做而不提醒我呢?

问题2不正确因此没有回答这个问题。

  

4)* i在该地址处的值如何为NULL,是否为编译器   复制j的值超过?

我所引用的值是j,即2,我无法在任何地方看到NULL

答案 3 :(得分:0)

  1. (注意:您实际上将j的地址分配给i。)然后比较j的地址和i的地址。它们在内存中相邻,因为它们在堆栈中彼此相邻。 (Google"堆栈布局解释"了解有关堆栈如何工作及其用途的更多信息。)

  2. 对于简单的用例,可以想象编译器将每个变量名称转换为地址的偏移量。每个名称代表不同的偏移量。即i可能表示0,j可能是4.偏移量应用于当前堆栈帧的自动变量和函数参数以及外部的某个常量地址(程序的某个段的开头)或静态变量。保证不同的对象(例如由i和j表示的对象)具有不同的位置,即存储器中的地址。这是编译器中最基本,最重要的工作之一。不要混淆:你在这里有两个不同的变量,它们都被命名为i:一个在main()中,一个在change_pointer()中。它们表示两个不同的对象,因此它们位于存储器中的不同位置。作为change_pointer()的参数的i是具有地址且包含地址的指针。这可能看起来令人困惑。 如果您在i中输出&i而不是change_pointer() ,则会获得i中包含的值,即j的地址

  3. 编译器不会更改任何地址。更复杂的运行时垃圾收集在运行时更改对象的位置(以及因此地址)(特别是大多数Java VM和CLR);但是他们必须跟踪对它们的所有引用并同时以原子方式改变它们。 C和C ++的基本运行时间通常不能做到这一点。

  4. 我不明白这个问题。您指的是哪个i?你在哪里看到一个NULL?

答案 4 :(得分:0)

在C中,所有参数都按值传递。所以函数change_value()中传递的参数是一个副本,坐在堆栈上。当您通过以下方式直接分配给“i”时:i = &j;所有正在更改的内容都是堆栈中地址的副本。设置调用者的'i'变量使用:'* i = j;'由于& i指向调用者堆栈上的某个位置,因此该地址无法真正改变,但可以更改调用者堆栈中“i”的内容。再次,通过:*i = j;