我正在为类做一些事情,我想根据某些条件使用不同的格式字符串。我这样定义:
const char *fmts[] = {"this one is a little long", "this one is short"};
以后,我可以使用
printf(fmts[0]);
或
printf(fmts[1]);
它有效。
编译器是否为我们做了些什么?我的猜测是它需要最长的字符串并存储所有这些字符串。但我想知道一个知道的人。感谢
答案 0 :(得分:16)
它的工作方式与任何其他数据类型相同。 “字符串”数组实际上是一个字符指针数组, all 具有相同的大小。因此,为了获得指针的正确地址,它将索引乘以单个元素的大小,然后将其添加到基址。
您的数组将如下所示:
<same-size>
+---------+
fmts: | fmts[0] | ------+
+---------+ |
| fmts[1] | ------|--------------------------+
+---------+ | |
V V
this one is a little long\0this one is short\0
字符串本身的字符不存储在数组中,它们存在于其他地方。你拥有它的方式,它们通常存储在只读存储器中,尽管你也可以malloc
它们,甚至可以将它们定义为可修改的字符数组,例如:
char f0[] = "you can modify me without invoking undefined behaviour";
您可以使用以下代码查看此操作:
#include<stdio.h>
const char *fmts[] = {
"This one is a little long",
"Shorter",
"Urk!"
};
int main (void) {
printf ("Address of fmts[0] is %p\n", (void*)(&(fmts[0])));
printf ("Address of fmts[1] is %p\n", (void*)(&(fmts[1])));
printf ("Address of fmts[2] is %p\n", (void*)(&(fmts[2])));
printf ("\n");
printf ("Content of fmts[0] (%p) is %c%c%c...\n",
(void*)(fmts[0]), *(fmts[0]+0), *(fmts[0]+1), *(fmts[0]+2));
printf ("Content of fmts[1] (%p) is %c%c%c...\n",
(void*)(fmts[1]), *(fmts[1]+0), *(fmts[1]+1), *(fmts[1]+2));
printf ("Content of fmts[2] (%p) is %c%c%c...\n",
(void*)(fmts[2]), *(fmts[2]+0), *(fmts[2]+1), *(fmts[2]+2));
return 0;
}
输出:
Address of fmts[0] is 0x40200c
Address of fmts[1] is 0x402010
Address of fmts[2] is 0x402014
Content of fmts[0] (0x4020a0) is Thi...
Content of fmts[1] (0x4020ba) is Sho...
Content of fmts[2] (0x4020c2) is Urk...
在这里,您可以看到数组元素的实际地址是等距的 - 0x40200c + 4 = 0x402010
,0x402010 + 4 = 0x402014
。
但是,值不是,因为它们指的是不同大小的字符串。字符串位于单个内存块中(在这种情况下 - 无论如何都没有必要),如下所示,*
个字符表示单个字符串的开头和结尾:
| +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
---------+-------------------------------------------------------------------
0x04020a0| *54 68 69 73 20 6f 6e 65 20 69 73 20 61 20 6c 69 This one is a li
0x04020b0| 74 74 6c 65 20 6c 6f 6e 67 00*53 68 6f 72 74 65 ttle long.Shorte
0x04020c0| 72 00*55 72 6b 21 00* r.Urk!.
答案 1 :(得分:3)
fmts 指向char的指针。它没有指向字符串本身。
换句话说:fmts[0]
和fmts[1]
的地址差异是char *
类型的大小。
答案 2 :(得分:3)
您没有字符串数组。你有一个指向字符串的指针数组,或者更确切地说,是一个指向字符串第一个字符的指针数组。所有指针都具有相同的大小,因此不会出现确定偏移的问题。
如果你真的想拥有一个字符串数组,你必须声明类似的东西
const char fmts[][64] = { "this one is a little long", "this one is short" };
即。你必须声明一个数组数组。在这种情况下,您有责任为实际的字符串数组指定足够的固定大小(在我的示例中为64
),该值将确定从一个字符串到数组中下一个字符串的固定偏移量。
正如您在问题中正确指出的那样,您在此示例中可以指定的最小大小由数组中最长的字符串确定。但是,编译器不会为您计算它。你必须自己明确指定它。
答案 3 :(得分:2)
答案是你没有字符串数组本身,你有一个指向char
的指针数组。指针的大小都相同,printf()
只是取消引用它们。
答案 4 :(得分:2)
是的,编译器会使第一个指针指向第一个字符串的第一个字符,第二个指针指向第二个字符串的第一个字符。
因为它是“一个指向字符的指针数组”,所以每个指针都可以指向任何地方,不需要等长或任何东西。
答案 5 :(得分:2)
您没有声明字符串数组。您声明了一个指向字符串的指针数组。字符串数组看起来像:
char fmts[][40] = {"this one is a little long", "this one is short"};
正如您所看到的,您必须将最大长度指定为第二个数组维度(只能在C中隐式确定多维数组的第一个维度)。