使用 c++ 类的意外输出
Unexpected output with c++ class
这是我的 c++ 代码:
class base
{
public:
int bval;
base(){ bval=0;}
void give() { std::cout<<bval<<":"; }
};
void SomeFunc(base *arr,int size)
{
for(int i=0; i<size; i++,arr++)
std::cout<<arr->bval;
std::cout<<"n";
for(int i=0; i<size; i++,arr++)
arr->give();
std::cout<<"n";
}
void test_case4()
{
base BaseArr[5];
SomeFunc(BaseArr,6);
}
我正在为上述代码获得以下输出:
000003379188
0:-1079809464:134515567:134515888:0:-1079809336:
为什么第二行与第一行不同,为什么我在SomeFunc
中得到第 6 个循环的输出,而该位置尚未分配,我的意思是没有代码供 give(( 函数执行。
我知道的另一件事是,对象的 sizeof 运算符仅给出其数据元素的大小,而不是对象包含的函数。因此,如果函数不在对象内存空间内,那么它们存储在哪里?
编辑:
我故意第 6 次增加 arr,只是为了检查执行不在第 6 位的函数时会发生什么give()
。
请参阅对齐姆卡里昂库回复的评论。也请回答我问题的第一部分。
您正在递增arr
指针并超过arr
指向的原始数组的大小。此外,正如 Cem 指出的那样,函数的值必须是 5 而不是 6。
你的数组,BaseArr 有 5 个元素,而不是 6 个。其上限为4。
base BaseArr[5];
SomeFunc(BaseArr,5); //should fix it.
编辑:
对于为什么你会得到输出:在 C 数组中没有固定的限制,你可以很容易地越界而不会得到任何错误。结果通常是灾难性的。你永远不会知道会发生什么。
编辑2:
今天我的思维工作得特别慢,现在我明白你为什么困惑了。好的,即使 arr 指向的对象无效。它仍然是一个内存位置。在调用 arr->give 时,您实际上是在调用类似于 give(arr( 的函数。由于 arr 只是指向内存位置调用的指针,因此是有效的,并且不会像在 C 中那样引发任何错误。但是,某些调试器能够注意到您越界。为此,始终建议使用载体。
或者,您可以使用类型安全的模板。
template<size_t size> void SomeFunc(Base (const &arr)[size]) {
//...
}
大小将由编译器自动推断。
为什么程序不崩溃?
C/C++ 语言不对数组进行任何边界检查。这取决于操作系统,以确保您访问有效的内存。
您正在声明一个基于堆栈的数组(大小为 5(。在数组边界之外访问只是访问已分配的堆栈空间的另一部分(大多数操作系统通常为堆栈保留一定部分内存(。幸运的是,您正在访问一个越界数组索引(6(,它属于这个预先分配的堆栈空间,因此它不会崩溃,而是返回该特定内存位置中存在的垃圾数据。
上面只是对发生的事情的逻辑解释,但事实是,
访问通过其边界的数组是未定义的行为,因此不可能定义和推理未定义的行为。时期!
如果函数不在对象内存空间内,那么它们存储在哪里?
C++ 标准未指定成员函数的存储位置。此行为作为编译器的实现详细信息被省略。因此,它可能因编译器而异。
正如您正确所说,与成员变量不同,每个对象都没有成员函数的副本。您可以像free functions
一样考虑成员函数,但在一个方面是特殊的,即隐式this
指针作为参数传递给它们。
所有编译的代码(包括成员函数(都作为被调用的text segment
或code segment
进入内存的一部分。这个内存区域独立于Heap(a.k.a Freestore in C++)
、Stack
和Data/BSS
段,这些段保存动态分配的对象、本地声明的对象和全局或静态对象。
希望能回答您的问题。
- 字符串比较中的意外输出
- 来自 decltype 的意外输出类型
- 字符数组到十六进制字符串的转换 - 意外输出
- 使用 boost::regex 从目录中获取带有一些正则表达式的文件名称时出现意外输出
- 使用后序遍历递归的深度优先搜索会产生意外输出
- C++的意外输出
- 贝金纳C++练习解决方案的意外输出
- 无效* 转换获得意外输出
- 以下程序的意外输出
- 意外输出:矢量矢量(功率集)
- 基本 int 数组提供意外输出
- 线程的意外输出
- 减法中的意外输出
- 带有左移操作员C 的意外输出
- C strncpy意外输出
- 意外输出..函数绑定在虚拟表中的发生方式
- 星号的意外输出
- 已编译的 protobuf 文件的意外输出路径
- 打印对象矢量的意外输出
- 递归函数用于计算 n 个数字之和的意外输出