Một lỗi phân khúc là gì? Có khác nhau ở C và C ++ không? Làm thế nào là lỗi phân khúc và con trỏ lơ lửng liên quan?
NullPointerException
.
Một lỗi phân khúc là gì? Có khác nhau ở C và C ++ không? Làm thế nào là lỗi phân khúc và con trỏ lơ lửng liên quan?
NullPointerException
.
Câu trả lời:
Lỗi phân đoạn là một loại lỗi cụ thể gây ra bởi việc truy cập bộ nhớ mà không thuộc về bạn. Đây là một cơ chế trợ giúp giúp bạn không làm hỏng bộ nhớ và đưa ra các lỗi bộ nhớ khó gỡ lỗi. Bất cứ khi nào bạn gặp lỗi segfault, bạn biết rằng mình đang làm gì đó với bộ nhớ - truy cập biến đã được giải phóng, ghi vào phần chỉ đọc của bộ nhớ, v.v. quản lý bộ nhớ, không có sự khác biệt chính giữa segfaults trong C và C ++.
Có nhiều cách để có được một segfault, ít nhất là trong các ngôn ngữ cấp thấp hơn như C (++). Một cách phổ biến để có được một segfault là hủy bỏ con trỏ null:
int *p = NULL;
*p = 1;
Một segfault khác xảy ra khi bạn cố ghi vào một phần bộ nhớ được đánh dấu là chỉ đọc:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
Con trỏ lơ lửng chỉ vào một thứ không còn tồn tại nữa, như ở đây:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
Con trỏ p
treo lủng lẳng vì nó trỏ đến biến ký tự c
không còn tồn tại sau khi khối kết thúc. Và khi bạn cố gắng hủy bỏ con trỏ lơ lửng (như *p='A'
), bạn có thể sẽ nhận được một segfault.
c
là địa phương, điều đó có nghĩa là nó đã được đẩy lên ngăn xếp sau đó {
và bật ra khỏi nó sau đó }
. con trỏ lơ lửng chỉ là một tham chiếu đến phần bù hiện nằm ngoài ngăn xếp. đó là lý do tại sao sửa đổi nó trong một chương trình đơn giản sẽ không bao giờ kích hoạt bất kỳ segfault nào. mặt khác, nó có thể dẫn đến segfault trong trường hợp sử dụng phức tạp hơn, trong đó các lệnh gọi hàm khác có thể dẫn ngăn xếp phát triển và chứa dữ liệu được trỏ bởi con trỏ lơ lửng. ghi vào dữ liệu đó (vars cục bộ) sẽ dẫn đến hành vi không xác định (segfault & Co)
SIGSEGV
, vì vậy tôi sẽ không mong đợi tín hiệu như vậy từ việc xáo trộn với ngăn xếp.
Điều đáng chú ý là lỗi phân đoạn không phải do truy cập trực tiếp vào bộ nhớ tiến trình khác (đôi khi đây là điều tôi nghe thấy), vì đơn giản là không thể. Với bộ nhớ ảo, mọi tiến trình đều có không gian địa chỉ ảo riêng và không có cách nào để truy cập vào một bộ nhớ khác bằng bất kỳ giá trị nào của con trỏ. Ngoại lệ cho điều này có thể là các thư viện chia sẻ có cùng không gian địa chỉ vật lý được ánh xạ tới (có thể) các địa chỉ ảo và bộ nhớ kernel khác nhau, thậm chí được ánh xạ theo cùng một cách trong mọi quy trình (để tránh TLB tuôn ra trên tòa nhà chọc trời, tôi nghĩ vậy). Và những thứ như shmat;) - đây là những gì tôi được coi là truy cập 'gián tiếp'. Tuy nhiên, người ta có thể kiểm tra xem chúng thường nằm cách mã quá trình và chúng ta thường có thể truy cập chúng (đây là lý do tại sao chúng ở đó,
Tuy nhiên, lỗi phân đoạn có thể xảy ra trong trường hợp truy cập bộ nhớ (quy trình) của chúng ta theo cách không phù hợp (ví dụ: cố gắng ghi vào không gian không thể ghi). Nhưng lý do phổ biến nhất cho nó là quyền truy cập vào một phần của không gian địa chỉ ảo hoàn toàn không được ánh xạ đến vật lý.
Và tất cả điều này liên quan đến hệ thống bộ nhớ ảo.
Lỗi phân đoạn là do yêu cầu đối với một trang mà quy trình không được liệt kê trong bảng mô tả hoặc yêu cầu không hợp lệ đối với trang mà nó đã liệt kê (ví dụ: yêu cầu ghi trên trang chỉ đọc).
Một con trỏ lơ lửng là một con trỏ có thể hoặc không thể trỏ đến một trang hợp lệ, nhưng lại trỏ đến một đoạn bộ nhớ "không mong muốn".
Thành thật mà nói, như các áp phích khác đã đề cập, Wikipedia có một bài viết rất hay về điều này vì vậy hãy xem ở đó. Loại lỗi này rất phổ biến và thường được gọi là những thứ khác như Vi phạm truy cập hoặc Lỗi bảo vệ chung.
Chúng không khác nhau về C, C ++ hoặc bất kỳ ngôn ngữ nào khác cho phép con trỏ. Những loại lỗi này thường được gây ra bởi con trỏ
Theo wikipedia:
Lỗi phân đoạn xảy ra khi chương trình cố gắng truy cập vị trí bộ nhớ mà nó không được phép truy cập hoặc cố gắng truy cập vị trí bộ nhớ theo cách không được phép (ví dụ: cố ghi vào vị trí chỉ đọc hoặc để ghi đè lên một phần của hệ điều hành).
Lỗi phân đoạn cũng là do lỗi phần cứng, trong trường hợp này là bộ nhớ RAM. Đây là nguyên nhân ít phổ biến hơn, nhưng nếu bạn không tìm thấy lỗi trong mã của mình, có thể một memtest có thể giúp bạn.
Giải pháp trong trường hợp này, thay đổi RAM.
biên tập:
Ở đây có một tài liệu tham khảo: Lỗi phân đoạn theo phần cứng
Lỗi phân đoạn xảy ra khi một quá trình (phiên bản đang chạy của chương trình) đang cố truy cập địa chỉ bộ nhớ chỉ đọc hoặc phạm vi bộ nhớ đang được quá trình khác sử dụng hoặc truy cập địa chỉ bộ nhớ không tồn tại (không hợp lệ). Vấn đề Tham chiếu (con trỏ) có nghĩa là cố gắng truy cập một đối tượng hoặc biến có nội dung đã bị xóa khỏi bộ nhớ, ví dụ:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
Trang Segmented_fault của Wikipedia có một mô tả rất hay về nó, chỉ nêu ra nguyên nhân và lý do. Có một cái nhìn vào wiki để mô tả chi tiết.
Trong điện toán, lỗi phân đoạn (thường được rút ngắn thành segfault) hoặc vi phạm truy cập là lỗi do phần cứng có bảo vệ bộ nhớ, thông báo cho hệ điều hành (HĐH) về vi phạm truy cập bộ nhớ.
Sau đây là một số nguyên nhân điển hình của lỗi phân đoạn:
Đến lượt chúng thường do lỗi lập trình dẫn đến truy cập bộ nhớ không hợp lệ:
Hủy bỏ hội nghị hoặc gán cho một con trỏ chưa được khởi tạo (con trỏ hoang dã, trỏ đến một địa chỉ bộ nhớ ngẫu nhiên)
Hủy bỏ hội nghị hoặc gán cho một con trỏ được giải phóng (con trỏ lơ lửng, trỏ đến bộ nhớ đã được giải phóng / giải phóng / xóa)
Một tràn bộ đệm.
Một chồng tràn.
Cố gắng thực hiện một chương trình không biên dịch chính xác. (Một số trình biên dịch sẽ xuất ra một tệp thực thi mặc dù có lỗi thời gian biên dịch.)
Nói một cách đơn giản: lỗi phân đoạn là hệ điều hành gửi tín hiệu đến chương trình nói rằng nó đã phát hiện truy cập bộ nhớ bất hợp pháp và chấm dứt sớm chương trình để ngăn bộ nhớ bị hỏng.
"Lỗi phân đoạn" có nghĩa là bạn đã cố truy cập vào bộ nhớ mà bạn không có quyền truy cập.
Vấn đề đầu tiên là với các đối số của bạn là chính. Hàm chính phải là int main(int argc, char *argv[])
và bạn nên kiểm tra xem argc có ít nhất 2 trước khi truy cập argv [1] không.
Ngoài ra, vì bạn đang chuyển từ float sang printf (nhân tiện, được chuyển đổi thành gấp đôi khi chuyển sang printf), bạn nên sử dụng công cụ xác định định dạng% f. Trình xác định định dạng% s dành cho các chuỗi (mảng ký tự kết thúc '\ 0').
Lỗi phân đoạn hoặc vi phạm truy cập xảy ra khi chương trình cố gắng truy cập vị trí bộ nhớ không tồn tại hoặc cố gắng truy cập vị trí bộ nhớ theo cách không được phép.
/* "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;
Ở đây tôi [1000] không tồn tại, vì vậy segfault xảy ra.
Nguyên nhân của lỗi phân khúc:
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).
Có rất nhiều lời giải thích tốt về "Phân đoạn lỗi" trong các câu trả lời, nhưng kể từ khi có lỗi segmentation thường có một bãi chứa nội dung bộ nhớ, tôi muốn chia sẻ nơi mối quan hệ giữa "cốt lõi đổ" gia lỗi Segmentation (core dumped) và bộ nhớ đến từ:
Từ khoảng năm 1955 đến 1975 - trước khi có bộ nhớ bán dẫn - công nghệ vượt trội trong bộ nhớ máy tính đã sử dụng những chiếc bánh rán từ tính nhỏ được xâu chuỗi trên dây đồng. Các bánh rán được gọi là "lõi ferrite" và bộ nhớ chính được gọi là "bộ nhớ lõi" hoặc "lõi".
Lấy từ đây .
Có đủ định nghĩa về lỗi phân đoạn, tôi muốn trích dẫn một vài ví dụ mà tôi đã gặp trong khi lập trình, có vẻ như là những lỗi ngớ ngẩn, nhưng sẽ lãng phí rất nhiều thời gian.
bạn có thể gặp lỗi phân đoạn trong trường hợp dưới đây trong khi kiểu argumet không khớp trong printf
#include<stdio.h>
int main(){
int a = 5;
printf("%s",a);
return 0;
}
đầu ra: Segmentation Fault (SIGSEGV)
khi bạn quên phân bổ bộ nhớ cho một con trỏ, nhưng cố gắng sử dụng nó.
#include<stdio.h>
typedef struct{
int a;
}myStruct;
int main(){
myStruct *s;
/* few lines of code */
s->a = 5;
return 0;
}
đầu ra: Segmentation Fault (SIGSEGV)
Ý nghĩa đơn giản Segmentation fault
là bạn đang cố truy cập một số bộ nhớ không thuộc về bạn. Segmentation fault
xảy ra khi chúng ta cố gắng đọc và / hoặc ghi các tác vụ trong một vị trí bộ nhớ chỉ đọc hoặc cố gắng giải phóng bộ nhớ. Nói cách khác, chúng ta có thể giải thích điều này như một loại tham nhũng bộ nhớ.
Dưới đây tôi đề cập đến những lỗi phổ biến được thực hiện bởi các lập trình viên dẫn đến Segmentation fault
.
scanf()
sai cách (quên đặt &
).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()
và scanf()
'