请看下面的代码。它尝试将数组作为 achar**
传递给函数:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
事实上,我只能通过显式转换&test2
为char**
已经暗示这段代码是错误的来编译它。
不过,我想知道它到底有什么问题。我可以传递一个指向动态分配数组的指针的指针,但我不能传递指向堆栈上数组指针的指针。当然,我可以通过首先将数组分配给临时变量来轻松解决该问题,如下所示:
char test[256];
char *tmp = test;
test[0] = 'B';
printchar(&tmp);
Run Code Online (Sandbox Code Playgroud)
不过,有人可以向我解释为什么不能直接投射char[256]
到char**
吗?
Eri*_*hil 38
test
is an array, not a pointer, and &test
is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
sizeof
.&
.In &test
, the array is the operand of &
, so the automatic conversion does not occur. The result of &test
is a pointer to an array of 256 char
, which has type char (*)[256]
, not char **
.
To get a pointer to a pointer to char
from test
, you would first need to make a pointer to char
. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Run Code Online (Sandbox Code Playgroud)
Another way to think about this is to realize that test
names the entire object—the whole array of 256 char
. It does not name a pointer, so, in &test
, there is no pointer whose address can be taken, so this cannot produce a char **
. In order to create a char **
, you must first have a char *
.
eml*_*lai 29
因为test
不是指针。
&test
为您提供一个指向数组的指针,类型为char (*)[256]
,与不兼容char**
(因为数组不是指针)。这会导致未定义的行为。
的类型test2
是char *
。因此,类型&test2
将char **
是与参数的类型兼容x
的printchar()
。
的类型test
是char [256]
。因此,类型&test
将char (*)[256]
是不带参数的类型兼容x
的printchar()
。
让我向您展示test
和的地址差异test2
。
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Run Code Online (Sandbox Code Playgroud)
这里要注意:
的输出(存储器地址)test2
和&test2[0]
是数字相同,并且它们的类型也是相同的,其是char *
。
但是test2
和&test2
是不同的地址,它们的类型也不同。
的类型test2
是char *
。
的类型&test2
是char **
。
x = &test2
*x = test2
(*x)[0] = test2[0]
Run Code Online (Sandbox Code Playgroud)
的输出(存储地址)test
,&test
并且&test[0]
是数字相同但它们的类型是不同的。
的类型test
是char [256]
。
的类型&test
是char (*) [256]
。
的类型&test[0]
是char *
。
如输出所示&test
,与&test[0]
.
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Run Code Online (Sandbox Code Playgroud)
因此,您遇到了分段错误。