01/10/2018, 01:08

Tại sao không khai báo độ rộng của mảng bằng biến được

Chào mọi người e là sinh viên năm nhất ngàh điện không chuyên cntt. Học kì này e có học C có 1 thắc mắc là tại sao khôn thể đặt độ dài mảng là biến được… còn nếu dùng cấp phát động thì có thể giải quyết được… thấy hơi mơ hồ mong mọi người chỉ giáo

Đỗ Nhiên viết 03:18 ngày 01/10/2018

nếu bạn để là static là được mà bạn

Khoa NTA viết 03:10 ngày 01/10/2018

Khi khai báo mảng kiểu int array[5]; thì mảng được lưu trên vùng nhớ stack, lúc này, độ dài mảng là cố định - tức là được khai báo trước khi thực thi (nôm na là vậy). Khi khai báo int *array; array = (int *) malloc(5*sizeof(int)); thì biến con trỏ mảng được lưu trên stack, sau khi dùng hàm malloc() thì được OS cấp phát động với vùng nhớ 5*sizeof(int) bytes (lúc này mới bắt đầu chứa phần tử được). Tức là mảng đã được khai báo độ dài trong quá trình thực thi.
Việc này có liên quan đến vùng nhớ stack và heap. Có nhiều topic nói về điều này, bạn có thể dùng công cụ search trên daynhauhoc.

Pham Van Hai viết 03:15 ngày 01/10/2018

Ơ thế mới có tên gọi mảng tĩnh và mảng động chứ, quy tắc của ngôn ngữ quy định như thế rồi.

  • Mảng tĩnh kích thước mảng phải đc biết trước - cố định
  • Mang động - có thể thây đổi kích thước trong quá trình thực thi.
Tâm Ninja viết 03:14 ngày 01/10/2018

nếu bạn để là static là được mà bạn

Static là gì?

Chào mọi người e là sinh viên năm nhất ngàh điện không chuyên cntt. Học kì này e có học C có 1 thắc mắc là tại sao khôn thể đặt độ dài mảng là biến được… còn nếu dùng cấp phát động thì có thể giải quyết được… thấy hơi mơ hồ mong mọi người chỉ giáo

Cái bạn đang nói đến là mảng tĩnh. Trong Java, mảng tĩnh được cấp phát bằng cách đặt các ô nhớ liền kề nhau để hình thành mảng. Ở ô nhớ đầu tiên lưu kích thước mảng và khi duyệt mảng thì con trỏ chỉ việc duyệt tuần tự các ô liên tiếp thôi. Như vậy tiết kiệm được chi phí về bộ nhớ do không phải tốn không gian lưu trữ các ô nhớ trong mảng. Nếu mảng có 1000 phần tử và máy đang chạy hệ điều hành 64bit thì sẽ tốn 1000 x 64 / 8 = 8000Bytes ~ 8KB để lưu trữ địa chỉ các ô nhớ (Thông tin không có giá trị với chương trình). Vậy nên thay vào đó chỉ cần biết điểm đầu và kích thước là có thể duyệt mảng được rồi. Tuy nhiên mảng này bắt buộc phải tĩnh do nếu kích thước mảng thay đổi, không thể chắc chắn được ô nhớ ngay tiếp theo có bị chương trình nào ghi đè lên không gây ra hiện tượng stackoverflow. Hình dung mảng có 5 phần tử. Ô nhớ sau phần tử thứ năm được dùng để ghi dữ liệu nào đó. Khi size của mảng thay đổi bằng 6. Tưởng tượng ô nhớ thứ sáu này sẽ bị hai operator can thiệp do cả hai operator này đều nhận thức đây là vùng nhớ của mình. Như vậy vi phạm tính toàn vẹn của dữ liệu.

