2012-09-13 16 views
5

tại sao điều này không gây ra lỗi khi tôi biên dịch?Tại sao tôi không nhận được lỗi phân đoạn khi tôi viết ngoài phần cuối của mảng?

#include <iostream> 
using namespace std; 

int main() 
{ 
    int *a = new int[2]; 
    // int a[2]; // even this is not giving error 
    a[0] = 0; 
    a[1] = 1; 
    a[2] = 2; 
    a[3] = 3; 
    a[100] = 4; 
    int b; 

    return 0; 
} 

ai đó có thể giải thích lý do tại sao điều này xảy ra. Cảm ơn bạn trước.)

+4

Thật không may, hành vi được xác định ** đôi khi ** là tập con của hành vi không xác định: ( – Mahesh

+0

@Mahesh :)) không. –

+1

@LuchianGrigore ** Đôi khi ** – Mahesh

Trả lời

2

Tôi đoán bạn đang đến từ Java hoặc ngôn ngữ giống như Java khi bạn bước ra khỏi ranh giới của một mảng, bạn sẽ nhận được "chỉ mục mảng ngoài giới hạn" ngoại lệ.

Vâng, C mong đợi nhiều hơn từ bạn; nó tiết kiệm không gian bạn yêu cầu, nhưng nó không kiểm tra xem bạn có đi ra ngoài ranh giới của không gian đã lưu không. Một khi bạn làm điều đó như đã đề cập ở trên, chương trình có hành vi không xác định đáng sợ. Hãy nhớ về tương lai rằng nếu bạn có lỗi trong chương trình và dường như bạn không tìm thấy nó, và khi bạn đi qua mã/gỡ lỗi, mọi thứ có vẻ ổn, bạn có cơ hội tốt '. lại "ngoài giới hạn" và truy cập vào một địa điểm không được phân bổ.

9

Vì hành vi không xác định == mọi thứ có thể xảy ra. Bạn không may mắn rằng nó không sụp đổ, loại hành vi này có khả năng ẩn các lỗi.

Đối với a được xác định hai lần - đó là lỗi trong trình biên dịch.

+0

Tôi xin lỗi. "a" không được khai báo hai lần. Tôi chỉ muốn nói rằng cả hai tờ khai đều hoạt động tương tự. – singingsingh

+0

@singingsingh ok :) sau đó bỏ qua đoạn thứ hai. –

8

Khai báo hai biến được gọi là a chắc chắn là một lỗi; nếu trình biên dịch của bạn chấp nhận điều đó, thì nó bị hỏng. Tôi giả sử bạn có nghĩa là bạn vẫn không nhận được một lỗi nếu bạn thay thế một tuyên bố với người khác.

Truy cập mảng không được kiểm tra phạm vi. Tại thời gian biên dịch, kích thước của một mảng thường không được biết, và ngôn ngữ không yêu cầu kiểm tra ngay cả khi nó được. Vào thời gian chạy, một kiểm tra sẽ làm suy giảm hiệu suất, mà sẽ đi ngược lại triết lý C++ không trả tiền cho một cái gì đó bạn không cần. Vì vậy, truy cập vượt ra ngoài kết thúc của một mảng cho hành vi không xác định, và nó lên đến các lập trình viên để đảm bảo nó không xảy ra.

Đôi khi, quyền truy cập không hợp lệ sẽ gây ra lỗi phân đoạn nhưng điều này không được đảm bảo. Thông thường, bảo vệ bộ nhớ chỉ được áp dụng cho toàn bộ trang bộ nhớ, với kích thước trang điển hình là vài kilobyte. Mọi quyền truy cập trong một trang bộ nhớ hợp lệ sẽ không bị phát hiện. Có một cơ hội tốt mà bộ nhớ bạn truy cập có chứa một số biến chương trình khác hoặc một phần của ngăn xếp cuộc gọi, vì vậy việc viết có thể ảnh hưởng đến hành vi của chương trình theo bất kỳ cách nào bạn có thể tưởng tượng.

Nếu bạn muốn an toàn, bạn có thể sử dụng std::vector và chỉ truy cập các thành phần của nó bằng chức năng at(). Điều này sẽ kiểm tra chỉ mục và ném một ngoại lệ nếu nó nằm ngoài phạm vi. Nó cũng sẽ quản lý cấp phát bộ nhớ cho bạn, sửa lỗi rò rỉ bộ nhớ trong ví dụ của bạn.

+0

Tôi xin lỗi. "a" không được khai báo hai lần. Tôi chỉ muốn nói rằng cả hai tờ khai đều hoạt động tương tự. – singingsingh

0

trình biên dịch có phân tích mã tốt chắc chắn sẽ cảnh báo mã đó tham chiếu ngoài phân bổ mảng của bạn. quên nhiều bản khai, nếu bạn chạy nó, nó có thể hoặc có thể không lỗi (hành vi không xác định như những người khác đã nói). nếu, ví dụ, bạn có một trang 4KB của heap (trong không gian địa chỉ bộ xử lý), nếu bạn không viết bên ngoài trang đó, bạn sẽ không nhận được một lỗi từ bộ vi xử lý. khi xóa mảng, nếu bạn đã thực hiện nó, và tùy thuộc vào việc thực hiện heap, heap có thể phát hiện rằng nó bị hỏng.

Các vấn đề liên quan