2012-04-21 36 views
5

tôi đã viết một mã sử dụng malloc cho một cái gì đó và sau đó phải đối mặt với một vấn đề vì vậy tôi đã viết một mã kiểm tra mà thực sự tóm tắt toàn bộ sự nhầm lẫn đó là bên dưới ::cấp phát bộ nhớ động trong 'c' Các vấn đề

# include <stdio.h> 
# include <stdlib.h> 
# include <error.h> 

int main()  
{ 
    int *p = NULL; 
    void *t = NULL; 
    unsigned short *d = NULL; 

    t = malloc(2); 
    if(t == NULL) perror("\n ERROR:"); 
    printf("\nSHORT:%d\n",sizeof(short)); 
    d =t; 
    (*d) = 65536; 
    p = t; 
    *p = 65536; 
    printf("\nP:%p: D:%p:\n",p,d); 
    printf("\nVAL_P:%d ## VAL_D:%d\n",(*p),(*d)); 
    return 0; 
    } 
    Output:: [email protected]:~/Desktop/ad/A1/CC$ ./test 

      SHORT:2 
      P:0x9512008: D:0x9512008: 
      VAL_P:65536 ## VAL_D:0 

Tôi đang phân bổ 2 byte bộ nhớ bằng cách sử dụng malloc. Malloc trả về một con trỏ void * được lưu trữ trong một con trỏ void * t '.

Sau đó, sau đó 2 con trỏ được khai báo loại p - số nguyên và d - loại ngắn. sau đó tôi gán t cho cả hai người * (p = t và d = t) * có nghĩa là cả hai d & p đang trỏ đến cùng một vị trí ghi nhớ trên heap.

khi cố gắng lưu 65536 (2^16) đến (* d) tôi nhận được cảnh báo rằng giá trị int lớn bị cắt ngắn như mong đợi. Bây giờ tôi một lần nữa lưu 65536 (2^16) đến (* p) mà không gây ra bất kỳ cảnh báo nào.

* Khi in cả (* p) và (d) tôi có các giá trị khác nhau (mặc dù mỗi giá trị chính xác cho riêng loại con trỏ được xác định).

Câu hỏi của tôi là:

  1. Mặc dù tôi đã phân bổ 2 byte (tức là 16 bit) của đống mem sử dụng malloc Làm sao tôi có thể tiết kiệm 65536 trong hai byte (bằng cách sử dụng (p) đó là một con trỏ của kiểu số nguyên). ?? tôi có một cảm giác rằng nguyên nhân của việc này là tự động loại converion của void để int * pointer (trong p = t) như vậy là nó gán t để p dẫn đến truy cập vào vùng bộ nhớ bên ngoài những gì được phân bổ thông qua malloc. ??.

  2. Mặc dù tất cả điều này xảy ra như thế nào địa ngục derefrencing cùng một vùng bộ nhớ thông qua (* p) và (* d) in hai câu trả lời khác nhau (mặc dù điều này cũng có thể được giải thích nếu những gì tôi đang nghĩ nguyên nhân trong câu hỏi 1).

Ai đó có thể đặt một số ánh sáng về vấn đề này, nó sẽ được thực sự appreciated..and cũng nếu một số ai có thể giải thích lý do đằng sau này ..

Rất cám ơn

+0

Malloc có thể làm tròn kích thước được yêu cầu lên tới một số nhân nhất định. Không biết về * nix, nhưng Windows thích làm tròn nó lên đến bội số của 8 byte. Nếu đúng như vậy, bạn đang viết bên ngoài khu vực bạn yêu cầu, nhưng nó sẽ xảy ra bên trong lề an toàn, và do đó bạn không làm hỏng bất cứ thứ gì khác. – DCoder

+0

Bạn đã cẩn thận lạm dụng quyền lực đúc để có được hành vi không xác định. C cung cấp cho bạn sức mạnh tuyệt vời và tính linh hoạt để làm * những điều xấu *. Bạn phải chịu trách nhiệm để *** không làm họ ***. – dmckee

