Вы находитесь на странице: 1из 24

Bản chất của việc cấp phát bộ nhớ động và giải phóng bộ nhớ

Hum nay mình sẽ đưa ra phân tích rõ bản chất của việc cấp phát và giải phóng bộ nhớ

1. Dẫn nhập
Bộ nhớ là 1 tài nguyên quan trọng trong hệ thống , được phân phối điều phối phức tạp.

ở đây, chúng ta sẽ xét tương quan như sau cho dễ hiểu : đất là 1 tài nguyên quý giá trong
thành phố và được điều phối bởi sở tài nguyên môi trường
(coi như thế, giờ hình như nó thuộc sở nhà đất thì phải,nói tóm lại là sở quản lí)

2. Cấp phát bộ nhớ :


Bộ nhớ quan trọng như thế ko thể tùy tiện sử dụng , vì trong máy có nhiều tiếng trình cần
bộ nhớ, tùy tiện sử dụng thì lấy đâu ra mà dùng ????

ai cũng cần có đất, cứ tùy tiện lấy gì cần gì sở quản lý, như thế sẽ có người không có đất mà
dùng ???

Cấp phát bộ nhớ hoạt động như thế nào : bản chất là trao quyền sử dụng.

hôm nay 1 người (1 con trỏ) xin cấp phát (malloc, new) 1 vùng đất, anh ta được trao quyền
sử dụng 1 vùng đất đó.
Khi này :
+ Có thể trên mảnh đất này đang trống rỗng (toàn null) nhưng cũng có thể trên đó đầy cỏ
rác,hoa màu hoặc nhà cửa do người trước đó sử dụng vẫn còn . (điều này đối với anh ta mà
nói nó hoàn toàn là ngẫu nhiên, ko ai có thể khẳng định được cả)
>>>>> khi ta xin cấp phát xong thì vùng nhớ đó hoàn toàn có giá trị ngẫu nhiên

+ Nếu như khi anh ta xin cấp phát mà có đút lót để ra thêm điều kiện hoặc trước đó anh ta
có thuê thêm 1 người quét dọn xây sửa thì anh sẽ có được 1 mảnh đất có sẵn cái anh ta
muốn
>>>> khi ta cấp phát đi cùng với ép buộc sẽ được vùng nhớ có giá trị như ta mong muốn
ví dụ
PHP Code:
int *a=new int(4);
int *b=(int*)malloc(1000);
memset(b.....);
static int x[1000];
static int y[10]={1,2,3,4,5,6};

<<<<<<<< toàn bộ điều này là đáp án tại sao khi cấp phát bộ nhớ lại có giá trị ngẫu nhiên

3. Giải phóng bộ nhớ như thế nào

Anh ta dùng xong đất rồi, ko cần nữa, đem trả quyền sử dụng mảnh đất lại cho khổ chủ.

Giải bộ nhớ hoạt động như thế nào : bản chất là trả lại quyền sử dụng
khi này :
+ sở sẽ thu lại quyền sử dụng đất của anh, thế là đủ rồi, sở ko cần phải động chạm sửa
chữa lại gì vùng đất đó. Nên khi đó dù vùng đất đó đã được giải phóng nhưng mà hoa màu
của a ta trên đó thì vẫn còn, ko có biến mất được

điều này giải thích tại sao khi mà trong 1 số hệ điều hành đời cổ, (các bạn lính mới bây giờ
chắc không gặp) nhiều bạn thử giải phóng bộ nhớ rồi, delete rồi, free rồi mà khi in thử ra
vẫn thấy kết quả như thế .
đơn giản thôi, a ta trả lại mảnh đất đó, nhưng chưa có ai thuê nó cả, chưa có ai sử dụng nên
hôm sau ra xem thử thì nó vẫn như hôm trước khi a ta trả lại
Các bạn đọc rõ chú ý ở dưới rồi hẵng hỏi thêm về câu này nhé.

Và các bạn phải chú ý là quyền sử dụng đất mới là cái được quan tâm duy nhất của vấn đề
này

PHP Code:
int *a=new int[10];
int *b=(int*)malloc(1000);

thì giá trị trong a và b là địa chỉ của vùng nhớ được cấp phát. địa chỉ này sẽ được lưu lại
trong sở, sở sẽ dùng cái số địa chỉ này để hiểu là quyền sử dụng đất khi giải phóng

tiếp theo
PHP Code:
free(b);
delete []a;

2 câu lệnh này ko có làm thay đổi giá trị của a và ba và b vẫn trỏ vào mảnh đất đấy. ok ?
Và càng ko can thiệp vào vùng nhớ mà a ,b trỏ đến, cái duy nhất mà nó làm là xác nhận
vùng nhớ đó đã được trả lại, đang rảnh rỗi, có thể cho thuê tiếp.

<<< điều này giải thích cho cách hiểu sai lầm của 1 số bạn mới học đối với việc cấp phát và
giải phóng

4. Memory leak

Câu hỏi mở rộng :


như thế này có phải là giải phóng ko
PHP Code:
int*x=new int[20];
x=NULL; <<<<< như thế này có phải là giải phóng ko

ở trong C (not java, java khác) thì :


câu trả lời là không , bạn đã hiểu sai lầm hoàn toàn về việc giải phóng rồi, bạn nên đọc kĩ lại
phần giải phóng để hiểu tại sao.
như thế này chính là :
anh ta đánh mất cái quyền sử dụng đất của mình, kết quả là vùng đất đó ko được sở lấy về,
sau nhiều lần như thế thì tài nguyên đất của sở càng ngày càng ít đi, hiện tượng này gọi mà
memory leak

Sau khi chương trình kết thúc , việc bộ nhớ xin cấp phát có được tự giải phóng hay ko thì
tùy thuộc vào cài đặt của trình biên dịch và hệ điều hành. Chúng ta có 2 khả năng Khả
năng 1 : trong phần khởi động (trước khi vào function main() ), program xin một khối
memory cuả system gọi là XXXX và mỗi lần malloc được gọi thì cấp pháp một phần memory
cuả XXXX cho malloc. Do đó, khi program exit thì trả XXXX về cho system là xong. Trong
trường hợp này không bị mất memory
Khả năng 2 : mỗi lần malloc được gọi thì xin memory từ system . Trường hợp này có thể
memory không trả về cho system. Lúc này chương trình sẽ bị gọi là có memory leak.Như
vậy sau vài lần chạy sẽ ko còn memory để cấp phát nữa

Đó là giải thích tại sao có nhiều chương trình chạy xong, thoát ra rồi, f5 mấy lần rồi mà máy
vẫn cứ ì ì ì ra..........

5. Trên đây là cách lý thuyết cơ bản dành cho các bạn mới học, nó được áp dụng đối với lập
trình trên console, (cấp sở tài nguyên thôi)
trong windows nó cũng như thế thôi nhưng mà nó có thêm nhiều quy tắc rằng buộc chặt
chẽ hơn rất nhiều (cấp bộ tài nguyên và môi trường, phải khác chứ)

Muốn biết thêm về bộ nhớ thì xem chap 1 của tut dưới đây :

Portable Executable File Format

