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

发布于 2025-01-14 03:10:46 字数 534 浏览 2 评论 0原文

我很难理解指针以及它们如何/何时失败。所以我制作了一个小程序,它创建一个指针,为其分配一个值,然后打印该值。使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

江湖彼岸 2025-01-21 03:10:46

指针是保存内存地址的变量。
您“可以”在指针中包含任何内存地址,但是尝试从允许应用程序读取的内存空间之外读取数据,将触发操作系统以段错误错误杀死您的应用程序。

如果允许我打个比喻的话:

您可以在纸上写下您所在国家/地区任何人的地址。但如果你未经许可试图进入那所房子,你很可能会被警察拦住。

回到代码:

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.

当您取消注释这两行代码时:

int a = 13;
b = &a;

基本上,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:

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. 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.

地狱即天堂 2025-01-21 03:10:46

指针是存储地址的变量。

int *b = (int*)  12;

这将 b 声明为指向 int 类型值的指针,并使用地址 12 对其进行初始化。你知道12地址上有什么吗?不,你不知道。因此,您不应该使用该地址。

*b = 11;

这将整数 11 存储在指针 b 指向的地址处。然而,由于指针 b 指向地址 12,整数 11 会覆盖该地址处的某些内容(我们甚至不知道它覆盖了什么) ,因为我们不知道从哪里开始)。这可能会损坏堆或堆栈或程序代码,或者只是导致访问冲突,任何事情都可能发生。

但如果您首先这样做:

b = &a;

那么指针b现在就指向存储变量a的地址。因此,随后在该地址写入 11 只会覆盖 a 的值(从 13 到 11),这是一个完全有效的操作,没有问题。

我只需要它指向某个可以容纳int的位置

确实如此,但这还不够。该位置不仅能够保存 int,而且该位置还必须可供您的程序存储这样的 int。这意味着该位置必须是现有对象的位置(例如,int 类型的现有变量的位置)或能够保存 int 的新分配的内存块的位置。例如:

b = new int;

这将动态分配存储int所需的内存,并将新分配的内存的地址分配给指针b

请记住,在使用完此类动态分配的内存后,应该释放它:

delete b;

否则,将会出现内存泄漏(至少在整个进程退出之前)。

如今,在现代 C++ 中,很少需要使用原始指针来手动管理动态内存分配/释放。为此,您可以使用标准容器和/或智能指针。

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. Do you know what resides at address 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. 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). 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. Thus, subsequently writing 11 at that address will just overwrite a's value (from 13 to 11), a perfectly valid operation, no problems.

I just need it to point to some location that can hold an 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. This means the location needs to be either that of an existing object (e.g., of an existing variable of type int) or a newly allocated memory chunk capable of holding an int. 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.

Remember that after you're done with such dynamically allocated memory, you should deallocate it:

delete b;

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文