指向 char 指针数组的指针与指向 char 指针的指针(或 char** argv 与 char* (*argv)[])

Posted

技术标签:

【中文标题】指向 char 指针数组的指针与指向 char 指针的指针(或 char** argv 与 char* (*argv)[])【英文标题】:Pointer to array of pointer to char vs. pointer to pointer to char (or char** argv vs. char* (*argv)[]) 【发布时间】:2018-04-05 15:57:01 【问题描述】:

我今天与一位同事讨论了他(对我而言)不寻常的“主要”功能签名。他喜欢这样声明:

int main(int argc, char* (*argv)[]) 
   printf("at index 0: %s\n", (*argv)[0]);

而我通常会写如下代码:

int main(int argc, char** argv)

    printf("at index 0: %s\n", argv[0]);

有时我会写“char* argv[]”,以更清楚地表明 argv 是一个指向字符的指针数组。

第一个示例中的代码在编译时出现警告

warning: second argument of ‘main’ should be ‘char **’

但它有效。我的问题是为什么代码有效,因为我预计会由于取消引用 argv 而崩溃。编译器是否知道函数签名不同,并允许 (*argv) 在这里作为一种“无操作”?

为了了解发生了什么,我编写了以下示例,令我惊讶的是,它也没有崩溃并打印“first”(但编译器会发出警告):

#include <stdio.h>

int my_function(int argc, char* (*argv)[])

    printf("at index 0: %s\n", (*argv)[0]);


int main(void)

    char* stringArr[] =  "frist",
                          NULL ;
    size_t stringArrSz = sizeof(stringArr)/sizeof(*stringArr);

    return my_function(stringArrSz, stringArr);

我曾预计我需要传递“&stringArr”(使用地址运算符)才能使代码运行。这 - 当然 - 也有效,并且修复了编译器警告。

如果我的问题不清楚,请告诉我,非常感谢任何帮助!

【问题讨论】:

检查这里 - ***.com/questions/27213580/… 请记住,对于函数参数,[] 被翻译为指针。所以char *argv[] 真的是char **argv。现在想想char *(*argv)[] 可能会被翻译成什么... 另请注意,C 规范告诉main 的参数类型是什么。偏离这一点,您的程序将不再有效。我建议你阅读例如this main function reference. @Someprogrammerdude 如果我没记错的话char* (*argv)[] 应该翻译成char*** argv。我不明白的是为什么取消引用 argv 仍然有效,即使在将 argv 传递给 main 时未使用运算符的地址。 @karacho84 - 您的评论与您的​​问题不同!哪一个是正确的?无论如何 - char* (*argv)[] 是错误的。警告类型告诉你。 【参考方案1】:

我的问题是为什么代码可以工作,因为我预计会由于取消引用 argv 而导致崩溃。编译器是否知道函数签名不同,并允许 (*argv) 在这里作为一种“无操作”?

“看起来按预期工作”是未定义行为的可能结果之一。

仍然从运行时环境为argv 传递了一个有效的指针值,所以我不希望代码仅仅因为访问argv[0] 而崩溃,不管它是如何声明的。

当您尝试访问 argv[1]argv[2] 等时,事情会变得有趣。虽然 C 语言本身并不能保证指向不同对象类型的指针具有相同的大小,但实际上它们在大多数情况下都可以做到现代架构,如x86; IOW,sizeof (T *) == sizeof (T **) == sizeof ( T *** )。因此,p + 1 应该为该平台上的每种类型产生相同的字节偏移量。

不过,您的同事正在与灾难调情。类型确实很重要,如果您在不同指针类型具有不同大小的系统上工作,将argv 声明为char *(*)[] 而不是char *[]char ** 可能会产生一些意想不到的后果。

【讨论】:

以上是关于指向 char 指针数组的指针与指向 char 指针的指针(或 char** argv 与 char* (*argv)[])的主要内容,如果未能解决你的问题,请参考以下文章

qt 中能不能用一个指向数组的指针对另一个数组赋值

数组名相当于一个指针,哪数组指针char *p[],不就变成一个二级指针?

char **argv 与char *argv[]

增加指针与增加指针指向的数组元素有啥区别?

C语言_18函数指针与函数指针数组

如何在C中对指向char的指针数组进行qsort?