您好我最近开始学习c指针并且无法理解为什么我得到的指针值不同于预期。 这是函数
int test(void){
int i,j;
int **p = (int **)malloc(2 * sizeof(int *));
p[0] = (int *)malloc(2 * sizeof(int));
printf("p[0] = %d\n",p[0]);
p[1] = p[0];
printf("p[1] = %d\n",p[1]);
for(i = 0; i < 2; i++){
for(j = 0; j < 2; j++) {
p[i][j] = i + j;
printf("p[%d][%d] = %d\n",i,j,p[i][j]);
}
}
printf("result p[0][0] = %d\n",p[0][0]);
return 0;
}
我期待从for循环中打印出p [0] [0] = 0,但是它等于1并且值似乎来自p [1] [0],我在这里缺少什么?
printf输出:
p[0] = 1224416
p[1] = 1224416
p[0][0] = 0
p[0][1] = 1
p[1][0] = 1
p[1][1] = 2
result p[0][0] = 1
答案 0 :(得分:5)
首先 - 您将int*
传递给printf()
,期望int
(%d
),使用(%p
)代替打印地址。< / p>
第二 -
p[1] = p[0];
p[0]
和p[1]
指针都指向同一地址。这意味着如果您修改一行(p[0]
),则第二行(p[1]
)也会被修改。
这是你问题的根源
我期待从for循环中打印出p [0] [0] = 0,但它是 等于1,值似乎来自p 1 [0],我是什么 在这里失踪?
+---+---+
| 0 | 0 |
+---+---+
^ ^
| |
| -------------------- p[0]
---------------------- p[1]
现在您修改p[1]
,它看起来像这样。换句话说,0
的值1
和p[0]
会被覆盖
+---+---+
| 1 | 2 |
+---+---+
^ ^
| |
| -------------------- p[0]
---------------------- p[1]
而不是p[1] = p[0]
,也可以在堆上分配p[1]
(不同的)内存。
p[0] = malloc(2 * sizeof(int));
p[1] = malloc(2 * sizeof(int));
现在p[0][0]
正确0
。
第三 - 重新制作malloc是多余的,可能会导致问题。 Do i cast malloc return value?
在C++
中,您可以( )使用内置运算符new
和delete
。
也不要忘记在堆上free()
分配的内存。
答案 1 :(得分:0)
逐行分解:
int **p = (int **)malloc(2 * sizeof(int *));
执行此行后,您将拥有以下内容:
+---+ +---+
p: | | --------> [0]: | | ---?
+---+ +---+
[1]: | | ---?
+---+
?
表示p[0]
和p[1]
包含不确定指针值(malloc
未初始化其分配的内存);这些指针值很可能无效(即,不对应于程序中对象的地址)。
p[0] = (int *)malloc(2 * sizeof(int));
执行此行后,您将拥有以下内容:
+---+ +---+ +---+
p: | | --------> [0]: | | ------> [0]: | ? |
+---+ +---+ +---+
[1]: | | ---? [1]: | ? |
+---+ +---+
同样,?
表示不确定的值。
p[1] = p[0];
执行此行后,您将拥有以下内容:
+---+ +---+ +---+
p: | | --------> [0]: | | ---+--> [0]: | ? |
+---+ +---+ | +---+
[1]: | | ---+ [1]: | ? |
+---+ +---+
现在,p[0]
和p[1]
指向同一块内存。因此,p[0][0]
和p[1][0]
会解析为同一个对象。如果我们展开你的循环,我们会看到以下分配顺序:
p[0][0] = 0 + 0;
+---+ +---+ +---+
p: | | --------> [0]: | | ---+--> [0]: | 0 |
+---+ +---+ | +---+
[1]: | | ---+ [1]: | ? |
+---+ +---+
p[0][1] = 0 + 1;
+---+ +---+ +---+
p: | | --------> [0]: | | ---+--> [0]: | 0 |
+---+ +---+ | +---+
[1]: | | ---+ [1]: | 1 |
+---+ +---+
p[1][0] = 1 + 0;
+---+ +---+ +---+
p: | | --------> [0]: | | ---+--> [0]: | 1 |
+---+ +---+ | +---+
[1]: | | ---+ [1]: | 1 |
+---+ +---+
p[1][1] = 1 + 1;
+---+ +---+ +---+
p: | | --------> [0]: | | ---+--> [0]: | 1 |
+---+ +---+ | +---+
[1]: | | ---+ [1]: | 2 |
+---+ +---+
这就是你看到你所看到的输出的原因。 p[0]
和p[1]
在您的输出中显示相同值的事实应该是一个很大的暗示。
如果p[1]
意在指向与p[0]
不同的数组,那么您需要为p[1]
分配另一个内存块来指向到:
p[1] = malloc( 2 * sizeof *p[1] );
作为一种惯例,你需要明确free
你分配的所有内容,即使你的程序即将退出 - 这只是一个很好的习惯:
free( p[0] ); // free each p[i] *before* freeing p
free( p[1] ); // assuming you added the malloc for p[1]
free( p );
如果这是C代码,则丢失对malloc
调用的强制转换 - 这是不必要的,它只会增加视觉混乱,如果您忘记包含stdlib.h
,在C89下可能会掩盖错误。编写这些调用的更好方法是
int **p = malloc( 2 * sizeof *p );
和
p[0] = malloc( 2 * sizeof *p[0] );
如果这是C ++代码,请使用new
和delete
代替malloc
和free
。
答案 2 :(得分:-1)
我回答了我自己的问题,因为它正在进行大量无关的讨论。
因为我有 指向第1行以与第2行共享相同的已分配内存 这里 - &gt; p [1] = p [0]; &#34; for&#34;循环使用第二行中的值覆盖第一行中的值。
示例函数来自cppinstitute.org CLA课程第5章。希望这将为将来像我这样的人提供更多的清晰度。