Update 9/9/10
Câu hỏi
Nhân tiện cho em hỏi, nếu mình khai báo 1 mảng có thể có rất nhiều phần tử thì bộ nhớ của
nó sẽ được lấy từ đâu ra (Ổ cứng, Ram.... Hay là một cái gì đó mà em không biết :P). Khi
em khai báo 1 mảng int a[1000000] thì nó báo là "Array size too large". Mới có 1000000
phần tử nó đã coi là lớn thì những bài toán thực tế vài triệu phần tử liền thì phải làm thế
nào? hix
Trả lời
int a[1000000] ; khai báo ở đâu ?
em khai báo ở sở (tức là khai báo dạng local, trong các hàm )thì sở nó xin vùng nhớ ở stack
segment, mà stack segment thì đây (trong ảnh, nhỏ gọn thế này, liệu nó có cho em vùng
lớn thế kia ko 1000000*4byte)

Click vào ảnh để xem hình đẩy đủ


đối với các bài toán cần nhiều vùng nhớ 1 cách kinh khủng thì ta thường dùng các hàm api
về malloc để lấy các vùng nhớ ở free store được bộ (os-hệ điều hành) cấp phát,

và 1 điều ko kém phần quan trọng đó là ta nên xây dựng những giải thuật thật thông minh
chứ ko phải là load tràn hết lên bộ nhớ
ví dụ xây dựng trước các phương pháp xử lý các sự kiện có thể xảy ra
giả sử như này, tôi có 1 khối thông tin, để bắt sự kiện "tìm nhân viên mới vào công ti", tôi
lập ra 1 temponary, mỗi khi chèn thằng mới vào khối thông tin của tôi, tôi gán thằng
temponary này bằng với nhân viên mới, như thế tôi đã có 1 phương pháp sử lí sự kiện tốt
rồi đúng ko ???

Update 10/9/10
câu hỏi

Cấp phát động thì nó lấy bộ nhớ từ đâu vậy cà.


"data segment"
Là cái gì thế em dịch là dữ liệu phân đoạn, nghĩa là sao đây, anh langman bận rộn thế :P:P
a. theo giáo trình đại học FPT về OS,theo giáo trình thầy phạm văn ất về tổ thức bộ nhớ, khi
tiến trình chạy , bộ nhớ được mô hình thành 4 phần như sau

(trên thực tế, trong windows, môi trường ảo hóa cụ thể này thì có cách tổ chức phức tạp
hơn phát triển từ lý thuyết này)
b. đang bận ôn thi ko có time online được

Update 20/11/10
Câu hỏi của quyết 1991 : sự khác nhau giữa malloc và new?

new và malloc khác nhau cực cực kì nhiều đó các pạn à


sơ bộ như sau, chưa phân tích kĩ
malloc là hàm, cấp phát trả về kiểu void *, malloc thì ko gọi hàm tạo
free ko gọi hàm hủy
malloc trả về NULL nếu thất bại

new là toán tử, new gọi hàm tạo, new có thể được đa năng hóa (nạp chồng),
new ném ra exception nếu thất bại
toán tử new và toán tử new[] ko có khả năng realloc

Update tiếp câu hỏi hay 2/3/2010


Nguyên bản được gửi bởi first_pace
Anh cho em hỏi rõ hơn về đoạn này. Khi giải phóng rồi mà a và b vẫn trỏ đến mảnh đất đó thì nghĩa là
nó vẫn có quyền kiểm soát khu vực đó, như vậy thì sao biết là khi đó đất là available đựoc ạ. Em có test
một đoạn chương trình như sau.
C Code:
Select All | Show/Hide
1. #include <iostream>
2. using namespace std;
3.
4. int main(){
5. int *p;
6.
7. p= new int[2]; // xin chính quyền cấp hai khu đất
8. p[0]=8888; // khu này trồng rau
9. p[1]=9999; // khu này nuôi lợn
10. cout << p[0] << " " << p[1] << endl; // xem tình hình ruộng rau và
chuồng lợn
11.
12. delete [] p; // trả lại đất cho chính quyền
13. cout << p[0] << " " << p[1] << endl; // xem chính quyền làm gì với ruộng
rau và chuồng lợn
14.
15. system("pause");
16. return 0;
17.}

kết quả là em không thấy ruộng rau và chuồng lợn đâu nữa

em nghĩ có hai nguyên nhân

 Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi nội dung
của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh nói nó không
can thiệp vào.
 Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước nữa.
Nhưng anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu đất đó (p
vẫn trỏ tới vùng nhớ mà trước đó nó trỏ tới)

Nếu thế thì em không giải thích được kết quả của chương trình trên. Anh giải thích kỹ hơn giùm em với.
Cám ơn anh

xin khẳng định lại 1 lần nữa, e đã hiểu hoàn toàn sai lầm, FREE và DEL ko bao giờ
thay đổi giá trị của con trỏ, hãy phân việt rõ ràng giữa giá trị của con trỏ và giá trị
nó trỏ đến

free nó là void free(void *mem) vậy thì xin hỏi con trỏ mem làm sao có thể thay đổi giá trị
qua hàm này (xin hãy đọc bài bản chất con trỏ trong C để hiểu sâu hơn vấn đề này, tip :
phân biệt rõ ràng giữa giá trị của mem và giá trị của thằng mà mem trỏ tới)

check lại đoạn code sau đây


C++ Code:
Select All | Show/Hide
1. #include <iostream>
2. using namespace std;
3.
4. int main(){
5. int *p;
6.
7. p= new int[2]; // xin chính quyền cấp hai khu đất
8. p[0]=8888; // khu này trồng rau
9. p[1]=9999; // khu này nuôi lợn
10. cout << p[0] << " " << p[1] << endl; // giá trị trỏ đến
11. printf("%x\n",p); // giá trị của p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
12.
13.
14. delete [] p; // trả lại đất cho chính quyền
15. cout << p[0] << " " << p[1] << endl; // xem chính quyền làm gì với ruộng
rau và chuồng lợn
16. printf("%x\n",p); // giá trị của p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
17.
18. system("pause");
19. return 0;
20. }

điều nữa
Giải bộ nhớ hoạt động như thế nào : bản chất là trả lại quyền sử dụng
khi này :
+ sở sẽ thu lại quyền sử dụng đất của anh, thế là đủ rồi, sở ko cần phải động chạm sửa chữa lại gì vùng
đất đó. Nên khi đó dù vùng đất đó đã được giải phóng nhưng mà hoa màu của a ta trên đó thì vẫn còn,
ko có biến mất được

điều này giải thích tại sao khi mà nhiều bạn thử giải phóng bộ nhớ rồi, delete rồi, free rồi mà khi in thử ra
vẫn thấy kết quả như thế .
đơn giản thôi, a ta trả lại mảnh đất đó, nhưng chưa có ai thuê nó cả, chưa có ai sử dụng nên hôm sau ra
xem thử thì nó vẫn như hôm trước khi a ta trả lại
giả sử ngay khi em vừa trả , có thằng khác nó đến thuê luôn thì lập tức nó bỏ hoa màu của
em đi, trồng hoa màu khác thì em quay lại làm gì còn thời đại này nhanh như ăn cắp ý mà

