检查 nullptr 100% 是否可以防止有关内存布局的段错误?

does checking for nullptr 100% protect from segfault regarding memory layout?

假设我正在迭代一个数组,但超出了这个数组,因为我的循环很愚蠢。
如果内存中的某个对象直接位于与此数组相同类型的此数组之后,则可以
检查 array[invalid_index] == nullptr
保护我?

检查索引(大小未知)是否对 C 数组有效的正确方法是什么?

不,检查 nullptr 并不能保护您。完全没有。 0%.

问题数组是您创建的。检查索引是否有效的正确方法是了解您创建的数组的大小(您所做的;记住:创建该数组的是),然后检查指标在范围内。更好的是,编写代码时索引首先不会超出范围,因此不需要检查开始于...

除了数组最后一个元素之后的假设元素外,尝试单独 计算(甚至不访问,只计算)一个元素的地址不是数组的一部分会立即调用未定义的行为 [expr.add]/4. And, without exception, attempting to access an element that is not actually an element of an array always invokes undefined behavior no matter what. 100%. The built-in subscript operator is just shorthand for computing the address of the given element and accessing the object at that address [expr.sub]/1。因此,在进入未定义行为领域之前,您实际上甚至没有达到 可以 将您读取的值与 nullptr 进行比较的程度……

无法通过指向数组第一个元素的指针来确定数组的大小。您需要以某种方式传达尺寸。

常见的策略是将数组保持为数组并通过类型系统传达大小,将大小作为单独的值提供或使用标记值(如 c 字符串中的空字符)。在 C++ 中,建议使用 std::vectorstd::array,它们始终知道自己的大小。

尝试取消引用超出该数组边界的数组元素是未定义的行为。一旦您尝试阅读 array[invalid_index] ,您就会遇到未定义的行为。所以不可能将 array[invalid_index] 用于任何有用的目的,包括边界检查。 nullptr在这里完全没有作用。

这种支票不会保护你。

许多 C API 与使用它的程序员签订了某种合同,他们将遵守 API 指定的约定,而无需对该合同进行任何严格的机械执行。例如,基于 C 的字符串 API 主要断言字符串始终以空值终止,并且任何基于 C 的字符串 API 的正确使用将假定并依赖于以空值终止的字符串。

当这个合同就位时,通常认为执行这些类型的检查是安全的,因为传递给你字符串的人应该保证这个合同,通常通过使用额外的 null 值填充字符串或数据结构来专门明确地履行此合同,如下所示:

char string[13] = "Hello World!"; //string[12] contains the value 0

/*...*/
char const* str = string;

do {
    char curr = *str++;
    if(curr == 0) 
        break;
    /*...*/
} while(true);

在大多数基于 C 的字符串 API 中,该代码被认为是 "safe" 在保证合同的特定上下文中。

但这取决于程序员自己的表现,并且无法保证。程序员用他们的代码和类似这样的行为不当并不需要太多:

char string[12] = "Hello World"; 
string[11] = '!';

会立即破坏我刚才显示的字符串循环。这就是为什么 C++ 程序员觉得(在我看来是正确的)这些类型的检查是不安全的:除非您相信您的用户(程序员)遵守您的规则,否则无法保证它们是正确的。

这就是为什么我们更喜欢 API 不会像这样意外损坏的原因。

std::string string = "Hello World!";
for(char curr : string) { //for-each loop, intrinsically safe unless the iterators are improperly implemented
    /*Do whatever with curr*/
}

所以回到你原来的问题:处理这个问题的安全方法是使用专门设计来保护我们安全的物品。使用 std::array<T, N> 而不是 T arr[N],这将允许使用 for-each 循环。如果您需要使用基于索引的迭代,在性能不是很重要的任何情况下,首选 at(index) 而不是 [index]。这些做法将使您的代码安全,而不仅仅是相信您的数据配置正确。

does checking for nullptr 100% protect from segfault

没有。访问无效内存的方式有很多种,空指针只是其中一种。

你必须做的是避免所有未定义的行为。

What is the correct way to check whether an index (size is not known) is valid for a C array?

检查方法是与数组的大小进行比较:

if (index < size)
    // valid

如果您不知道数组的大小,则无法检查有效性。错误的其他典型来源是错误地假设数组的大小或生命周期。