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

时间:2017-10-24 18:24:29

标签: c arrays pointers main

我今天与同事就他(对我来说)不寻常的“主要”功能签名进行了讨论。他喜欢这样声明:

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)作为一种“无操作”吗?

试着理解发生了什么,我写了下面的例子,令我惊讶的是它也没有崩溃并打印“第一”(但是编译器发出警告):

#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);
}

我原本以为我需要传递“&amp; stringArr”(使用地址运算符)来运行代码。那 - 当然 - 也有效,并修复了编译器警告。

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

1 个答案:

答案 0 :(得分:1)

  

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

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

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

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

但是,你的同事正在调查灾难。类型确实很重要,如果您正在使用不同指针类型具有不同大小的系统,则将argv声明为char *(*)[]而不是char *[]char **可能会产生一些意外后果。