对于分配在空闲存储区的数组
int* arr = new int[size];
有两种方法可以知道终点在哪里。最直接的就是记住它有多大:
for (int i = 0; i < size; ++i)
// do something with arr[i]
另一种方法是将数组的最后一个元素设置为 sentinel 值——该值不会显示在您正在使用的数据中,因此当您看到你知道你在数组的末尾:
for (int i = 0; i < size; ++i)
arr[i] = i;
arr[size - 1] = -1;
现在您可以遍历数组查看值:
for (int i = 0; arr[i] != -1; ++i)
// do something with arr[i]
这就是文字字符串的工作原理(尽管它们不是在免费存储中分配的):
const char *str = "Hello, world!";
for (int i = 0; str[i] != '\0'; ++i)
std::cout << str[i];
std::cout << '\n';
这里的权衡是,第一种方法你必须传递一个额外的参数来告诉其他代码数组有多大:
void do_something(int* arr, int size) {
for (int i = 0; i < size; ++i)
// whatever
}
另一方面,有一个哨兵意味着你浪费了最后一个元素:
void do_something(int* arr) {
for (int i = 0; arr[i] != -1; ++i)
// whatever
}
最后一个元素没有您正在使用的任何数据;它只是为了标记结束。
当然,对于哨兵,存在您没有选择好的哨兵值的风险。如果您在数据中间的某处发现该值,则代码将停止循环,并且不会处理其余数据。