【问题标题】:Difference between char argv[][7] and char *argv[] [duplicate]char argv[][7] 和 char *argv[] 之间的区别 [重复]
【发布时间】:2014-04-21 12:50:04
【问题描述】:

我最近学习了 C 语言。我读到有一些方法可以创建一个字符串数组。 char argv[][7]char *argv[] 之间有什么区别吗?如果没有你更喜欢用什么?

【问题讨论】:

标签: c++ c


【解决方案1】:

引用 C99 标准 §6.2.5 ¶20(类型)

数组类型描述了一个连续分配的非空集合 具有特定成员对象类型的对象,称为元素类型。 数组类型的特征在于它们的元素类型和数量 数组中的元素。

该标准在 §6.2.5 ¶22 中进一步说明

未知大小的数组类型是不完整类型。完成了, 对于该类型的标识符,通过在稍后指定大小 声明(带有内部或外部链接)。

数组下标运算符[] 的优先级高于* 运算符。因此,声明

char *argv[];

argv 定义为一个指向未知大小字符的指针数组,因为未指定数组大小。数组argv 是不完整的类型。这是假设上述语句中的表达式没有作为函数参数出现。由于数组argv 是不完整类型,因此您必须在使用前提供其大小信息。这意味着您应该将上述语句作为声明并在其他地方提供其定义,以便链接器将解析它。阅读本文以了解声明和定义之间的区别 -

What is the difference between a definition and a declaration?

// array declaration.
// this does not allocate space
// but only provides type information
// though of an incomplete type.
// argv must have internal or external linkage. 
extern char *argv[];

// definition of the array.
// complete information and
// allocates memory for it.
// in the same translation unit or 
// a different one.
char *argv[8];

您还可以使用数组初始化器列表来初始化数组,并且将从列表中推断出数组的大小。

// size of the array argv is determined
// explicitly to be 2
char *argv[] = {"Hello", "World"};

// the above is equivalent to
char *argv[2];
argv[0] = "Hello";
argv[1] = "World";

注意:以上只是为了演示数组初始化而没有明确提及它的大小。字符串字面量是只读的,所以语句最好写成

const char *argv[] = {"Hello", "World"};

如果它作为函数参数出现,那么它相当于char **argv,如

int main(int argc; char *argv[]);
// equivalent to
int main(int argc, char **argv);

以下语句中的数组也是如此。

char argv[][7];

上述语句将argv定义为char[7]类型的元素数组,即7字符数组。同样,未指定数组argv 的大小。因此,argv 是一个不完整的类型。假设它不作为函数参数出现,则应将语句放入声明中,因为它是不完整的类型,应在其他地方提供其定义。

// array declaration.
// argv must have internal or external linkage
extern char argv[][7];

// definition.
// in the same translation unit
// or a different one
char argv[10][7];

数组可以像前一种情况一样初始化,大小将由初始化列表隐式确定。

// size of the array argv is inferred from 
// the initializer list to be 3.
char argv[][7] = {{'a', 'b', 'c', 'd', 'e', 'f', 'g'},
                  {'a', 'b', 'c', 'd', 'e', 'f', 'g'},
                  {'a', 'b', 'c', 'd', 'e', 'f', 'g'}};

但是,如果数组表达式以函数参数的形式出现,则它等价于
char (*)[7],即指向7 字符数组的指针。

void foo(char argv[][7]);
// equivalent to
void foo(char (*)[7])

这是因为您不能将数组传递给函数。实际上传递的是指向数组第一个元素的指针。因此,函数中的数组参数被隐式转换为pointer to array element类型。请阅读本文了解更多详情 -

Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

【讨论】:

  • 你应该补充一点,这个语法在声明时初始化时是有意义的。
  • 澄清一下,char argv[][7]; 在文件范围内是一个暂定定义,它的类型不完整。在块范围内,这是违反约束的。
  • declaration char *argv[];(声明不是 C 中的语句,尽管它们是 C++ 中的)是相同的;它在块范围内无效,在文件范围内是暂定定义。
  • @MattMcNabb 谢谢。更新了我的答案。此外,链接到您的答案,这在这里非常有用。 :)
  • @MattMcNabb:这个问题被标记为 C 和 C++。暂定定义是 C 功能,在 C++ 中不存在(参见 C++11 附录 §C.1.2,第一段)。也许可以清楚地区分每种情况下的语言,但在我看来,问题是归咎于......
【解决方案2】:

尝试在cdecl.org 输入这些,你会看到

char argv[][7] :  declare argv as array of array 7 of char
char *argv[]   :  declare argv as array of pointer to char

换句话说,它们根本不是一回事。第一个是固定大小的字符数组的数组(和你想象的不同,不一定是 nul 终止的!),而另一个是指向字符的数组,它也可以用作“C 样式字符串”,那是一个可变长度的以 nul 结尾的字符序列(通常在 argv 后面的意图)。

【讨论】:

  • 它们不一样,在main中只有一个作为参数有效。
【解决方案3】:

首先,这段代码出现在哪里很重要。实际上这两个声明符在以下三个作用域中都有不同的含义:函数参数列表、块作用域和文件作用域。

函数形参列表中,char argv[][7]表示argv是一个指向7个字符数组的指针。 char *argv[] 表示argv 是一个指针数组。

如果我们使用main(),那么char argv[][7] 在这种情况下是不可移植的,并且可能会导致运行时错误。

块作用域(即在函数内)或文件作用域(全局变量),我们不应将事物称为argv,因为该名称通常用于main() 的参数,在其他语义不同的地方使用它是一种糟糕的风格。我们可能有:

char foo[][7] = { "the", "quick", "brown" };
char *bar[] = { "the", "quick", "brown" };

这两个都是合法的。在foo 中,字符都存在于存储foo 中,并且是可修改的。在bar 中,字符不可写。 bar 是指向字符串表的 3 个指针的数组(无论如何,在常见的实现中)。

顺便说一句,您应该在第二个中写 char const * 以确保类型安全。

foo 浪费了一些内存,因为字符串并不总是 7 个字符长,但是为每个数组条目分配了 7 个字符。 bar 增加了间接级别,但可能会占用更少的内存。

最后,我不确定你是否也在询问声明:

char foo[][7];
char *bar[];

没有初始化。如果是这样,那么这些在块范围内是非法的。在 C++ 中,它们在文件范围内是非法的。在 C 语言中,在文件范围内它们是 暂定定义`,这意味着它们声明了一个不完整的数组类型,您应该稍后在文件中完成该类型(可能通过使用我们已经讨论过的初始化示例之一) )。这是 C 的一个很少有用的特性。

【讨论】:

    【解决方案4】:

    如果您怀疑这些声明之间的基本区别,那么,

    char argv[][7];
    

    是一个 7 列的二维字符数组。不需要定义行数。

    char *argv[];
    

    是一个指向字符的指针数组。

    如果您将此与参数计数和参数值混淆,

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

    那请参考

    http://www.cprogramming.com/tutorial/c/lesson14.html

    What does int argc, char *argv[] mean?

    【讨论】:

      猜你喜欢
      • 2015-01-28
      • 1970-01-01
      • 2021-11-09
      • 2018-08-12
      • 2015-01-10
      • 2011-07-08
      • 1970-01-01
      • 2022-07-14
      • 2011-01-02
      相关资源
      最近更新 更多