Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何判断变量是2D数组、指针数组还是字符双指针?_C_Arrays_Pointers - Fatal编程技术网

C 如何判断变量是2D数组、指针数组还是字符双指针?

C 如何判断变量是2D数组、指针数组还是字符双指针?,c,arrays,pointers,C,Arrays,Pointers,假设我们有3个变量: char a[4][4]; char *b[4]; char **c; 假设上述所有变量都有正确的赋值。 没有代码错误 所有这些变量都可以使用[]运算符打印其值,如下所示: for( i=0; i<4; i++){ printf( "%s\n", a[i] ); } for( i=0; i<4; i++){ printf( "%s\n", b[i] ); } for( i=0; i<4; i++){ printf( "%s\

假设我们有3个变量:

 char a[4][4];
 char *b[4];
 char **c;
假设上述所有变量都有正确的赋值。 没有代码错误

所有这些变量都可以使用[]运算符打印其值,如下所示:

for( i=0; i<4; i++){
    printf( "%s\n", a[i] );
}
for( i=0; i<4; i++){
    printf( "%s\n", b[i] );
}
for( i=0; i<4; i++){
    printf( "%s\n", c[i] );

for(i=0;i我认为这是不可靠的。如果你对你的编译器了解很多,你也许可以推断出

&a[0][0]
距离
&a[3][3]

&b[0][0]
距离
b[0][3]

将其他内容保留为
c


但是编译器必须知道如何使它们可用,因此您很可能无法在不忽略编译时警告的情况下互换使用它们。

通过使用
sizeof()
可以区分这些变量,因为
sizeof()
将为不同的变量提供不同的大小。希望这对您有所帮助。

是的,您这样做是危险的,因为您不应该对分配进行假设。如果指针数组的指针指向局部变量-这是完全合法的-您的布局可能与i数组的布局相同新界南部

您必须区分两种情况:

A.动态评价

C运行时非常小。尤其是没有运行时类型信息。因此,仅凭语言的功能无法获得运行时引用的对象的类型

B.静态评价

但您的示例似乎希望在编译时确定对象的类型。C11为此支持
\u Generic
。它类似于
开关
,但不计算具有值
大小写
的普通表达式,而是对类型进行处理

如何判断变量是2D数组、指针数组还是字符双指针

有一种方法可以区分类型。
请注意,“2D数组”不是一种类型-更像是一种类型分类。
“双指针字符”可以被认为是类型<代码> char *

将对象的地址传递给
\u Generic()

输出

char [4][4]
char *[4]
char **
char [4]
char *
char *
char
char
char

\u Generic()
是对C语言的一个有用的补充,它的一些细节和正确的应用程序仍然具有挑战性。我希望上面的内容至少让OP能够部分区分对象

有趣的是,我能够使用一个更通用的
\u generic
,如下所示,在
a、b、c
之间具有相同的区别。我对
\u generic
的某些方面持谨慎态度,因为我怀疑实现定义的行为

#define xtype(X) _Generic((&X), \
    char (*)[][4] : "char [][4]", \
    char *(*)[]   : "char *[]", \
    char ***      : "char **", \
    char (*)[]    : "char []", \
    char **       : "char *", \
    char *        : "char", \
    default       : "?" \
)

使用
\u Generic()
a
是一个2D数组,
b
是指向char的指针数组
[4]
c
是指向char的指针。正如您所注意到的,所有这些指针都是不同的。但是,没有“测试”确定三者之间的区别。您可以跟踪您拥有的内容,并正确地传递和返回所需的类型。使用C11,您可以接受chux的正确建议,否则,这取决于您。@chux--
\u Generic()
无法区分
char*b[4]
char**c
,因为
b
在传递给
\u Generic()的表达式中衰减为
char**
;还是我遗漏了什么?@DavidBowling解决方案发布在下面。它使用了对象地址的类型,避免了转换。请查看声明。类型就在那里。如果“值”数组的大小等于指针数组的大小,这不起作用,因为值类型的指针大小相同(即在大多数平台上
long
whatevertype*
).有用吗?也许吧。我认为其基本原理是支持函数重载。这很公平,但如果是这样,那么就选择一种简单明了的语言功能。因为如果这个想法是在像C这样的语言中引入额外的元编程工具,那么你最好确保至少在“包含”。@doynax我在各种编译器中的经验是,存在一些细微的实现差异。与其说是由于编译器出错,不如说是由于C规范缺乏精确性。通常将来的版本会对这些细微的细节进行排序。在引入之前很难解决所有问题。OTOH,C是正在快速发展的语言很少有庞大的遗留代码库。@chux--(拍着自己的额头)很好的技巧。也许这应该是公认的答案。@doynax不幸的是\u Generic确实有一些问题……委员会在C11之后对其进行了澄清,例如,是否对参数应用了数组指针衰减,是否从右值参数中删除了限定符
#define xtype(X) _Generic((&X), \
    char (*)[][4] : "char [][4]", \
    char *(*)[]   : "char *[]", \
    char ***      : "char **", \
    char (*)[]    : "char []", \
    char **       : "char *", \
    char *        : "char", \
    default       : "?" \
)