2013-03-09 28 views
6

Chúng tôi đã có một dự án trường học, bất kỳ hệ thống thông tin nào sử dụng C. Để giữ một danh sách sinh viên có kích thước động, tôi đã đi đến một cấu trúc dữ liệu danh sách được liên kết. Sáng nay bạn tôi cho tôi xem hệ thống của anh ấy. Tôi đã rất ngạc nhiên với danh sách hồ sơ của anh ấy:C mảng chưa được đánh dấu toàn cầu?

#include <stdio.h> 
/* and the rest of the includes */ 

/* global unsized array */ 
int array[]; 

int main() 
{ 
    int n; 
    for (n=0; n < 5; n ++) { 
     array[n] = n; 
    } 


    for (n=0; n < 5; n ++) { 
     printf("array[%d] = %d\n", n, array[n]); 
    } 
    return 0; 
} 

Giống như đoạn mã, anh ấy đã khai báo mảng không xác định là toàn cầu (trong phân đoạn bss) cho toàn bộ chương trình. Ông đã có thể thêm các mục mới để mảng bằng cách ghi đè các khối tiếp theo của bộ nhớ với một giá trị khác hơn không để ông có thể đi qua các mảng thusly:

for (n=0; array[n]; n++) { 
    /* do something */ 
} 

Ông đã sử dụng (Tôi cũng đã thử nghiệm nó với) Turbo C v1 . Tôi đã thử nó trong linux và nó cũng hoạt động.

Vì tôi chưa bao giờ gặp phải kỹ thuật này trước đây, tôi cho là có vấn đề với nó. Vì vậy, yeah, tôi muốn biết tại sao đây là một ý tưởng tồi và tại sao lại thích điều này hơn một danh sách liên kết.

+1

Giống như ghi vào bất kỳ mảng nào ngoài giới hạn - không xác định. – teppic

+0

có phải là c99 không? –

+0

1der Vui lòng kiểm tra câu trả lời cập nhật của teppic.và mở liên kết codepad bạn có thể quan sát hành vi không xác định của C trong mã của bạn. –

Trả lời

6
int array[]; 

là về mặt kỹ thuật được gọi là một mảng với đầy đủ loại. Đơn giản chỉ cần đặt nó tương đương với:

int array[1]; 

Đây không phải là tốt đơn giản vì:

  1. Nó tạo ra một hành vi Undefined. Việc sử dụng chính mảng có loại không đầy đủ là trong Struct Hack. Lưu ý rằng các loại mảng không hoàn chỉnh được chuẩn hóa trong C99 và chúng là bất hợp pháp trước đây.
+0

Không phải chỉ UB, vì GCC nói 'source.c: 4: 5: warning: array 'array' được giả sử có một phần tử [được kích hoạt mặc định]' có nghĩa là anh ta sẽ viết bên ngoài giới hạn của mảng đi xa hơn 1 phần tử? –

+2

Nó không phải là VLA, nó chỉ ghi vào một địa chỉ ngẫu nhiên trong bộ nhớ. – teppic

+0

@teppic, Tony: Yup, được sửa đổi để phản ánh đúng đắn. –

3

Đây là Hành vi chưa xác định. Bạn đang viết cho bộ nhớ chưa được phân bổ (ngoài mảng). Để biên dịch điều này, trình biên dịch phân bổ ít nhất một phần tử, và sau đó bạn viết ra ngoài phần tử đó. Hãy thử một phạm vi số lớn hơn nhiều. Ví dụ, nếu tôi chạy mã của bạn trên Linux nó hoạt động, nhưng nếu tôi thay đổi vòng lặp thành 50.000, nó sẽ bị treo.

CHỈNH SỬA Mã có thể hoạt động với các giá trị nhỏ n nhưng đối với các giá trị lớn hơn, nó sẽ thất bại. Để chứng minh điều này tôi đã viết mã của bạn và thử nghiệm nó cho n = 1000.

Đây là liên kết cho CODEPAD và bạn có thể thấy rằng đối với n = 1000, lỗi phân đoạn xảy ra.

Trong khi có cùng mã với cùng trình biên dịch, nó hoạt động với n = 10, xem liên kết này CODEPAD. Vì vậy, điều này được gọi là Hành vi không xác định.

+0

Tôi thêm một số chi tiết hơn trong câu trả lời của bạn để chứng minh hành vi Undefined cho mã. Hy vọng bạn thích nó. Nếu không, bạn có thể hoàn nguyên về phiên bản –

+0

@GrijeshChauhan: ok, tôi sẽ chỉnh sửa nó một chút. – teppic

+0

vâng, hãy tiếp tục. :) –

1

Nếu bạn sử dụng danh sách được liên kết, bạn có thể kiểm tra xem bộ nhớ có được cấp đúng hay không.

int *ptr; 
ptr = (int *)malloc(sizeof(int)) 
if(ptr==NULL) 
{ 
    printf("No Memory!!!"); 
} 

Nhưng với mã chương trình của bạn chỉ gặp sự cố nếu được kiểm tra với một mảng có giới hạn lớn.

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