C和C++中未定义,未指定和实现定义的行为有什么区别?
c c++ undefined-behavior unspecified-behavior implementation-defined-behavior
为什么C在数组索引超出限制的情况下进行区分
#include <stdio.h>
int main()
{
int a[10];
a[3]=4;
a[11]=3;//does not give segmentation fault
a[25]=4;//does not give segmentation fault
a[20000]=3; //gives segmentation fault
return 0;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,它正在尝试访问分配给进程或线程的内存,如果是a[11]或者a[25]它正在超出堆栈边界a[20000].
为什么编译器或链接器没有出错,他们不知道数组大小?如果没有,那么如何sizeof(a)正常工作?
我注意到C++中的分段错误的常见原因列表没有问题,所以我想我会添加它.
自然它是社区维基,因为没有一个正确的答案.
我认为这对于学习C++的新程序员可能有用,如果你不同意,可以随意关闭它.
以下示例来自Wikipedia.
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // undefined behavior
Run Code Online (Sandbox Code Playgroud)
如果我从不取消引用p,那么为什么arr + 5单独的未定义行为?我希望指针表现为整数 - 除了取消引用时,指针的值被视为内存地址.
指针如何指向[-1]数组的索引每次都会产生合法的输出.指针赋值实际发生了什么?
#include<stdio.h>
int main()
{
int realarray[10];
int *array = &realarray[-1];
printf("%p\n", (void *)array);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
代码输出:
manav@workstation:~/knr$ gcc -Wall -pedantic ptr.c
manav@workstation:~/knr$ ./a.out
0xbf841140
Run Code Online (Sandbox Code Playgroud)
编辑:如果这种情况有效,那么我可以用它来定义一个索引从1开始而不是0的数组,即:array [1],array [2],...
我在C中有这个代码,它接受了一堆chars
#include<stdio.h>
# define NEWLINE '\n'
int main()
{
char c;
char str[6];
int i = 0;
while( ((c = getchar()) != NEWLINE))
{
str[i] = c;
++i;
printf("%d\n", i);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输入是:testtesttest
输出:1 2 3 4 5 6 7 8 117 118 119 120
我的问题是:
虽然我明显超出了阵列的容量,为什么我不会出现超出界限(分段错误)的异常?
为什么输出中的数字会突然跳到很大的数字?
我在C++中试过这个并且得到了相同的行为.请问有谁可以解释一下这是什么原因?
这个奇怪的事情发生了,我设法把它浓缩成这个小程序:
int main()
{
int a[20];
a[21] = 5;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个程序导致在puppies puppies puppies终端上不断滚动,直到我点击 control-C。这是怎么回事?!
编辑:这个问题有什么不清楚的地方?请告诉我,以便我改进它。
int data[8];
data[9] = 1;
Run Code Online (Sandbox Code Playgroud)
c ++标准对此有何评论?这是未定义的行为吗?
至少C编译器(gcc -std = c99 -pedantic -W -Wall)对此没有任何说明.
谢谢.
我有这段代码,它运行得很好,但我不知道为什么:
int main(){
int len = 10;
char arr[len];
arr[150] = 'x';
}
Run Code Online (Sandbox Code Playgroud)
说真的,尝试一下!它有效(至少在我的机器上)!但是,如果我尝试更改索引太大(例如索引 20,000)的元素,它就不起作用。所以编译器显然不够聪明,无法忽略这一行。
那么这怎么可能呢?
答案:我可以用它来写入堆栈上其他变量消耗的内存,如下所示:
#include <stdio.h>
main(){
char b[4] = "man";
char a[10];
a[10] = 'c';
puts(b);
}
Run Code Online (Sandbox Code Playgroud)
输出“可以”。这确实是一件很糟糕的事情。
[在此发现一个疑问:C++ - 检测超出范围的访问 ]
如果我有一个"超出范围矢量访问"的程序,像这样:
std::vector<int> A(2);
...
A[10] = 3;
Run Code Online (Sandbox Code Playgroud)
我有办法确定找到这个错误吗? 我的意思是在调试模式下编译并查看某些断言是否会停止执行.
到目前为止,我已经自己查了一下.但可能是我不必编写额外的代码?
PS我当然检查过断言.它没有打电话.
有了这个程序:
#include <vector>
int main() {
std::vector<int> A(2);
A[10] = 3;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
汇编
g++ 1.cpp -O0; ./a.out
Run Code Online (Sandbox Code Playgroud)
所以看起来std在代码中没有断言,我不禁想知道为什么他们不做这么简单的检查.