char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
除了string 可以指向任意大小的字符串之外
string1Ptr 只能指向大小为 4 的字符串(否则
指针算术会出错),我之间没有任何区别
他们。
它们是绝对的、根本的不同,但 C 会费力地向你隐藏区别。
string 是一个数组。它标识一个连续的内存块,其中存储了它的元素。在此示例中,这些元素恰好是 char * 类型,但这是一个相对次要的细节。可以将这里类比为包含多个房间的房子——这些房间在物理上是房子的一部分,并且存在于房子的物理边界内。我可以随心所欲地装饰房间,但它们始终是那所房子的房间。
string1Ptr 是一个指针。它标识一块内存,其内容描述了如何访问另一个不同的内存块,其中驻留了 4 个chars 的数组。在我们的房地产类比中,这就像一张纸,上面写着“42 C 街,主卧室”。使用该信息,您可以找到房间并根据需要重新装修,就像在其他情况下一样。但是您也可以用定位器替换纸张,用于不同的房间,可能在不同的房子里,或者用随机文本,或者您甚至可以烧掉整个信封,而不会影响 C 街上的房间。
string1 就其本身而言,是一个数组数组。它标识存储其元素的连续内存块。这些元素中的每一个本身都是一个由 4 个chars 组成的数组,顺便说一下,它恰好是string1Ptr 可以指向的对象类型。
例如,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
它们似乎都执行相同的指针运算。(我的理由
假设string 和string1Ptr 几乎相似,除了
我上面说的区别)
... 这就是 C 隐藏区别的地方。要了解 C 数组的基本内容之一是,在几乎所有表达式中,数组类型的 * 值都是静默自动的转换为指针[指向数组的第一个元素]。这有时被称为指针“衰减”。因此,索引运算符是指针上的运算符,而不是数组上的运算符,实际上它在您的三个示例中确实具有类似的行为。事实上,string1 衰减到的指针类型与string1Ptr 的类型相同,这就是为什么您为后者提供的初始化是允许的。
但是你应该明白,这三种情况下操作的逻辑顺序是不一样的。首先,考虑
printf("%s\n", string1Ptr[2]);
这里,string1Ptr 是一个指针,索引运算符直接适用于该指针。结果等价于*(string1Ptr + 2),其类型为char[4]。作为数组类型的值,即转换为指向第一个元素的指针(产生char *)。
现在考虑
printf("%s\n", string1[2]);
string1 是一个数组,因此首先将其转换为指向其第一个元素的指针,从而产生char(*)[4] 类型的值。这与string1Ptr1 的类型相同,并且会相应地进行评估,如上所述。
但这个有点不同:
printf("%s\n", string[2]);
这里,string 是一个指针,因此索引操作直接应用于它。结果等价于*(string + 2),其类型为char *。不执行自动转换。
有什么理由使用其中一个?
很多,双向的,取决于您当时的特殊需求。一般来说,指针更灵活,尤其是在处理动态分配的内存时需要它们。但他们遭受的问题是
- 指针可能在范围内,但不指向任何东西,并且
- 声明一个指针不会为它创建任何指向的东西。另外,
- 即使一个指针在程序执行期间一次指向某个东西,并且它的值随后没有被程序写入,它仍然可以停止指向任何东西。 (这通常是由于指针比它指向的对象寿命更长。)
此外,它既可以是优势也可以是劣势
- 可以在其生命周期内任意多次将指针指定为指向新对象。
一般来说,数组更容易用于多种用途:
- 声明一个数组会为其所有元素分配空间。您可以选择在声明时为它们指定初始值,或者在某些(但不是全部)情况下使用默认初始化。
- 数组的标识符是有效的,并且无论它在范围内的任何地方都引用该数组。
- (可选)如果提供了初始化程序,则数组声明可以使用它来自动确定数组维度。
* 但只有几乎所有。有一些例外,最重要的是 sizeof 运算符的操作数。