Có cách khác để tự tao một mảng động:
I.String pool style:

  • Khi size của mảng thay đổi, tạo một mảng mới có kích thước bằng mảng cũ.
  • Copy toàn bộ mảng cũ về mảng mới theo quy tắc tự định trước (Nếu kích thước của mảng giảm thì sẽ bị mất dữ liệu nên cần tự định nghĩa xem dữ liệu bị mất sẽ ở đầu, ở cuối hay như thế nào)
  • Xóa mảng cũ đi.
    => Tổng cộng tốn ba bước thuật toán cho mỗi lần tăng kích thước mảng và alpha bước nếu giảm kích thước mảng.

II.Dùng các kiểu dữ liệu khác thay thế như ArrayList, Stack, Queue…

viết 03:21 ngày 01/10/2018

tại vì người ta muốn cấp phát/thu hồi bộ nhớ 1 cách lẹ và đơn giản nhất. Cách đơn giản nhất chỉ cần 1 con trỏ là đủ để cấp phát/thu hồi bộ nhớ, con trỏ này là stack pointer. Vì nó cực kì đơn giản nên nó phải biết trước kích cỡ bộ nhớ cần cấp phát/thu hồi.

vd main() của bạn có int a, int b, int c, thì stack pointer sẽ lùi lại 12 bytes tương ứng với 3 số nguyên a,b,c. Khi main() gọi f(a,b) thì stack pointer lùi 8 bytes nữa, để lấy chỗ cho 2 biến tạm thời a, b (có thể lùi thêm nữa nếu trong f() có thêm biến cục bộ). Khi f() kết thúc, stack pointer tiến lên 8 bytes, trở lại main().

với mảng, nếu ko biết trước kích cỡ, thì khi cấp phát vẫn có thể cấp phát được, vd int x[n]; với n = 3 tức là lùi 4*x = 12 bytes, nhưng khi thu hồi, lỡ n bị thay đổi thành 5 thì sao? Stack pointer sẽ tiến lên 4*5 = 20 bytes? Như vậy là hỏng chương trình. Như vậy khi cấp phát, stack pointer phải cấp phát thêm biến const int N = 3 nữa, để khi thu hồi thu hồi cho đúng. Nhưng bạn tưởng tượng có 10 mảng x1 … x10 như vậy thì sao? Phải thêm 10 biến N1 … N10? Nhưng 10 biến này ở vị trí nào trên stack? Để khi thu hồi stack còn biến mà cộng 4 * $sp[12] hay 4 * $sp[100]?? Bạn có thể dồn 10 giá trị này thành 1 biến N, nhưng khi bạn cấp phát động theo yêu cầu user, thì stack pointer lại lùi thêm x y z v.v… bytes nữa, thành ra biến N này ban đầu tại vị trí $sp[100] bây giờ lại trôi đi bao nhiêu byte nữa… làm sao mà nhớ nó ở vị trí nào so với $sp? Hay là mỗi lần cấp phát lại phải copy paste N lại cho nó ở ngay $sp? … Nói chung là phức tạp, nên người ta để bạn tự xử lý với cấp phát động ở vùng heap.

明玉 viết 03:11 ngày 01/10/2018

Nếu bạn sử dụng compiler là GCC thì được!
int a = 9;
int n[a];
Nhưng Visual Studio Compiler thì không, vì nó theo đúng chuẩn của C++ là không có điều đó.

Ké thêm: nếu bạn học asm thì bạn sẽ thấy: hoàn toàn có thể tạo biến mảng static với độ dài tùy ý nhập từ bàn phím, đơn giản chỉ là thay đổi thanh ghi esp để lấy vùng nhớ trong stack thôi.

rogp10 viết 03:18 ngày 01/10/2018

^ Đúng vậy

Thực ra có thể viết kiểu int a[n] trong ISO C99 nhưng C++ thì không cho.

stackoverflow.com
Quuxplusone

Why aren't variable-length arrays part of the C++ standard?

c++, arrays, standards, variable-length-array
answered by Quuxplusone on 03:01AM - 03 Feb 14
Bài liên quan
0