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,但似乎没有回答我的问题。
答案 0 :(得分:4)
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个char
数组的另一个不同的内存块。在我们的房地产类比中,这就像一张纸,上面写着“ 42 C Street,master bedroom”。与其他情况一样,使用该信息,您可以找到房间并重新装修。但是,您也可以用定位器替换纸张,以放置在不同的房间(可能在另一间房子里),或者使用随机文本,或者甚至可以烧毁整个信封,而不会影响C街上的房间。
string1
本身是一个数组数组。它标识存储其元素的连续内存块。这些元素中的每个元素本身都是4个char
的数组,偶然地,它们恰好是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
运算符的操作数。
答案 1 :(得分:0)
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的2D数组,可以保证是连续的。 string1Ptr
是一个指向4个字符的数组的指针,当您对其进行索引时,将以该字符数递增,这将使您到达string1
数组的下一行。