指针数组和指向数组的指针之间的区别?
Difference between array of pointers and pointer to array?
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
//I want to know differences between string1Ptr(pointer to array mentioned in question) and string(array of pointers mentioned in question). I only typed string1 here to give string1Ptr an address to strings
除了 string
可以指向任何大小的字符串而 string1Ptr
只能指向大小为 4 的字符串(否则指针运算会出错)之外,我看不到它们之间的任何差异。
例如,
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
的原因除了我上面提到的差异之外几乎相似)
那么string和string1Ptr有什么区别呢?有什么理由使用一个而不是另一个吗?
PS: 我是新手所以请放轻松。
另外,我确实检查了C pointer to array/array of pointers disambiguation,它似乎没有回答我的问题。
string1
与string
的区别与
的区别相同
char s1[4] = "foo";
char *s2 = "foo";
s1
是4个字符的可写数组,s2
是指向字符串字面量的指针,不可写。参见 Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?。
因此在您的示例中,可以执行 string1[0][0] = 'f';
将 string1[0]
更改为 "foo"
,但 string[0][0] = 'f';
会导致未定义的行为。
此外,由于 string
是一个指针数组,您可以重新分配这些指针,例如string[0] = "abc";
。您不能分配给 string1[0]
因为元素是数组,而不是指针,就像您不能重新分配 s1
.
string1Ptr
起作用的原因是因为 string1
是一个 char 的二维数组,保证是连续的。 string1Ptr
是一个指向 4 个字符数组的指针,当您对其进行索引时,您会增加该字符数,这将使您到达 string1
数组的下一行。
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
Besides the fact that string
can point to strings of any size and
string1Ptr
can only point to strings of size 4 only(otherwise
pointer arithmetic would go wrong), I don't any differences between
them.
它们完全不同,根本不同,但 C 会费些力气向您隐藏区别。
string
是一个 数组 。它标识存储其元素的连续内存块。在此示例中,这些元素恰好属于 char *
类型,但这是一个相对次要的细节。人们可以在这里类比一个包含多个房间的房子——这些房间在物理上是房子的物理边界的一部分,并且存在于房子的物理边界内。我可以随心所欲地装饰房间,但它们永远是那个房子的房间。
string1Ptr
是一个 指针 。它标识一块内存,其内容描述如何访问另一个不同的内存块,其中驻留一个 4 char
的数组。在我们的房地产比喻中,这就像一张纸,上面写着“42 C 街,主卧室”。使用这些信息,您可以找到房间并根据需要重新装修它,就像在其他情况下一样。但是你也可以用不同房间的定位器替换纸张,也许在不同的房子里,或者用随机文本,或者你甚至可以烧掉整个信封,而不会影响 C 街的房间。
string1
,就其本身而言,是一个数组的数组。它标识存储其元素的连续内存块。这些元素中的每一个本身都是一个 4 char
的数组,顺便说一下,这恰好是 string1Ptr
可以指向的对象类型。
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for
assuming string
and string1Ptr
are almost similar besides for the
difference I stated above)
... 这就是 C 隐藏区别的地方。了解 C 数组的基本内容之一是,在几乎所有表达式中,* 数组的值type 会默默地自动 converted 为指针 [指向数组的第一个元素]。这有时称为指针 "decay"。因此,索引运算符是指针上的运算符,而不是数组上的运算符,实际上它在您的三个示例中确实具有类似的行为。事实上,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 *
。不执行自动转换。
Any reason to use one over the other?
很多,双向的,这取决于你当时的特殊需要。一般来说,指针更灵活,尤其是在处理动态分配的内存时需要指针。但他们遭受的问题是
- 指针可能在范围内,但不指向任何东西,并且
- 声明一个指针不会为它创建任何指向。另外,
- 即使一个指针在程序执行期间一次指向某物,并且它的值随后没有被程序写入,它仍然可以停止指向任何东西。 (这通常是指针比它指向的对象寿命更长的结果。)
此外,
既可以是优势也可以是劣势
- 一个指针可以在其生命周期内任意多次分配以指向一个新对象。
一般来说,数组更容易用于许多用途:
- 声明数组会为其所有元素分配 space。您可以选择在声明时为它们指定初始值,或者在某些(但不是全部)情况下使用默认初始化。
- 数组的标识符是有效的,并且在范围内的任何地方都引用数组。
- 可选地,如果提供了初始值设定项,则数组声明可以使用它来自动确定数组维度。
* 但只有 几乎 全部。有一些例外,最重要的是 sizeof
运算符的操作数。
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
//I want to know differences between string1Ptr(pointer to array mentioned in question) and string(array of pointers mentioned in question). I only typed string1 here to give string1Ptr an address to strings
除了 string
可以指向任何大小的字符串而 string1Ptr
只能指向大小为 4 的字符串(否则指针运算会出错)之外,我看不到它们之间的任何差异。
例如,
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
的原因除了我上面提到的差异之外几乎相似)
那么string和string1Ptr有什么区别呢?有什么理由使用一个而不是另一个吗?
PS: 我是新手所以请放轻松。 另外,我确实检查了C pointer to array/array of pointers disambiguation,它似乎没有回答我的问题。
string1
与string
的区别与
char s1[4] = "foo";
char *s2 = "foo";
s1
是4个字符的可写数组,s2
是指向字符串字面量的指针,不可写。参见 Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?。
因此在您的示例中,可以执行 string1[0][0] = 'f';
将 string1[0]
更改为 "foo"
,但 string[0][0] = 'f';
会导致未定义的行为。
此外,由于 string
是一个指针数组,您可以重新分配这些指针,例如string[0] = "abc";
。您不能分配给 string1[0]
因为元素是数组,而不是指针,就像您不能重新分配 s1
.
string1Ptr
起作用的原因是因为 string1
是一个 char 的二维数组,保证是连续的。 string1Ptr
是一个指向 4 个字符数组的指针,当您对其进行索引时,您会增加该字符数,这将使您到达 string1
数组的下一行。
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
Besides the fact that
string
can point to strings of any size andstring1Ptr
can only point to strings of size 4 only(otherwise pointer arithmetic would go wrong), I don't any differences between them.
它们完全不同,根本不同,但 C 会费些力气向您隐藏区别。
string
是一个 数组 。它标识存储其元素的连续内存块。在此示例中,这些元素恰好属于 char *
类型,但这是一个相对次要的细节。人们可以在这里类比一个包含多个房间的房子——这些房间在物理上是房子的物理边界的一部分,并且存在于房子的物理边界内。我可以随心所欲地装饰房间,但它们永远是那个房子的房间。
string1Ptr
是一个 指针 。它标识一块内存,其内容描述如何访问另一个不同的内存块,其中驻留一个 4 char
的数组。在我们的房地产比喻中,这就像一张纸,上面写着“42 C 街,主卧室”。使用这些信息,您可以找到房间并根据需要重新装修它,就像在其他情况下一样。但是你也可以用不同房间的定位器替换纸张,也许在不同的房子里,或者用随机文本,或者你甚至可以烧掉整个信封,而不会影响 C 街的房间。
string1
,就其本身而言,是一个数组的数组。它标识存储其元素的连续内存块。这些元素中的每一个本身都是一个 4 char
的数组,顺便说一下,这恰好是 string1Ptr
可以指向的对象类型。
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav" printf("%s\n", string1Ptr[2]); printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for assuming
string
andstring1Ptr
are almost similar besides for the difference I stated above)
... 这就是 C 隐藏区别的地方。了解 C 数组的基本内容之一是,在几乎所有表达式中,* 数组的值type 会默默地自动 converted 为指针 [指向数组的第一个元素]。这有时称为指针 "decay"。因此,索引运算符是指针上的运算符,而不是数组上的运算符,实际上它在您的三个示例中确实具有类似的行为。事实上,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 *
。不执行自动转换。
Any reason to use one over the other?
很多,双向的,这取决于你当时的特殊需要。一般来说,指针更灵活,尤其是在处理动态分配的内存时需要指针。但他们遭受的问题是
- 指针可能在范围内,但不指向任何东西,并且
- 声明一个指针不会为它创建任何指向。另外,
- 即使一个指针在程序执行期间一次指向某物,并且它的值随后没有被程序写入,它仍然可以停止指向任何东西。 (这通常是指针比它指向的对象寿命更长的结果。)
此外,
既可以是优势也可以是劣势- 一个指针可以在其生命周期内任意多次分配以指向一个新对象。
一般来说,数组更容易用于许多用途:
- 声明数组会为其所有元素分配 space。您可以选择在声明时为它们指定初始值,或者在某些(但不是全部)情况下使用默认初始化。
- 数组的标识符是有效的,并且在范围内的任何地方都引用数组。
- 可选地,如果提供了初始值设定项,则数组声明可以使用它来自动确定数组维度。
* 但只有 几乎 全部。有一些例外,最重要的是 sizeof
运算符的操作数。