+0

@ dmckee tôi biết những gì tôi đang làm không nên được thực hiện nhưng sau khi ngại về điều này tôi đã tò mò muốn biết lý do chính xác đằng sau nó mà tôi đoán ban đầu là thực tế là tự động chuyển đổi loại int * của một con trỏ 2 byte void * dẫn đến int * con trỏ truy cập nhiều bộ nhớ hơn 2 byte vì int máy của tôi là 4 byte. Điều này có đúng không (giả định của tôi) – abhi

Trả lời

2

Trả lời câu hỏi thứ hai của bạn đầu tiên:

Câu trả lời rất thực tế là một int thường là 4 byte, và các byte quan trọng nhất có thể được lưu trữ ở hai vị trí đầu tiên.Một short, chỉ có 2 byte, cũng lưu trữ dữ liệu của nó ở hai vị trí đầu tiên. Rõ ràng, sau đó, lưu trữ 65536 trong một intshort, nhưng chỉ vào cùng một vị trí bộ nhớ, sẽ làm cho dữ liệu được lưu trữ bù đắp hai byte cho int liên quan đến short, với hai byte ít quan trọng nhất của int tương ứng với bộ nhớ cho short.

Vì vậy, khi các bản in biên dịch *d, nó diễn giải điều này như một short và nhìn vào khu vực tương ứng với lưu trữ cho một short, mà không phải là nơi trình biên dịch được lưu trước đó các 65536 khi *p được viết ra. Lưu ý rằng viết *p = 65536; ghi đè *d = 65536; trước đó, điền hai byte ít quan trọng nhất với 0.

Về câu hỏi đầu tiên: Trình biên dịch thực hiện không lưu trữ 65536 cho *p trong phạm vi 2 byte. Nó chỉ đơn giản là đi ra ngoài giới hạn của bộ nhớ bạn đã phân bổ - có khả năng gây ra một lỗi tại một số điểm.

+0

Vì vậy, thực tế là chuyển đổi kiểu tự động thành int * của con trỏ 2 byte được phân bổ void * dẫn đến int * con trỏ truy cập nhiều bộ nhớ hơn 2 byte vì int máy của tôi là 4 byte. Điều này có đúng không (giả định của tôi) – abhi

+0

và cảm ơn câu trả lời rõ ràng và rõ ràng giải thích mọi thứ :) – abhi

+1

Về mặt khái niệm, đó là nó. Tôi muốn nói về mặt kỹ thuật, có lẽ không phải là từ ngữ tốt nhất để nói "chuyển đổi kiểu tự động" trong câu của bạn, bởi vì không có gì thực sự được chuyển đổi - nó chỉ là trình biên dịch truy cập các byte trong bộ nhớ như thể chúng đang lưu trữ một loại dữ liệu, trái với việc truy cập chúng như thể chúng đang lưu trữ một kiểu khác. –

1

Trong C có không có sự bảo vệ nào cả cho việc viết ra các giới hạn của một phân bổ. Chỉ cần không làm điều đó, bất cứ điều gì có thể xảy ra. Ở đây nó có vẻ làm việc cho bạn bởi vì một số trùng hợp ngẫu nhiên không gian đằng sau hai byte bạn được phân bổ không được sử dụng cho cái gì khác.

+0

Hoặc ít nhất anh ta đã không làm bất cứ điều gì thể hiện một số sử dụng khác cho bộ nhớ đó. Phản ứng im lặng đối với loại lỗi này là điều cho phép họ lẻn vào bạn. – dmckee

0

1) Mức độ chi tiết của trình quản lý bộ nhớ OS là 4K. An ovewrite bởi một chút là không thể kích hoạt một AV/segfault, nhưng nó sẽ làm hỏng bất kỳ dữ liệu ở vị trí liền kề, dẫn đến:

2) Hành vi không xác định. Tập hợp hành vi này bao gồm 'hoạt động chính xác khác', (hiện tại!).

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