C如何为数组字符串获取数组偏移量?

时间:2010-11-05 04:45:03

标签: c arrays string

我正在为类做一些事情,我想根据某些条件使用不同的格式字符串。我这样定义:

const char *fmts[] = {"this one is a little long", "this one is short"};

以后,我可以使用

printf(fmts[0]);

printf(fmts[1]);

它有效。

编译器是否为我们做了些什么?我的猜测是它需要最长的字符串并存储所有这些字符串。但我想知道一个知道的人。感谢

6 个答案:

答案 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 = 0x4020100x402010 + 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中隐式确定多维数组的第一个维度)。