【问题标题】:Denoting the end of a multidimensional array or multi-pointer [duplicate]表示多维数组或多指针的结尾
【发布时间】:2019-09-11 22:56:03
【问题描述】:

对于单个(字符串)数组,结尾用\0 表示。例如,如果我创建字符串:

char * string = "hello";

它将被表示为{'h','e','l','l','o','\0'}

对如下所示的数组做了什么来表示“它的结束”?

char * strings[] = {"one", "two"};

循环遍历时,如何检测数组的“结束”?

【问题讨论】:

标签: c


【解决方案1】:

你可以做这样的事情,这非常类似于字符串的空终止:

char * strings[] = {
    "one",
    "two",
    NULL
};

您可以使用这样的循环打印这些字符串:

char **pp;
for(pp = strings; pp != NULL; pp++)
    printf("%s\n", *pp);

但当我说“你能做到”时,我是认真的。没有规定说您必须这样做。 (这与字符串本身形成对比,如果您构建自己的字符串并且希望自己的字符串与strcpyprintf 等兼容,则确实必须使用空字符终止。)

我展示的NULL 终结点适用于指针数组。为其他类型选择合适的标记值可能更难,例如int 的数组。 (如果你知道你的数字都是正数,你可以使用 0 或 -1 作为哨兵,但如果你的数组有正数和负数,你可能会卡住。)

另一种可能性是保持单独的计数:

char * strings[] = {
    "one",
    "two"
};

int nstrings = 2;


int i;
for(i = 0; i < nstrings; i++)
    printf("%s\n", strings[i]);

与其手动计算字符串并将nstrings 显式初始化为2,不如让编译器为您完成这项工作:

int nstrings = sizeof(strings) / sizeof(strings[0];

sizeof(strings) 以字节为单位为您提供整个数组的大小,而sizeof(strings[0]) 以字节为单位为您提供一个元素的大小(即一个指针),因此除法为您提供了条目数,这就是你想要的。

使用sizeof 并像这样划分是一个非常常见且完全合法的习语,但它有点晦涩难懂,所以我更喜欢用一个宏来封装它(并使其更具自我记录性),如下所示:

#define SIZEOFARRAY(a) (sizeof(a) / sizeof(a[0])

int nstrings = SIZEOFARRAY(strings);

【讨论】:

  • 虽然“while sizeof(strings[0]) 给你一个指针的大小以字节为单位”在这种情况下是正确的,“while sizeof(strings[0]) 给你一个数组的大小以字节为单位的元素”也是正确且更通用的。
  • @chux 这是一个权衡。我喜欢一次采取一个小的、明确的步骤,因为过早地进入太多抽象级别(比如说“一个元素”)可能会让人困惑。我故意说“一个指针”,因为在这里我们知道我们正在谈论一个指针数组。但是话又说回来,对数组和指针很容易混淆,所以那里还有另一种可能的误读。采用了妥协的措辞。
【解决方案2】:

数组有编译时常量大小,元素个数可以通过表达式sizeof(strings) / sizeof(*strings)来确定。那么给定:

const size_t STRING_COUNT = sizeof(strings) / sizeof(*strings) ;

那么数组的最后一个元素是:

strings[STRING_COUNT - 1] ;

数组可以迭代:

for( size_t i = 0; i < STRING_COUNT; i++ ) ...

如果strings作为参数传递,它将作为指针传递,因此数组大小信息将丢失。在这种情况下,您通常会将尺寸信息作为单独的参数传递:

some_function( strings, STRING_COUNT ) ;

或者,您可以显式地将标记值添加到数组中:

char* strings[] = 
{
    "one",
    "two",
    NULL
} ;

然后可以像 NUL 字符用于字符串一样检测到它。请注意,对于字符串,字符串长度和存储字符串的数组的长度无关,数组只需至少与字符串加上 NUL 终止符一样长。使用哨兵值也是如此。例如给出:

char* strings[20] = 
{
    "one",
    "two"
    NULL
} ;

sizeof(strings)/sizeof(*strings) 将是 20,但该数组仅包含指向初始化后初始化器之前的两个有效字符串常量的指针。

所以你使用数组大小​​还是哨兵取决于你需要的具体数据结构。数组大小适用于常量数组或有效元素数量恒定的数组。哨兵可能用于可变数组,但并非总是必要的 - 您可以简单地维护有效元素的单独计数,或者可能有一个稀疏数组,其中有效元素不一定是连续的。

【讨论】:

    猜你喜欢
    • 2011-01-12
    • 1970-01-01
    • 2013-04-29
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    相关资源
    最近更新 更多