c ++指针段错误没有编译器警告,在先前分配时有效
c++ pointer segfaults without compiler warning, works when previously assigned
我很难理解指针,how/when它们失败了。所以我做了一个小程序,它创建一个指针,给它赋值,然后打印那个值。使用 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;
}
指针是存储地址的变量。
int *b = (int*) 12;
这将 b
声明为指向类型 int
的值的指针,并使用地址 12
对其进行初始化。你知道地址 12
上有什么吗?不,你不知道。因此,您不应使用该地址。
*b = 11;
这在指针b
指向的地址存储了一个整数11
。然而,由于指针 b
指向地址 12
,整数 11
覆盖了那个地址的东西(我们甚至不知道它覆盖了什么,因为我们不知道什么是从那里开始)。这可能会损坏堆或堆栈或程序代码,或者只是导致访问冲突,任何事情都可能发生。
但是如果你先这样做:
b = &a;
然后指针b
现在指向存储变量a
的地址。因此,随后在该地址写入 11
只会覆盖 a
的值(从 13 到 11),这是一个完全有效的操作,没有问题。
I just need it to point to some location that can hold an int
的确如此,但这还不够。不仅该位置能够保存 int
,该位置还必须可供您的程序存储这样的 int
。这意味着该位置需要是现有对象的位置(例如,类型 int
的现有变量)或能够容纳 int
的新分配的内存块。例如:
b = new int;
这将动态分配存储一个int
所需的内存,并将新分配的内存地址分配给指针b
。
请记住,在完成此类动态分配的内存后,您应该释放它:
delete b;
否则会出现内存泄漏(至少直到整个进程退出为止)。
如今,在现代 C++ 中,很少需要使用原始指针来手动管理动态内存 allocations/deallocations。为此,您可以使用标准容器 and/or 智能指针。
指针是保存内存地址的变量。
你“可以”在你的指针中有任何内存地址,但是试图从允许你的应用程序读取的内存 space 之外读取,将触发 OS 以段错误杀死你的应用程序。
如果你允许我打个比方:
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.
返回代码:
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
不是any-more指向那个被禁止的123
地址,而是指向a
的地址。 a
在你自己的代码里,它的内存对你来说不是禁止的,所以在这之后访问 *b
是允许的。
C++ 不禁止读取任何 hard-coded 地址(实际上它在某些情况下很有用),但您的 OS 可能不允许您弄乱该内存。
另一方面,编译器能够检测到没有初始化就使用的变量,并且可以警告这种情况。这与原始指针无关。
我很难理解指针,how/when它们失败了。所以我做了一个小程序,它创建一个指针,给它赋值,然后打印那个值。使用 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;
}
指针是存储地址的变量。
int *b = (int*) 12;
这将 b
声明为指向类型 int
的值的指针,并使用地址 12
对其进行初始化。你知道地址 12
上有什么吗?不,你不知道。因此,您不应使用该地址。
*b = 11;
这在指针b
指向的地址存储了一个整数11
。然而,由于指针 b
指向地址 12
,整数 11
覆盖了那个地址的东西(我们甚至不知道它覆盖了什么,因为我们不知道什么是从那里开始)。这可能会损坏堆或堆栈或程序代码,或者只是导致访问冲突,任何事情都可能发生。
但是如果你先这样做:
b = &a;
然后指针b
现在指向存储变量a
的地址。因此,随后在该地址写入 11
只会覆盖 a
的值(从 13 到 11),这是一个完全有效的操作,没有问题。
I just need it to point to some location that can hold an
int
的确如此,但这还不够。不仅该位置能够保存 int
,该位置还必须可供您的程序存储这样的 int
。这意味着该位置需要是现有对象的位置(例如,类型 int
的现有变量)或能够容纳 int
的新分配的内存块。例如:
b = new int;
这将动态分配存储一个int
所需的内存,并将新分配的内存地址分配给指针b
。
请记住,在完成此类动态分配的内存后,您应该释放它:
delete b;
否则会出现内存泄漏(至少直到整个进程退出为止)。
如今,在现代 C++ 中,很少需要使用原始指针来手动管理动态内存 allocations/deallocations。为此,您可以使用标准容器 and/or 智能指针。
指针是保存内存地址的变量。
你“可以”在你的指针中有任何内存地址,但是试图从允许你的应用程序读取的内存 space 之外读取,将触发 OS 以段错误杀死你的应用程序。
如果你允许我打个比方:
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.
返回代码:
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
不是any-more指向那个被禁止的123
地址,而是指向a
的地址。 a
在你自己的代码里,它的内存对你来说不是禁止的,所以在这之后访问 *b
是允许的。
C++ 不禁止读取任何 hard-coded 地址(实际上它在某些情况下很有用),但您的 OS 可能不允许您弄乱该内存。
另一方面,编译器能够检测到没有初始化就使用的变量,并且可以警告这种情况。这与原始指针无关。