什么是细分错误?在C和C ++中有区别吗?分段错误和悬空指针如何关联?
NullPointerException
。
什么是细分错误?在C和C ++中有区别吗?分段错误和悬空指针如何关联?
NullPointerException
。
Answers:
分段错误是由访问“不属于您”的内存引起的特定类型的错误。它是一种帮助机制,可防止您破坏内存并引入难以调试的内存错误。每当遇到段错误时,您就知道您在内存上做错了–访问已经释放的变量,写到内存的只读部分,等等。在大多数语言中,分段错误在本质上都是相同的,这会让您陷入困境在内存管理方面,C和C ++中的段错误之间在原理上没有区别。
至少在诸如C(++)之类的较低级语言中,有很多方法可以获取段错误。获取段错误的常见方法是取消引用空指针:
int *p = NULL;
*p = 1;
当您尝试写入标记为只读的一部分内存时,会发生另一个段错误:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
悬空的指针指向不再存在的事物,例如:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
指针p
悬空是因为它指向c
在块结束后不再存在的字符变量。当您尝试取消引用悬空指针(如*p='A'
)时,可能会遇到段错误。
c
是本地的,这意味着它在之后被压入堆栈{
并在之后弹出}
。悬空指针只是对偏移量的引用,该偏移量现在已从堆栈中移出。这就是为什么在简单的程序中对其进行修改将永远不会触发任何段错误的原因。另一方面,在更复杂的用例中,它可能导致段错误,其中其他函数调用可能会导致堆栈增长并包含悬空指针指向的数据。写入该数据(本地变量)将导致未定义的行为(segfault&Co)
SIGSEGV
会将未使用的堆栈页面返回给系统,使该空间成为的主题,因此我不会期望这样的信号来处理堆栈。
值得注意的是,分段错误不是由直接访问另一个进程内存引起的(这是我有时听到的),因为这根本不可能。使用虚拟内存,每个进程都有自己的虚拟地址空间,无法使用任何指针值访问另一个进程。例外是共享库,它们是相同的物理地址空间,映射到(可能)不同的虚拟地址,内核内存甚至在每个进程中都以相同的方式映射(我认为,这是为了避免在系统调用中刷新TLB)。还有类似shmat;)的东西-这些就是我所谓的“间接”访问。但是,您可以检查它们是否通常位于距流程代码较远的位置,并且我们通常可以访问它们(这就是它们在那里的原因,
但是,如果以不正确的方式访问我们自己的(进程)内存(例如,尝试写入不可写的空间),则会发生分段错误。但是最常见的原因是访问虚拟地址空间中没有映射到物理地址空间的部分。
所有这些都与虚拟内存系统有关。
分段错误是由对该进程未在其描述符表中列出的页面的请求或对该进程未在其列表中列出的页面的无效请求(例如,对只读页面的写请求)引起的。
悬空指针是可能指向也可能不指向有效页的指针,但指向内存的“意外”段。
老实说,正如其他发布者所提到的那样,Wikipedia对此有很好的文章,因此可以在那里看看。这种类型的错误非常普遍,通常称为“访问冲突”或“常规保护错误”之类的其他错误。
它们在C,C ++或任何其他允许指针的语言中没有什么不同。这些类型的错误通常是由
根据维基百科:
当程序尝试访问不允许访问的存储位置,或者尝试以不允许的方式访问存储位置(例如,尝试写入只读位置,或者覆盖部分操作系统)。
Wikipedia的Segmentation_fault页面对此有很好的描述,仅指出了原因和原因。查看Wiki以获取详细说明。
在计算中,分段错误(通常简称为segfault)或访问冲突是具有内存保护功能的硬件引发的错误,它会通知操作系统(OS)有关内存访问冲突的信息。
以下是分段错误的一些典型原因:
这些反过来通常是由导致错误的内存访问的编程错误引起的:
取消引用或分配给未初始化的指针(野生指针,指向随机内存地址)
取消引用或分配给释放的指针(悬挂的指针,指向已释放/取消分配/删除的内存)
缓冲区溢出。
堆栈溢出。
试图执行无法正确编译的程序。(尽管存在编译时错误,某些编译器仍将输出可执行文件。)
当程序尝试访问不存在的存储位置或试图以不允许的方式访问存储位置时,就会发生分段错误或访问冲突。
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
这里i [1000]不存在,因此发生段错误。
分段故障的原因:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).
答案中有很多关于“分段错误”的很好的解释,但是由于分段错误经常存在内存内容的转储,因此我想分享分段错误中的“核心转储”部分(核心转储)与内存之间的关系。内存来自:
从大约1955年到1975年-在半导体存储器出现之前-计算机存储器中的主导技术使用了缠绕在铜线上的微小磁环。甜甜圈被称为“铁氧体磁芯”,主存储器因此被称为“磁芯存储器”或“核”。
取自这里。
分段错误有足够的定义,我想引用一些编程时遇到的例子,这些看似愚蠢的错误,但会浪费很多时间。
在以下情况下,您可能会遇到分段错误,而printf中的argumet类型不匹配
#include<stdio.h>
int main(){
int a = 5;
printf("%s",a);
return 0;
}
输出: Segmentation Fault (SIGSEGV)
当您忘记将内存分配给指针,但尝试使用它时。
#include<stdio.h>
typedef struct{
int a;
}myStruct;
int main(){
myStruct *s;
/* few lines of code */
s->a = 5;
return 0;
}
输出: Segmentation Fault (SIGSEGV)
简单的含义Segmentation fault
是您正在尝试访问一些不属于您的内存。Segmentation fault
当我们尝试在只读内存位置读取和/或写入任务或尝试释放内存时,会发生这种情况。换句话说,我们可以将其解释为某种内存损坏。
下面我提到导致程序员犯错误的常见错误Segmentation fault
。
scanf()
以错误的方式使用(忘了放&
)。int num;
scanf("%d", num);// must use &num instead of num
int *num;
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
char *str;
//Stored in read only part of data segment
str = "GfG";
//Problem: trying to modify read only memory
*(str+1) = 'n';
// allocating memory to num
int* num = malloc(8);
*num = 100;
// de-allocated the space allocated to num
free(num);
// num is already freed there for it cause segmentation fault
*num = 110;
printf()
和scanf()
' 时,请使用错误的格式说明符