简体   繁体   English

c++ 没有编译器警告的指针段错误,在先前分配时有效

[英]c++ pointer segfaults without compiler warning, works when previously assigned

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.使用 gcc 和 clang 都可以很好地编译,并且在使用 -Wall 开关时不会发出任何警告。 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;
}

A pointer is a variable that save a memory address.指针是一个变量,保存了一个memory地址。
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.你“可以”在你的指针中有任何 memory 地址,但是试图从允许你的应用程序读取的 memory 空间之外读取,将触发操作系统以段错误杀死你的应用程序。

If you allow me the metaphor:如果你允许我打个比喻:

You can write on a paper the address of any person in your country.您可以在纸上写下您所在国家/地区任何人的地址。 But if you try to enter that house without permission, you most probably will get stopped by the police.但是如果你试图未经许可进入那所房子,你很可能会被警察拦住。

Back to code:回到代码:

int *b = (int*) 123; // ok, you can save what you want.
std::cout << *b << std::endl; // SEGFAULT: you are not allowed to read at 123.

When you uncomment the two lines of code:当您取消注释这两行代码时:

int a = 13;
b = &a;

Basically, b is not any-more pointing to that forbidden 123 address, but to the address of a .基本上, b不再指向那个被禁止的123地址,而是指向a的地址。 a is in your own code, and it memory is not forbidden to you, so accessing *b after this is allowed. a在你自己的代码中,它 memory 不是你禁止的,所以在这之后访问*b是允许的。

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. C++ 不禁止读取任何硬编码地址(实际上它在某些情况下很有用),但您的操作系统可能不允许您弄乱 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.这与原始指针无关。

A pointer is a variable to store an address.指针是存储地址的变量。

int *b = (int*)  12;

This declares b as a pointer to a value of type int , and initializes it with the address 12 .这将b声明为指向int类型值的指针,并使用地址12对其进行初始化。 Do you know what resides at address 12 ?你知道地址12有什么吗? No, you don't.不,你不知道。 Thus, you should not use that address.因此,您不应使用该地址。

*b = 11;

This stores an integer 11 at the address pointed to by the pointer b .这会将 integer 11存储在指针b指向的地址。 However, since pointer b points at address 12 , the integer 11 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).但是,由于指针b指向地址12 , integer 11会覆盖该地址处的内容(我们甚至不知道它覆盖了什么,因为我们不知道从什么开始)。 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:但是如果你先这样做:

b = &a;

Then pointer b now points at the address at which the variable a is stored.然后指针b现在指向存储变量a的地址。 Thus, subsequently writing 11 at that address will just overwrite a 's value (from 13 to 11), a perfectly valid operation, no problems.因此,随后在该地址写入11只会覆盖a的值(从 13 到 11),这是一个完全有效的操作,没有问题。

I just need it to point to some location that can hold an int我只需要它指向某个可以容纳int的位置

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 an int .该位置不仅可以保存一个int ,而且该位置还必须可供您的程序存储这样一个int This means the location needs to be either that of an existing object (eg, of an existing variable of type int ) or a newly allocated memory chunk capable of holding an int .这意味着该位置需要是现有 object 的位置(例如,类型为int的现有变量)或新分配的能够容纳int的 memory 块。 For example:例如:

b = new int;

This will dynamically allocate the memory needed to store an int , and assign the address of the newly allocated memory to the pointer b .这样会动态分配存储一个int所需要的memory,并将新分配的memory的地址赋值给指针b

Remember that after you're done with such dynamically allocated memory, you should deallocate it:请记住,在完成动态分配的 memory 之后,您应该释放它:

delete b;

Otherwise, there will be a memory leak (at least until the whole process exits anyway).否则,将出现 memory 泄漏(至少直到整个过程退出为止)。

Nowadays, in modern C++, there is rarely a need to use raw pointers to manage dynamic memory allocations/deallocations manually.如今,在现代 C++ 中,很少需要使用原始指针手动管理动态 memory 分配/释放。 You'd use standard containers and/or smart pointers for that purpose instead.为此,您可以使用标准容器和/或智能指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM