[英]C: malloc of string showing unexpected behaviour with double pointer and function calls
這是一個查詢,用於了解以下代碼即使出現錯誤也能正常工作。
據我所知,如果我想重新分配/重新分配傳遞給 function 的指針,則該指針需要作為雙指針傳遞。 錯誤地,我傳遞了一個指針,程序仍在運行。 我想它必須與指針作為字符串有關。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x;
x = (char *)malloc(10);
strcpy(x, "abcdefghi");
printf("befor main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
return 1;
}
OutPut:
befor main &x = 489275896; x = 20414480; x = abcdefghi; x_size = 9
befor func1 &x = 489275864; x = 20414480; *x = abcdefghi; x_size = 9
befor func2 x = 489275864; *x = 20414480; **x = abcdefghi; x_size = 9
after func2 x = 489275864; *x = 20414480; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 489275864; x = 20414480; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 489275896; x = 20414480; x = zyxwvutsrqponmlkjih; x_size = 19
我可以理解 output 直到func1
。 但是在func2
中修改后,大小和值如何返回到main
? 我沒有將x
作為雙指針從main
傳遞到func1
。 但不知何故,它仍然有效。
是因為它是char *
嗎?
編輯1:
在評論中建議編輯后:
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x, *y, *z;
x = (char *)malloc(10);
z = (char *)malloc(100);
y = (char *)malloc(100);
strcpy(x, "abcdefghi");
printf("befor main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
free(y);
free(z);
return 1;
}
Output:
befor main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = abcdefghi; x_size = 9
befor func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = abcdefghi; x_size = 9
befor func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = abcdefghi; x_size = 9
after func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = zyxwvutsrqponmlkjih; x_size = 19
該程序在引入多個 malloc 后仍然有效。
你所擁有的是未定義的行為。
以下是程序的重要部分(使用重命名的變量以便能夠在函數中區分它們):
void func2(char **x)
{
free(*x);
*x = malloc(SOME_OTHER_SIZE);
}
void func1(char *y)
{
func2(&y);
}
int main(void)
{
char *z = malloc(SOME_SIZE);
func1(z);
}
在main
function 中分配一些 memory,並使z
指向它。
然后調用func1
按值傳遞指針z
,這意味着指針被復制到func1
參數變量y
中。 現在你有兩個指針指向同一個 memory: z
在main
function 和y
在func1
function。
然后func1
調用func2
,但它通過不傳遞y
中值的副本而是傳遞指向變量y
本身的指針來模擬按引用傳遞。 當func2
free 是*x
指向的 memory 時,它會使指針*x
, y
和z
無效。 然后它重新分配*x
以指向一些新的 memory。 這將改變y
指向的位置,但不會改變z
,這仍然是無效的。
當func1
返回指針z
不再有效時,任何取消引用它的嘗試都將導致所述未定義行為。
從圖形上看,它可以是這樣的:
main
function分配memory並使z
指向它:
+---+ +-----------+ | z | --> | Memory... | +---+ +-----------+
調用 function func1
,傳遞z
的副本:
+---+ | z | -\ +---+ \ +-----------+ >-> | Memory... | +---+ / +-----------+ | y | -/ +---+
調用 function func2
,將指針傳遞給y
:
+---+ | z | -\ +---+ \ +-----------+ >-> | Memory... | +---+ +---+ / +-----------+ | x | --> | y | -/ +---+ +---+
function func2
free 是*x
指向的 memory :
+---+ | z | -\ +---+ \ >->??? +---+ +---+ / | x | --> | y | -/ +---+ +---+
function func2
分配新的 memory 並使*x
(因此y
)指向它:
+---+ | z | -->??? +---+ +---+ +---+ +---------------+ | x | --> | y | --> | New memory... | +---+ +---+ +---------------+
從上面應該很容易看出為什么func2
中的free(*x)
也會使main
function 中的z
無效。
現在有趣的部分,這就是為什么 function 中的z
指向的main
似乎已更改:這似乎是 ZCD69B4957F06CD818D7BF3D61980E291 新分配器的一個怪癖分配。 重要的一點是z
仍然無效。
您似乎認為使用char *x
(單指針)作為func1
的參數是錯誤的。 不過,我覺得完全沒問題。 func1
期望一個指向 char 作為參數的指針,或者基本上是一個 memory 地址,當取消引用時會給出一個字符或一堆字符。 當你寫func1(x);
在 main 中,您傳遞的是 x,一堆字符的地址,這正是func1
所期望的參數類型。
為什么 x 是一堆字符的地址? 在這種情況下,指針x
存儲一個數組(字符)的地址。 現在,你可能知道,如果你只寫一個數組的名字,你就會得到數組的基地址。 請參閱以下代碼:
#include <stdio.h>
#include <stdlib.h>
int main () {
int arr[5] = {1, 2, 3, 4, 5};
printf ("%d\n", arr); // address of the first element (1) of the array
// or, the base address of the array
printf ("%d\n", &arr[0]); // same as above
printf ("%d\n\n", *arr); // gives the first element of the array
int *x = malloc (5*sizeof (int));
*x = 1;
*(x+1) = 2;
*(x+2) = 3;
*(x+3) = 4;
*(x+4) = 5;
printf ("%d\n", x); // address of the first element (1) of the array
// or, the base address of the array
printf ("%d\n", &*(x+0)); // same as above
printf ("%d\n\n", *x); // gives the first element of the array
return 0;
}
output如下:
6356712
6356712
1
9768168
9768168
1
現在,為什么我們可以修改 x 指向的字符數組中的值? 因為我們已經傳遞了該數組的基地址。 我們可以取消引用該地址以訪問數組並使用它做任何我們想做的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.