(windows có bao nhiêu process, thread,? nên việc bị thuê ngay lập tức là quá bình thường,
em à, đặc biệt nếu là hàng nằm trên stack thì thay đổi liên tục là bt)

More :
Nguyên bản được gửi bởi first_pace
Thanks anh, giá trị của con trỏ và giá trị của vùng nhớ mà con trỏ trỏ tới thì em biết. Em chỉ thắc mắc
không hiểu tại sao khi kiểm tra lại thì giá trị của vùng nhớ lại bị thay đổi (8888 và 9999) nên em với đặt
ra hai khả năng:
 Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi nội dung
của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh nói nó không
can thiệp vào.
 Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước nữa. Nhưng
anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu đất đó (p vẫn trỏ tới
vùng nhớ mà trước đó nó trỏ tới)

Và theo câu trả lời của anh nó là khả năng thứ nhất, bị thằng nào đó thuê lại ngay sau đó:

Thanks anh đã giải đáp đoạn này, em không biết là nó lại bị thuê luôn như thế, em hiểu rồi
khi em cài hook bắt các API trên window sẽ thấy LocalAlloc, RemoteAlloc,GlobalAlloc... được
xài rất nhiều lần trên /1s chứ ko phải (ví dụ nhỏ xem ở hình dưới , đó là chỉ trong 1 tiến
trình firefox thôi đó, chứ ko phải xét trên 5x process đang chạy)

tuy nhiên đối với các môi trường cũ, đặc biệt như trên borland C for dos thì hiện tượng free
rồi mà còn tài nguyên rất hay xảy ra, có rât rất nhiều người hiểu lầm là lỗi, rồi ... (đã có rất
nhiều câu hỏi như thế trong box thắc mắc C). đó là lý do vì sau a phải nhấn mạnh điều đó

Attached Thumbnails

nếu mình khai báo 1 mảng có thể có rất nhiều phần tử thì bộ nhớ của nó sẽ được lấy từ đâu
ra (Ổ cứng, Ram.... Hay là một cái gì đó mà em không biết :P). Khi em khai báo 1 mảng int
a[1000000] thì nó báo là "Array size too large". Mới có 1000000 phần tử nó đã coi là lớn thì
những bài toán thực tế vài triệu phần tử liền thì phải làm thế nào? hix
Và cái "Program heap size" có phải là bộ nhớ để cấp phát động không ạ? Mình chỉ được cấp
phát tối đa là 640KB?

int a[1000000] ; khai báo ở đâu ?


em khai báo ở sở (tức là khai báo dạng local, trong các hàm )thì sở nó xin vùng nhớ ở stack
segment, mà stack segment thì đây (trong ảnh, nhỏ gọn thế này, liệu nó có cho em vùng
lớn thế kia ko 1000000*4byte)

Em khai báo trong hàm main(); thế nếu em khai báo là mảng toàn cục thì nó lấy ở đâu ra.

các hằng và biến tĩnh nằm data segment,

cậu phải cấp phát động mới được lớn như thế chứ
Cấp phát động thì nó lấy bộ nhớ từ đâu vậy cà.

"data segment"
Là cái gì thế em dịch là dữ liệu phân đoạn, nghĩa là sao đây, anh langman bận rộn thế :P:P
4 segment đó khi biên dịch thì được xác định kích thước cụ thể, hầu hết các trình biên dịch
đều cho phép bạn chọn lựa kích thước (tiny, small...) cho 4 vùng này để đáp ứng nhu cầu
bộ nhớ khi thực thi chương trình.
khái niệm con trỏ gần, con trỏ xa (định nghĩa, khai báo, sử dụng...) và mối liên quan của
chúng đối với địa chỉ vùng nhớ
2 vấn đề trên bạn có thể tìm thấy trong sách của Phạm Văn Ất (phần mục lục), cuốn sách
nói về C nha (ông có 2 cuốn, 1 cuốn nói về C và 1 cuốn nói về hướng đối tượng). Tuy chỉ
giới thiệu chung chung nhưng cũng có thể cho bạn hướng đi tiếp theo để làm sáng tỏ vấn đề
khai niệm con trỏ gần con trỏ xa chỉ được dùng trong dos os cũ, với các IDE cũ từ đời tống
truyền lại, ko còn tồn tại trong môi trường windows bây giờ nữa
chỉ có duy nhất con trỏ thôi, 32bit, trỏ hết vùng nhớ VA
Sau khi chương trình kết thúc , việc bộ nhớ xin cấp phát có được tự giải phóng hay ko thì tùy thuộc vào
cài đặt của trình biên dịch và hệ điều hành. Chúng ta có 2 khả năng · Khả năng 1 : trong phần khởi động
(trước khi vào function main() ), program xin một khối memory cuả system gọi là XXXX và mỗi lần malloc
được gọi thì cấp pháp một phần memory cuả XXXX cho malloc. Do đó, khi program exit thì trả XXXX về
cho system là xong. Trong trường hợp này không bị mất memory
· Khả năng 2 : mỗi lần malloc được gọi thì xin memory từ system . Trường hợp này có thể memory
không trả về cho system. Lúc này chương trình sẽ bị gọi là có memory leak.Như vậy sau vài lần chạy sẽ
ko còn memory để cấp phát nữa
option 2 thông thường malloc thì xin memory từ system nhưng trường hợp đó khi process bị
kill or exit thì nó vẫn giải phóng đc vì OS nó đã quản lý việc này, nếu ở option 2 bạn có thể
cho ví dụ or code để clear hơn chút.

Vẫn có thể trong những trường hợp đặc biệt chạy không có OS thì mới có khả năng này
[thông thường trong các hệ thống nhúng của micro system]
ví dụ 1 : Mình nhớ ngày trước chạy OS củ, có 1 số game chơi xong nó ko tự giải phóng được
bộ nhớ, chơi xong, thoát ra, máy vẫn chạy ùn ùn, khởi động lại mới ngon. cái này chắc bạn
gặp nhiều oy,

ví dụ 2 : Giả sử process A của mình chạy và có 1 vùng nhớ chia sẻ với process B,C xài

Một vùng nhớ chia sẻ tồn tại độc lập với các tiến trình >> B,C thoát thì vùng nhớ này có thể
vẫn chưa được giải phóng do còn A nằm quyền nữa

sau đó A thoát đột ngột, chưa kịp báo cho OS bít, vậy OS có dám thu hồi vùng nhớ này ko ?

mình có 1 ví dụ thực tế như này :


bạn chạy BAV home, bạn đang chạy, remove nó đi, vô thư mục BKAV còn 1 file vẫn ko bị
del, bạn có muốn cũng chả del được ngay lập tức ......

ví dụ 3 : bạn thử code 1 ct cấp phát điên cuồng bộ nhớ,


bao giờ đến được gần 2gb thì thoát chương trình đột ngột
rồi cảm nhận xem
mình thử 2 lần thấy màn hình đen sì lại, mãi chả có khả năng phục hồi, phải reset lai máy
PS: theo mình nghĩ thì, hệ thống nào cũng phải có OS bạn à, dù là nhỏ xíu (1K 2K ) được
gọi là ROM như bên điện tử thì đó vẫn được coi là 1 hệ điều hành mà bạn
#include<stdio.h>
#include<conio.h>
#include<time.h>
#include<stdlib.h>

