char argv [] [7]和char * argv []之间的区别

时间:2014-04-21 12:50:04

标签: c++ c

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

4 个答案:

答案 0 :(得分:5)

引用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"};

如果它显示为函数参数,则它等同于<{p>}中的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?

答案 1 :(得分: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-terminated!),而另一个是指向char的数组,它也可以作为“C样式字符串”,这是一个可变长度的nul终止字符序列(通常在argv后面的意图)。

答案 2 :(得分:0)

首先,这个代码出现的地方很重要。实际上,这两个声明符在以下所有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的一个很少有用的功能。

答案 3 :(得分:0)

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

char argv[][7];

是一个包含7列的2-D字符数组。定义不必要的行数。

char *argv[];

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

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

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

然后请参阅

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

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