我最近在C:
中编写了这段代码#include <stdio.h>
#define N_ROWS 100
int main() {
char *inputFileName = "triangle_data.txt";
FILE *inputFile = fopen(inputFileName, "r");
if (inputFile == NULL) {
printf("ERROR: Failed to open \"%s\".\n", inputFileName);
return -1;
}
int triangle[(N_ROWS*(N_ROWS+1))/2 - 1];
size_t size = sizeof(triangle)/sizeof(int);
size_t index;
for (index = 0; !feof(inputFile); ++index) {
fscanf(inputFile, "%d", &triangle[index]);
}
return 1;
}
并期待Segmentation Fault
,因为N_ROWS*(N_ROWS+1))/2
足以容纳文件中的数据,但正如您所看到的,我使数组的元素变小了一个。不知何故,这不会触发分段错误。如果我将for
- 循环的主体替换为:
int tmp;
fscanf(inputFile, "%d", &tmp);
triangle[index] = tmp;
这里发生了什么。如果我将数组三个元素变小,它仍然不会触发分段错误。五个元素小触发一个。我确定文件中有足够的数据。
作为测试,我之后打印了数组,如果选择较小的数组,则会丢失元素。
这里发生了什么?
PS:在OS X上使用clang
编译。
答案 0 :(得分:2)
这里发生了什么?
当您在数组对象外部编写时,您的程序会调用未定义的行为。 C中的未定义行为未定义,您的程序可以在今天工作并在其他所有日期崩溃,甚至可以打印莎士比亚的全部作品。
答案 1 :(得分:2)
分段错误并不意味着您访问数组越界,这意味着您已经访问了未映射的虚拟内存地址。通常访问数组越界将导致这种情况,但仅仅因为您没有看到段错误,它并不意味着您的所有内存访问都是有效的。
至于为什么你会看到不同的行为,很难说,当结果被指定为未定义时,尝试证明不同的结果并不一定是值得花时间使用。如果您对正在发生的事情感到非常好奇,可以查看代码的两个版本生成的程序集(使用--save-temps
参数进行叮当)。
答案 2 :(得分:1)
程序的行为(访问数组元素超出界限)是未定义的。
没有特别要求未定义的行为导致分段错误或任何其他可观察的错误条件。
未定义的行为意味着 - 从字面上看 - C标准不会对允许发生的内容施加任何限制。这意味着任何事情都可能发生,包括看似正常工作,或在一种情况下工作而不是另一种情况。
技巧是不要担心分段错误的特定潜在原因(或任何未定义行为的实例可能触发的任何其他错误条件)。这是为了确保程序具有明确的行为,因此保证不会发生这种症状。