我最近学习了C语言。我读到有一些方法可以创建字符串数组。char argv[][7]和char *argv[]有什么区别吗?如果没有,你更喜欢用什么?
发布于 2014-04-21 21:12:35
引用C99标准§6.2.5²20(类型)
数组类型描述具有特定成员对象类型(称为element类型)的连续分配的非空对象集。数组类型的特征在于它们的元素类型和数组中元素的数量。
该标准在§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?
发布于 2014-04-21 21:13:50
尝试在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后面)。
发布于 2014-04-21 22:00:43
首先,这段代码出现的位置很重要。实际上,这两个声明在以下三个作用域中都有不同的含义:函数参数列表、块作用域和文件作用域。
在函数的形参列表中,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的一个很少有用的特性。
https://stackoverflow.com/questions/23197806
复制相似问题