// Ham Nhap

void Nhap(int* &a,long &n)


{
printf("\n n= ");
scanf("%ld",&n);

a=new int[n*n];

for (int i=0;i<n;i++)

for (int j=0;j<n;j++)


{
//printf("Nhap a[%d][%d]: ",i,j);
//scanf("%d",&a[i*n+j]);
a[i*n+j]=rand();
}
}

// Ham In

void In(int* a, long n)


{
printf("\n");
for(int i=0;i<n;i++)
{
printf("\n");
for(int j=0;j<n;j++)
{
printf(" %3d",a[i*n+j]);
}
}

// Ham Chia Nho Ma Tran x thanh 4 phan a,b,c,d

void ChiaNho(long n, int* x, int* &a, int* &b, int* &c, int* &d)
{
long m=n/2;
int i,j;

for(i=0;i<m;i++)
for(j=0;j<m;j++)
a[i*m+j]=x[i*n+j];

for(i=0;i<m;i++)
for(j=m;j<n;j++)
b[i*m+j-m]=x[i*n+j];

for(i=m;i<n;i++)
for(j=0;j<m;j++)
c[(i-m)*m+j]=x[i*n+j];

for(i=m;i<n;i++)
for(j=m;j<n;j++)
d[(i-m)*m+j-m]=x[i*n+j];
}

// Ham Cong

void CongMaTran(long n, int* a, int*b, int* c, long &congstr)


{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
c[i*n+j]=a[i*n+j]+b[i*n+j];
congstr++;
}
}

// Ham Nhan 2 Ma Tran Voi n=2

void NhanMaTran(int* a, int* b, int* &c, long &nhanstr, long &congstr)


{
int m1, m2, m3, m4, m5, m6, m7;
m1=(a[0*2+1]-a[1*2+1])*(b[1*2+0]+b[1*2+1]);
m2=(a[0*2+0]+a[1*2+1])*(b[0*2+0]+b[1*2+1]);
m3=(a[0*2+0]-a[1*2+0])*(b[0*2+0]+b[0*2+1]);
m4=(a[0*2+0]+a[0*2+1])*b[1*2+1];
m5=a[0*2+0]*(b[0*2+1]-b[1*2+1]);
m6=a[1*2+1]*(b[1*2+0]-b[0*2+0]);
m7=(a[1*2+0]+a[1*2+1])*b[0*2+0];

c[0*2+0]=m1+m2-m4+m6;
c[0*2+1]=m4+m5;
c[1*2+0]=m6+m7;
c[1*2+1]=m2-m3+m5-m7;

congstr=congstr+18;
nhanstr=nhanstr+7;
}

// Ham To Hop 4 Ma Tran a,b,c,d thanh Ma Tran x

void ToHop(long n, int* &x, int* a, int* b, int* c, int* d)


{
long m=n/2;
int i,j;

for(i=0;i<m;i++)
for(j=0;j<m;j++)
x[i*n+j]=a[i*m+j];
for(i=0;i<m;i++)
for(j=m;j<n;j++)
x[i*n+j]=b[i*m+j-m];

for(i=m;i<n;i++)
for(j=0;j<m;j++)
x[i*n+j]=c[(i-m)*m+j];

for(i=m;i<n;i++)
for(j=m;j<n;j++)
x[i*n+j]=d[(i-m)*m+j-m];
}

// Nhan 2 Ma Tran Bang Phuong Phap Thong Thuong

void Nhan2MaTran(int* a, int* b, int* &c, long n, long &nhanbt, long &congbt)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
c[i*n+j]=0;
for(int k=0;k<n;k++)
{
c[i*n+j]=c[i*n+j]+a[i*n+k]*b[k*n+j];
}
}
congbt=n*n*(n-1);
nhanbt=n*n*n;
}

// Thuat Toan Strassen

void Strassen(int* a, int* b, int* &c, int n, long &nhanstr, long &congstr)
{
if(n==2)
NhanMaTran(a, b, c, nhanstr, congstr);
else
{
int* d1=new int[n*n];
int* d2=new int[n*n];
int* a00=new int[n*n];
int* a01=new int[n*n];
int* a10=new int[n*n];
int* a11=new int[n*n];
int* b00=new int[n*n];
int* b01=new int[n*n];
int* b10=new int[n*n];
int* b11=new int[n*n];
int* c00=new int[n*n];
int* c01=new int[n*n];
int* c10=new int[n*n];
int* c11=new int[n*n];

ChiaNho(n, a, a00, a01, a10, a11);


ChiaNho(n, b, b00, b01, b10, b11);
ChiaNho(n, c, c00, c01, c10, c11);
Strassen(a00, b00, d1, n/2, nhanstr, congstr);
Strassen(a01, b10, d2, n/2, nhanstr, congstr);
CongMaTran(n/2, d1, d2, c00, congstr);

Strassen(a00, b01, d1, n/2, nhanstr, congstr);


Strassen(a01, b11, d2, n/2, nhanstr, congstr);
CongMaTran(n/2, d1, d2, c01, congstr);

Strassen(a10, b00, d1, n/2, nhanstr, congstr);


Strassen(a11, b10, d2, n/2, nhanstr, congstr);
CongMaTran(n/2, d1, d2, c10, congstr);

Strassen(a10, b01, d1, n/2, nhanstr, congstr);


Strassen(a11, b11, d2, n/2, nhanstr, congstr);
CongMaTran(n/2, d1, d2, c11, congstr);

ToHop(n, c, c00, c01, c10, c11);


}
}

// Ham Chinh

