c++没有编译器警告的指针段错误,在先前分配时有效
我很难理解指针以及它们如何/何时失败。所以我制作了一个小程序,它创建一个指针,为其分配一个值,然后打印该值。使用 gcc 和 clang 都可以正常编译,并且在使用 -Wall 开关时不会发出任何警告。为什么它会出现段错误,为什么当我首先为指针分配不同的值时不会出现段错误?我以为我已经初始化了指向某个地方的指针。当我只是声明指针而不进行初始化时,我理所当然地收到编译器警告。但是,在这里我没有收到编译器警告,但它仍然存在段错误。
#include<iostream>
int main(){
int *b = (int*) 12; //pointer gets initialized, so it points to somewhere
//int a = 13; //works fine when uncommenting this and the next line
//b = &a;
*b = 11;
std::cout << "*b = " << *b << "\n";
return 0;
}
I have a difficulties understanding pointers and how/when they fail. So I made a tiny program which creates a pointer, assigns a value to it and then prints that value. Compiles fine with both gcc and clang and does not give any warnings when using the -Wall switch. Why does it segfault and why does it not segfault when I assign a different value to the pointer first? I thought I had initialized the pointer to somewhere. When I just declare the pointer without initialization, then I rightfully get a compiler warning. However, here I do not get a compiler warning, but it still segfaults.
#include<iostream>
int main(){
int *b = (int*) 12; //pointer gets initialized, so it points to somewhere
//int a = 13; //works fine when uncommenting this and the next line
//b = &a;
*b = 11;
std::cout << "*b = " << *b << "\n";
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
指针是保存内存地址的变量。
您“可以”在指针中包含任何内存地址,但是尝试从允许应用程序读取的内存空间之外读取数据,将触发操作系统以段错误错误杀死您的应用程序。
如果允许我打个比喻的话:
回到代码:
当您取消注释这两行代码时:
基本上,
b
不再指向那个禁止的123
地址,而是指向的地址一个。
a
在您自己的代码中,并且它的内存不被禁止,因此在此之后访问*b
是允许的。C++ 并不禁止读取任何硬编码地址(事实上,它在某些情况下很有用),但您的操作系统可能不允许您弄乱该内存。
另一方面,编译器能够检测到未经初始化而使用的变量,并可以警告这种情况。这与原始指针无关。
A pointer is a variable that save a memory address.
You "can" have any memory address in your pointer, but trying to read from memory space outside of where your application are allowed to read, will trigger the OS to kill you application with a segfault error.
If you allow me the metaphor:
Back to code:
When you uncomment the two lines of code:
Basically,
b
is not any-more pointing to that forbidden123
address, but to the address ofa
.a
is in your own code, and it memory is not forbidden to you, so accessing*b
after this is allowed.Reading at any hard-coded address is not forbidden by C++ (in fact it is useful in some situations), but your OS may not allow you to mess with that memory.
On the other hand, the compiler is able to detect a variable being used without initialization, and can warn this case. This has nothing to do with raw pointers.
指针是存储地址的变量。
这将
b
声明为指向int
类型值的指针,并使用地址12
对其进行初始化。你知道12
地址上有什么吗?不,你不知道。因此,您不应该使用该地址。这将整数
11
存储在指针b
指向的地址处。然而,由于指针b
指向地址12
,整数11
会覆盖该地址处的某些内容(我们甚至不知道它覆盖了什么) ,因为我们不知道从哪里开始)。这可能会损坏堆或堆栈或程序代码,或者只是导致访问冲突,任何事情都可能发生。但如果您首先这样做:
那么指针
b
现在就指向存储变量a
的地址。因此,随后在该地址写入11
只会覆盖a
的值(从 13 到 11),这是一个完全有效的操作,没有问题。确实如此,但这还不够。该位置不仅能够保存
int
,而且该位置还必须可供您的程序存储这样的int
。这意味着该位置必须是现有对象的位置(例如,int 类型的现有变量的位置)或能够保存 int 的新分配的内存块的位置。例如:这将动态分配存储
int
所需的内存,并将新分配的内存的地址分配给指针b
。请记住,在使用完此类动态分配的内存后,应该释放它:
否则,将会出现内存泄漏(至少在整个进程退出之前)。
如今,在现代 C++ 中,很少需要使用原始指针来手动管理动态内存分配/释放。为此,您可以使用标准容器和/或智能指针。
A pointer is a variable to store an address.
This declares
b
as a pointer to a value of typeint
, and initializes it with the address12
. Do you know what resides at address12
? No, you don't. Thus, you should not use that address.This stores an integer
11
at the address pointed to by the pointerb
. However, since pointerb
points at address12
, the integer11
overwrites something at that address (we don't even know what does it overwrite, because we don't know what is there to begin with). This could corrupt heap or stack or program's code or just cause an access violation, anything can happen.But if you first do this:
Then pointer
b
now points at the address at which the variablea
is stored. Thus, subsequently writing11
at that address will just overwritea
's value (from 13 to 11), a perfectly valid operation, no problems.Indeed, but this is not enough. Not only shall the location be able to hold an
int
, that location must also be available for your program to store such anint
. This means the location needs to be either that of an existing object (e.g., of an existing variable of typeint
) or a newly allocated memory chunk capable of holding anint
. For example:This will dynamically allocate the memory needed to store an
int
, and assign the address of the newly allocated memory to the pointerb
.Remember that after you're done with such dynamically allocated memory, you should deallocate it:
Otherwise, there will be a memory leak (at least until the whole process exits anyway).
Nowadays, in modern C++, there is rarely a need to use raw pointers to manage dynamic memory allocations/deallocations manually. You'd use standard containers and/or smart pointers for that purpose instead.