void main()
{
clrscr();
int* a;
int* b;
int* c;
int* d;
long n,congbt=0,nhanbt=0,congstr=0,nhanstr=0;
printf("\n Ma Tran a: ");
Nhap(a,n);
printf("\n Ma Tran b: ");
Nhap(b,n);
In(a,n);
In(b,n);
Nhan2MaTran(a,b,d,n,nhanbt,congbt);
printf("\n Ket Qua Bai Toan Tinh Bang Phuong Phap thong thuong");
In(d,n);
Strassen(a,b,c,n,nhanstr,congstr);
printf("\n Ket Qua Bai Toan Tinh Bang Phuong Phap Strassen ");
In(c,n);

printf("\n Nhan theo phuong phap binh thuong can: %ld Phep Nhan va %ld Ph
ep Cong(Tru)",nhanbt,congbt);
printf("\n Nhan theo phuong phap strassen can: %ld Phap NHan va %ld Ph
ep Cong(Tru)",nhanstr,congstr);
getch();
}

cho mình hỏi với bài toán nhân Strassen như thế này, khi nhập n=2^x. n=64 thì trình C out
luôn hoặc hiện 1 dòng gì đó bắt mình phải bấm Close và C tự tắt :( hixx. mình nghĩ là lỗi do
cập phát bô nhớ nhưng không biết sửa kiểu gì, giúp mình với :(
Cho mình hỏ i là là m sao để câṕ phát bô ̉ ng. Kiểu int và kiểu Malloc, cái nà o hơn, mình cân
̣ nhớ khu ̀ khai
̉ ng khoa
báo 1 ma ̉ ng 128*128 phân từ ̉ trên C
phuonggm à, ý bạn có phải hỏi là cấp phát tĩnh dạng int a[][] và cấp phát động dùng malloc
à

2 cái ni , cái nào hơn thì khó nói quá, có nhiều khía cạnh để đánh giá lắm,
theo langman thấy thì, trên 1 cái bàn có nhiều loại dao khác nhau, tùy vào từng trường hợp
cụ thể mà ta chọn con dao nào để giết con vật nào

128*128 phần tử int thì chỉ cỡ tầm 64KB thôi bạn à, cũng ko quá lớn mà,

vấn đề bạn hỏi nếu phân tích tỉ mỉ ra thì cũng khá loằng ngoằng đấy

ví dụ nhé, ở trong C thuần túy trên môi trường 16 bit,


ở mô hình small, medium thì ko thể
nhưng ở mô hình large thì bạn có thể dùng con trỏ near để cấp phát bộ nhớ

còn trong cmd, việc cấp phát 6KB ko quá phức tạp, bạn hoàn toàn có thể cấp phát mà
Thực ra cái mình muốn hỏi là kiểu khai báo trong bài đó thôi langman à. bạn có thể test
dùm mình được không. Trong bài mình cấp phát bộ nhớ cho mảng 2 chiều theo kiểu 1
chiều, và trong bài toán phải cấp phát bộ nhớ rất nhiều, mình cũng đã cố gắng giải phóng
nhưng không được. Giả sử bây giờ mình cần nhập vào 1 mảng a kiểu con trỏ. Tức là mình
phải cấp phát bộ nhớ cho a. sau đó gán các địa chỉ của mảng = 1 giá trị nào đó. Sau đó
free(a). Sau đó nhập b, lúc này ta lại cấp phát cho b. Hỏi, liệu có xảy ra xung đột gì ở đây k.
ví dụ 1 : Mình nhớ ngày trước chạy OS củ, có 1 số game chơi xong nó ko tự giải phóng được bộ nhớ,
chơi xong, thoát ra, máy vẫn chạy ùn ùn, khởi động lại mới ngon. cái này chắc bạn gặp nhiều oy,

ví dụ 2 : Giả sử process A của mình chạy và có 1 vùng nhớ chia sẻ với process B,C xài

Một vùng nhớ chia sẻ tồn tại độc lập với các tiến trình >> B,C thoát thì vùng nhớ này có thể vẫn chưa
được giải phóng do còn A nằm quyền nữa

sau đó A thoát đột ngột, chưa kịp báo cho OS bít, vậy OS có dám thu hồi vùng nhớ này ko ?

mình có 1 ví dụ thực tế như này :


bạn chạy BAV home, bạn đang chạy, remove nó đi, vô thư mục BKAV còn 1 file vẫn ko bị del, bạn có
muốn cũng chả del được ngay lập tức ......

ví dụ 3 : bạn thử code 1 ct cấp phát điên cuồng bộ nhớ,


bao giờ đến được gần 2gb thì thoát chương trình đột ngột
rồi cảm nhận xem
mình thử 2 lần thấy màn hình đen sì lại, mãi chả có khả năng phục hồi, phải reset lai máy

PS: theo mình nghĩ thì, hệ thống nào cũng phải có OS bạn à, dù là nhỏ xíu (1K 2K ) được gọi là ROM như
bên điện tử thì đó vẫn được coi là 1 hệ điều hành mà bạn
hệ điều hành có cung cấp một số signals để cho chương trình ứng xử với nó. Vì thế chương
trình của langman có thoát đột ngột thế nào cũng không thoát ra khoải cái màn xô đấy.
Tuy sẽ có một số trường hợp khiến bạn phải tắt máy, đó là vì hệ điều hành đón nhận các
thông điệp mà chương trình gửi quá chậm, (CPU còn đang mắc dở với em hàng xóm mà).
cái này cũng liên quan đến thủ thuật cấp phát,như khi làm code từ điển,thì để C tự động
nạp vào từ đã có sẵn trong file thì nên làm sao??? nghĩa là load xong đợt này,khi bấm lên
hay xuống thì sẽ tự động load vào những từ đã xem hoặc chưa xem???có thể theo dslk đơn
hoặc tuyến tính gì cũng được
khi nào dùng new, khi nào dùng malloc?
2. khi free hoăc delete chỉ đơn thuần là thông bào vùng nhớ đó đã được giải phóng. vậy có
khi nào chẳng may khai báo 1 biến khác mà PC cấp cho nó vùng nhớ a (b) đang trỏ tới ?

new và malloc đều được, new đi chung với delete, malloc đi chung với free. Vùng nhớ đã
free tức là nó được đánh dấu là đang rảnh, và nó hoàn toàn có thể được cấp lại cho con trỏ
khác. Tái sử dụng bộ nhớ là điều hiển nhiên phải làm, ko phải hên xui gì cả. Những vùng
nhớ đã cấp phát mà chưa giải phóng thì ko thể cấp lại cho con trỏ khác được
Bản chất của free(): free() thực chất ra là việc call trực tiếp HeapFree() trong winbase.h,
đây là prototype của HeapFree():
PHP Code:
BOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem);

Khi đó nếu free(n) được gọi thì lpMem được set là n, còn dwFlags được set là 0.
PHP Code:
free(b);
delete []a;

2 câu lệnh này ko có làm thay đổi giá trị của a và b. a và b vẫn trỏ vào mảnh đất đấy. ok ? Và càng ko
can thiệp vào vùng nhớ mà a ,b trỏ đến, cái duy nhất mà nó làm là xác nhận vùng nhớ đó đã được trả
lại, đang rảnh rỗi, có thể cho thuê tiếp.

<<< điều này giải thích cho cách hiểu sai lầm của 1 số bạn mới học đối với việc cấp phát và giải phóng
Anh cho em hỏi rõ hơn về đoạn này. Khi giải phóng rồi mà a và b vẫn trỏ đến mảnh đất đó
thì nghĩa là nó vẫn có quyền kiểm soát khu vực đó, như vậy thì sao biết là khi đó đất là
available đựoc ạ. Em có test một đoạn chương trình như sau.
C Code:
Select All | Show/Hide
1. #include <iostream>
2. using namespace std;
3.
4. int main(){
5. int *p;
6.
7. p= new int[2]; // xin chính quyền cấp hai khu đất
8. p[0]=8888; // khu này trồng rau
9. p[1]=9999; // khu này nuôi lợn
10. cout << p[0] << " " << p[1] << endl; // xem tình hình ruộng rau và chuồng
lợn
11.
12. delete [] p; // trả lại đất cho chính quyền
13. cout << p[0] << " " << p[1] << endl; // xem chính quyền làm gì với ruộng
rau và chuồng lợn
14.
15. system("pause");
16. return 0;
17. }

kết quả là em không thấy ruộng rau và chuồng lợn đâu nữa

em nghĩ có hai nguyên nhân

 Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi
nội dung của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh
nói nó không can thiệp vào.
 Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước
nữa. Nhưng anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu
đất đó (p vẫn trỏ tới vùng nhớ mà trước đó nó trỏ tới)
xin khẳng định lại 1 lần nữa, e đã hiểu hoàn toàn sai lầm, FREE và DEL ko bao giờ
thay đổi giá trị của con trỏ, hãy phân việt rõ ràng giữa giá trị của con trỏ và giá trị
nó trỏ đến

free nó là void free(void *mem) vậy thì xin hỏi con trỏ mem làm sao có thể thay đổi giá trị
qua hàm này (xin hãy đọc bài bản chất con trỏ trong C để hiểu sâu hơn vấn đề này, tip :
phân biệt rõ ràng giữa giá trị của mem và giá trị của thằng mà mem trỏ tới)

check lại đoạn code sau đây


C++ Code:
Select All | Show/Hide
1. #include <iostream>
2. using namespace std;
3.
4. int main(){
5. int *p;
6.
7. p= new int[2]; // xin chính quyền cấp hai khu đất
8. p[0]=8888; // khu này trồng rau
9. p[1]=9999; // khu này nuôi lợn
10. cout << p[0] << " " << p[1] << endl; // giá trị trỏ đến
11. printf("%x\n",p); // giá trị của p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
12.
13.
14. delete [] p; // trả lại đất cho chính quyền
15. cout << p[0] << " " << p[1] << endl; // xem chính quyền làm gì với ruộng
rau và chuồng lợn
16. printf("%x\n",p); // giá trị của p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
17.
18. system("pause");
19. return 0;
20. }

điều nữa
Giải bộ nhớ hoạt động như thế nào : bản chất là trả lại quyền sử dụng
khi này :
+ sở sẽ thu lại quyền sử dụng đất của anh, thế là đủ rồi, sở ko cần phải động chạm sửa chữa lại gì vùng
đất đó. Nên khi đó dù vùng đất đó đã được giải phóng nhưng mà hoa màu của a ta trên đó thì vẫn còn,
ko có biến mất được

điều này giải thích tại sao khi mà nhiều bạn thử giải phóng bộ nhớ rồi, delete rồi, free rồi mà khi in thử ra
vẫn thấy kết quả như thế .
đơn giản thôi, a ta trả lại mảnh đất đó, nhưng chưa có ai thuê nó cả, chưa có ai sử dụng nên hôm sau ra
xem thử thì nó vẫn như hôm trước khi a ta trả lại
giả sử ngay khi em vừa trả , có thằng khác nó đến thuê luôn thì lập tức nó bỏ hoa màu của
em đi, trồng hoa màu khác thì em quay lại làm gì còn thời đại này nhanh như ăn cắp ý mà

(windows có bao nhiêu process, thread,? nên việc bị thuê ngay lập tức là quá bình thường,
em à, đặc biệt nếu là hàng nằm trên stack thì thay đổi liên tục là bt)
giá trị của con trỏ và giá trị của vùng nhớ mà con trỏ trỏ tới thì em biết. Em chỉ thắc mắc
không hiểu tại sao khi kiểm tra lại thì giá trị của vùng nhớ lại bị thay đổi (8888 và 9999)
nên em với đặt ra hai khả năng:
 Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi nội dung
của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh nói nó không
can thiệp vào.
 Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước nữa. Nhưng
anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu đất đó (p vẫn trỏ tới
vùng nhớ mà trước đó nó trỏ tới)
Và theo câu trả lời của anh nó rơi vào khả năng thứ nhất, bị thằng nào đó thuê lại ngay
sau đó:
Nguyên bản được gửi bởi langman

giả sử ngay khi em vừa trả , có thằng khác nó đến thuê luôn thì lập tức nó bỏ hoa màu của em đi, trồng
hoa màu khác thì em quay lại làm gì còn thời đại này nhanh như ăn cắp ý mà

(windows có bao nhiêu process, thread,? nên việc bị thuê ngay lập tức là quá bình thường, em à, đặc
biệt nếu là hàng nằm trên stack thì thay đổi liên tục là bt)
Thanks anh đã giải đáp đoạn này, em không biết là nó lại bị thuê luôn như thế, em hiểu rồi
khi em cài hook bắt các API trên window sẽ thấy LocalAlloc, RemoteAlloc,GlobalAlloc... được
xài rất nhiều lần trên /1s chứ ko phải (ví dụ nhỏ xem ở hình dưới , đó là chỉ trong 1 tiến
trình firefox thôi đó, chứ ko phải xét trên 5x process đang chạy)

tuy nhiên đối với các môi trường cũ, đặc biệt như trên borland C for dos thì hiện tượng free
rồi mà còn tài nguyên rất hay xảy ra, có rât rất nhiều người hiểu lầm là lỗi, rồi ... (đã có rất
nhiều câu hỏi như thế trong box thắc mắc C). đó là lý do vì sau a phải nhấn mạnh điều đó
Attached Thumbnails

Xin hỏi, khi con trỏ của cấu trúc ( hay cấu trúc tự trỏ ), có con trỏ tự trỏ *tiep thì dòng khai
báo người ta thường nói p->tiep ( tức trỏ đến phần tử tiếp theo ), mình thì cứ học thuộc
lòng , nhưng thực chất không hiểu quá trình làm việc và bản chất của nó như thế nào.
giả sử em tạo ra 1 kiêu dữ liệu có tên data. em xay dung 1 stack nhu sau :
typdef struct tagNode{
data infor;
struct tagNode *link;
}Node,*pNode;
// Vây anh cho em hỏi bản chất của Node va *pNode ở đây là gì ? Và sự khác nhau cúa nó ?
Xin hỏi, khi con trỏ của cấu trúc ( hay cấu trúc tự trỏ ), có con trỏ tự trỏ *tiep thì dòng khai báo người ta
thường nói p->tiep ( tức trỏ đến phần tử tiếp theo ), mình thì cứ học thuộc lòng , nhưng thực chất không
hiểu quá trình làm việc và bản chất của nó như thế nào.
không có cái con trỏ tự trỏ đâu bạn, thật ra lúc đó cái p->tiep mà bạn nói chính là việc cấp
phát vùng nhớ cho con trỏ next của lần nhâp trước đó, khi đó thì p->tiep mới chứa được địa
chỉ của địa chỉ cấp phát sau. Cái này trừu tượng và hơi khó hiểu.
sau lần nhập một p->next=NULL, lần 2 bắt đầu cấp phát từ value next của một hay là p-
>next=(struct name*)mallloc(sizeof(struct name)); Mình tự tìm hiểu và test thì nó là vậy,
nguyên tắc của nó là thế. Chứ không phải xong lần nhập 1 mà p->next đã có địa chỉ của 2
ngay được mà nó luôn được khởi gán p->next =NULL(phòng người dùng không nhập thêm
dữ liệu).
Bạn ơi, cho mình hỏi cái, cách xác định kích thước mảng lớn nhất mà máy tính của mình có thể cấp phát?

mem (phần cứng) là do os quản lý,


vì thế nên điều này bạn phải dùng api có support sẵn trong os, chứ trong ngôn ngữ c ko
support vấn đề này

ví dụ trên windows bạn tham khảo các hàm api của phần memory management,
lên google tìm "win32 api memory management" là thấy ngay link msdn về phần này,
bạn dùng các api này để check xem memory status còn bao nhiêu nhé.
tại sao tới phần tích hai ma trận kết quả lại sai ạ?
# include <stdio.h>
# include <conio.h>
# include <math.h>

int main ()
{ int n,m,p,q;
int i,j,k;

// ma tran a
int **a;
printf ( "Nhap dong cua matran a: ");
scanf( "%d",&n);

a = new int* [n];

printf("Nhap cot cua ma tran a: ") ;


scanf("%d",&m) ;

for (int i=0; i<n; i++)


{ a[i] = new int [m];}

//t?i dây thì có th? s? d?ng m?ng 2 chi?u r?i

for ( i=0;i < n; i++)


for ( j=0; j< m; j++)
{ printf ("\n nhap phan tu a[%d][%d]= ",i+1,j+1);
scanf ("%d",&a[i][j]); }
printf (" ma tran a:");
printf ("\n");
for ( i=0;i < n; i++)
{for ( j=0; j< m; j++)
printf (" %d",a[i][j]);
printf (" \n");}

// ma tran b
int **b;

printf ( "Nhap dong cua ma tran b: ");


scanf( "%d",& p);

b = new int* [p];

printf("Nhap cot cua ma tran b: ") ;


scanf("%d",&q) ;

for (int j=0; j<p; j++)


{ b[j] = new int [q];}

//t?i dây thì có th? s? d?ng m?ng 2 chi?u r?i

for ( j=0;j< p; j++)


for ( k=0; k< q; k++)
{ printf ("\n nhap phan tu b[%d][%d]= ",j+1,k+1);
scanf ("%d",&b[j][k]); }
printf (" ma tran b:");
printf ("\n");
for ( j=0;j < p; j++)
{for ( k=0; k< q; k++)
printf (" %d",b[j][k]);
printf (" \n");}

// nhan 2 ma tran
int **c;
c = new int* [n];
for ( i=0; i<n; i++)
{ c[i] = new int [q];}

if (m==p)

{ for (i=0;i<n;i++)
for (k=0;k<q;k++)
{ c[i][j]=0;
for (j=0;j<m;j++)

c[i][k]+= a[i][j] * b[j][k];

printf ("matran tich c:");


printf ("\n");
for (i=0;i<n;i++)
{ for (k=0;k<q;k++)

printf (" %d",c[i][k]);


printf (" \n");}} }
else return 0;

//còn dây là ph?n h?y


for (int k=0; k<n; k++)
{ delete []c[k]; }
delete []c;
//còn dây là ph?n h?y
for (int k=0; k<p; k++)
{ delete []b[k]; }
delete []b;
//còn dây là ph?n h?y
for (int j=0; j<n; j++)
{ delete []a[j]; }
delete []a;

getch();
}
Mình k thể Free được biến con trỏ cấu trúc.

Code:
#include <stdio.h>
#include <stdlib.h>
typedef int element;
typedef struct basicnode {
element inf;
basicnode *next, *prev;
} *node;
typedef struct basiclist {
node head;
node tail;
} *list;
list Initialize() {
list ds = (list)malloc(sizeof(list));
if (!ds) {
printf ("MEMORY FULL!!! No memory to access!");
return NULL;
}
ds->head = NULL;
ds->tail = NULL;
return (ds);
}
node Create_Node() {
node temp = (node)malloc(sizeof(node));
if (!temp) {
printf ("MEMORY FULL!!! No memory to access!");
return NULL;
}
temp->next = NULL;
temp->prev = NULL;
return (temp);
}
void Add_head(list ds, element x) {
node NewNode = Create_Node();
if (!NewNode) return;
if (!ds->head) ds->head = ds->tail = NewNode;
else {
NewNode->inf = x;
NewNode->next = ds->head;
ds->head->prev = NewNode;
ds->head = NewNode;
}
}
void Add_Last(list ds, element x) {
node NewNode = Create_Node();
if (!NewNode) return;
NewNode->inf = x;
if (!ds->tail) ds->head = ds->tail = NewNode;
else {
ds->tail->next = NewNode;
NewNode->prev = ds->tail;
ds->tail = NewNode;
}
}
node Add_Mid(list ds, element x, node InsNode) {
node NewNode = Create_Node();
if (!NewNode) return (NULL);
if (!InsNode->next) {
InsNode->next = NewNode;
NewNode->prev = InsNode;
ds->tail = NewNode;
}
else {
NewNode->next = InsNode->next;
InsNode->next->prev = NewNode;
InsNode->next = NewNode;
NewNode->prev = InsNode;
}
return (NewNode);
}
node Searching(list ds, element SearchData) {
node CurNode = ds->head;
while (CurNode) {
if (CurNode->inf == SearchData) return CurNode;
CurNode = CurNode->next;
}
return CurNode;
}
void Delete_Node (list ds, element DelData) {
node DelNode = Searching(ds, DelData);
if (!DelNode) return;
if (!DelNode->next && !DelNode->prev) ds->head = ds->tail = NULL;
else
if (!DelNode->prev) {
ds->head = ds->head->next;
ds->head->prev = NULL;
}
else
if (!DelNode->next) {
ds->tail = ds->tail->prev;
ds->tail->next = NULL;
}
else {
DelNode->prev->next = DelNode->next;
DelNode->next->prev = DelNode->prev;
}
free (DelNode);
}
void Delete (list ds) {
node TempNode = ds->head;
while (TempNode) {
TempNode = TempNode->next;
/*free(ds->head); */
ds->head = TempNode;
}
return;
}
list Create(list ds, int N) {
ds = Initialize();
element NewData;
for (int i = 0; i < N; i++) {
printf ("Nhap du lieu thu %d:", i+1); scanf ("%d", &NewData);
Add_Last(ds, NewData);
}
return (ds);
}
void Bubble_Sort (list ds) {
node Inode = ds->head;
element temp;
if (!Inode) return;
while (Inode != ds->tail) {
node Jnode = ds->tail;
while (Jnode != Inode) {
if (Jnode->inf < Jnode->prev->inf) {
temp = Jnode->inf;
Jnode->inf = Jnode->prev->inf;
Jnode->prev->inf = temp;
}
Jnode = Jnode->prev;
}
Inode = Inode->next;
}
}
int main() {
list ds;
node dp;
int i;
ds = Create(ds, 5);
for (dp = ds->head; dp; dp= dp->next) printf ("%d ", dp->inf);printf ("\n");
Bubble_Sort(ds);
printf ("Danh sach tang dan:\n");
for (dp = ds->head; dp; dp= dp->next) printf ("%d ", dp->inf);printf ("\n");
dp = Searching(ds, 5);
if (dp) printf ("%d\n", dp->inf); else printf ("Khong co phan tu 15 trong danh
sach.\n");
if (dp) {
Delete_Node(ds, 5);
printf ("Danh sach sau khi xoa phan tu 5: \n");
for (dp = ds->head; dp; dp= dp->next) printf ("%d ", dp->inf);
}
else printf ("Khong co phan tu 5 trong danh sach.");
Delete(ds);
for (dp = ds->head; dp; dp= dp->next) printf ("%d ", dp->inf); printf ("\n");
return 0;
}

cơ chế cấp phát cho biến toàn cục và biến địa phương với. Tôi có một bài như thế này:
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
FILE *f;
int n, a[1000001], i;//*
f=fopen("bai1.inp","r");
fscanf(f,"%d",&n);
for(i=0; i<n; i++){
fscanf(f,"%d",&a[i]);
printf("%d, ", a[i]);
}
fclose(f);
}
Dịch không bị lỗi nhưng khi chạy lại không đọc được file bai1.inp (file này có chứa 1 số
nguyên N và dòng 2 chứa N số nguyên cách nhau dấu cách). Nếu tôi đưa chỗ khai báo (*)
lên toàn cục thì lại được bác ạ.
vậy thì khi khai báo 1 biến con trỏ nó sẽ tồn tại mãi mãi hay sao, dù cho mình có set free
chăng nữa? Như thế nếu mình khai báo vô số biến con trỏ, thì làm sao hệ thống phòng
tránh được chuyện này khi bộ nhớ là có hạn?

Và bạn có suy nghĩ gì khi mình làm thế này

free(p);
p=NULL;

Khi làm thế này biến con trỏ mình đã mất hoàn toàn chưa? hay nó vẫn tồn tại ngoại trừ địa
chỉ ô nhớ của mình là NULL?
vậy thì khi khai báo 1 biến con trỏ nó sẽ tồn tại mãi mãi hay sao, dù cho mình có set free chăng nữa?
Như thế nếu mình khai báo vô số biến con trỏ, thì làm sao hệ thống phòng tránh được chuyện này khi bộ
nhớ là có hạn? Bây giờ cấp phát động là gần 100% (OOP :trollface: ), nhả ra là có người hốt
liền. Và bạn có suy nghĩ gì khi mình làm thế này

free(p);
p=NULL;

Khi làm thế này biến con trỏ mình đã mất hoàn toàn chưa? hay nó vẫn tồn tại ngoại trừ địa chỉ ô nhớ của
mình là NULL?

Thực ra để quản lí bộ nhớ heap thì có những cái list, mỗi list ứng với từng (block) size cụ
thể.
Khi bạn malloc thì 1 block đc đánh dấu cho bạn luôn chứ ko cho lẻ tẻ.
cơ chế cấp phát cho biến toàn cục và biến địa phương với. Tôi có một bài như thế này:
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
FILE *f;
int n, a[1000001], i;//*
f=fopen("bai1.inp","r");
fscanf(f,"%d",&n);
for(i=0; i<n; i++){
fscanf(f,"%d",&a[i]);
printf("%d, ", a[i]);
}
fclose(f);
}
Dịch không bị lỗi nhưng khi chạy lại không đọc được file bai1.inp (file này có chứa 1 số nguyên N và
dòng 2 chứa N số nguyên cách nhau dấu cách). Nếu tôi đưa chỗ khai báo (*) lên toàn cục thì lại được
bác ạ.
Cảm ơn bác.
Khi bác khai báo biến trong hàm main, nó sẽ đc cấp phát trên stack, mà stack chỉ đc cấp
cho ứng dụng 1 lần và bị giới hạn bởi linker, tối đa 1 MB(có thể chỉnh lại đc) => mảng của
bác 4MB sẽ báo lỗi segment fault.

Khi mảng a[] khai báo toàn cục, nó được cấp phát 1 lần ở phân vùng nằm ngoài stack và
heap (gọi là BSS) khi chạy ứng dụng, và vùng này cũng như heap, chỉ bị giới hạn theo khả
năng của máy.

khi khai báo 1 biến con trỏ nó sẽ tồn tại mãi mãi hay sao, dù cho mình có set free chăng nữa? Như thế
nếu mình khai báo vô số biến con trỏ, thì làm sao hệ thống phòng tránh được chuyện này khi bộ nhớ là
có hạn?

Và bạn có suy nghĩ gì khi mình làm thế này

free(p);
p=NULL;

Khi làm thế này biến con trỏ mình đã mất hoàn toàn chưa? hay nó vẫn tồn tại ngoại trừ địa chỉ ô nhớ của
mình là NULL?
Bạn nên nhớ biến con trỏ cũng như bao biến khác (cục bộ hay toàn cục), sẽ được giải phóng
khi ra khỏi scope, chỉ có vùng nhớ được trỏ bởi nó mới còn lại
Do đó:
free(p): vùng nhớ trỏ bởi p đc đánh dấu free, biến p ko thay đổi.
đến đây p vẫn đang trỏ tới vùng nhớ ban nãy, tuy nhiên nó ko đc kiểm soát vùng nhớ đó
dẫn tới có thể 1 tiến trình khác truy cập vào và làm thay đổi giá trị vùng nhớ. Nếu bạn sử
dụng p lúc này
sẽ ra sai kết quả.
p = NULL: đảm bảo ko sử dụng được vùng nhớ ban nãy.
Có phải lỗi khi cấp phát lượng lớn bộ nhớ động?

Trước đây em có làm một bài tập về đọc dữ liệu từ một tập tin từ điển, sau đó đưa dữ liệu
đó vào cây nhị phân tìm kiếm AVL. Khi viết xong em chạy với bộ thử nhỏ (khoảng vài trăm
từ) thấy đúng nên coi như hoàn thành. Gần đây em sử dụng lại cũng mã nguồn ấy với bộ từ
điển lớn (vài trăm nghìn từ) thì thấy sai. Sau khi các từ (từ khoảng vài nghìn trở đi) được
thêm vào và tiến hành cân bằng thì cây không còn giữ đúng thứ tự.

Em đã thử tách riêng các hàm và chạy thì đều đúng (các hàm so sánh, thêm nút, quay
trái/phải, cân bằng), khi gộp các hàm lại chạy với bộ thử vài nghìn từ vẫn đúng, nhưng
nhiều hơn nữa thì sai. Em chạy bắt lỗi được vị trí nhánh sai (từ làm cho sai), sau đó cắt bộ
thử từ khoảng 1000 từ trước nó đến 1000 từ sau nó) thì kết quả lại đúng.

Cuối cùng em nghĩ là do sử dụng cấp phát động (malloc()) vì lí do nào đó mà các địa chỉ bị
trùng (chất lên nhau) làm quá trình thêm vào bị sai thứ tự (cái này là em phỏng đoán). Vì
em đã thử tách từ điển ra làm nhiều đoạn (mỗi đoạn vài nghìn từ) bất kì thì không có đoạn
nào chạy sai. Để ý bắt lỗi nhiều lần chỉ sai ở từ thứ vài nghìn trở đi (bất kể đoạn nào). Sau
đó đã lên mạng tìm hiểu thì biết malloc() thỉnh thoảng không thể đáp ứng được yêu cầu cấp
phát bộ nhớ và trả về NULL. Sau đó em dùng toán tử new thay cho malloc() thì kết quả vẫn
vậy.

Liệu có ai đã bị những lỗi tương tự như vầy chưa và lí do có phải nằm ở vấn đề bộ nhớ?
Theo em biết cấp phát động là sử dụng bộ nhớ RAM, mà không có chuyện cấp phát vài
nghìn từ lại hết ram được (em tính thử chỉ khoảng mấy chục MB). Em cũng không thể tin
đây là lỗi logic của mã nguồn vì khi không mấy nghìn từ đầu tiên không bao giờ sai, đến
đúng khoảng vài nghìn trở đi thì sai một cách khó hiểu

Вам также может понравиться