Xin chào, và chào mừng trở lại. Trong bài giảng này, tôi muốn cung cấp
một minh chứng
cho thách thức trước đây của chúng tôi, đó là giúp bạn hiểu cách
cấp phát bộ nhớ động bằng cách sử dụng malloc.
Chúng ta sẽ chỉ thực hiện một số thao tác đọc đơn giản từ bàn phím và
sau đó hiển thị một chuỗi, nhưng chúng ta sẽ sử dụng
nó với các con trỏ được cấp phát động,
con trỏ ký tự.
Vì vậy, hãy đưa ra các khối mã tạo một dự án mới.
Và chúng tôi sẽ đặt tên cho một ví dụ cấp phát bộ nhớ động này.
Và điều đầu tiên bạn cần làm khi sử
dụng phân bổ bộ nhớ động là bạn phải đảm bảo rằng bạn đang bao gồm lib tiêu chuẩn.
May mắn thay, khi bạn tạo một dự án trong các khối mã, nó
sẽ tự động bao gồm nó cho bạn.
Nhưng lý do chúng ta cần bao gồm lib tiêu chuẩn là vì malloc,
hàm malloc nằm trong đó. Và malloc, hãy nhớ, là chức năng
chính để cấp phát bộ nhớ. Bạn cũng có calloc.
Calloc thực sự quan trọng vì calloc sẽ thực
hiện một số phép tính tuyệt vời về số byte bạn cần
vì đó là hai tham số.
Nhưng điều tốt thực sự về calloc là nó khởi tạo tất cả dữ liệu thành
số 0 nếu chúng là số nguyên, v.v., một chức năng thực sự tuyệt vời.
Bạn có phân bổ lại. Realloc sẽ mở rộng bộ nhớ đã
được cấp phát. Vì vậy, bạn vượt qua nó trong một con trỏ.
Từ con trỏ đó, nó xác định lượng bộ nhớ được cấp cho nó
và nó sao chép mọi thứ có trong đó vào một vị trí bộ nhớ mới và
sau đó bạn cũng chỉ định thêm bao nhiêu byte mà bạn
muốn cấp phát chỉ cần thêm nó vào vị trí bộ nhớ mới, thực sự tính năng tốt đẹp.
Nhưng hãy nhớ rằng khi bạn cấp phát bộ nhớ cho các số nguyên bằng cách sử
dụng malloc, bạn phải xác định dung lượng bộ nhớ bạn muốn cấp phát byte,
nhưng bạn thường muốn sử dụng toán tử sizeof.
Vì vậy, ở đây chúng ta hãy bắt đầu.
Trong phương thức chính của tôi, tôi sẽ tạo một số nguyên và tôi
chỉ nói rằng đó sẽ là kích thước. sẽ nhập kích thước của bao nhiêu byte mà họ
muốn phân bổ trong thời gian chạy, vì vậy điều đó sẽ lưu trữ kích thước.
Điều khác tôi muốn tạo là tôi muốn tạo một con trỏ char, và
đây sẽ chỉ là văn bản. Và tôi sẽ khởi tạo nó
thành null vì nó không trỏ đến bất cứ thứ gì ngay lập tức.
Bây giờ điều đầu tiên tôi muốn làm là tôi muốn yêu cầu người dùng nhập kích thước.
Vì vậy, tôi sẽ nói
printf, tôi sẽ nói nhập giới hạn của văn bản.
Và họ sẽ nhập một số cho bao nhiêu byte muốn được phân bổ
thực sự là số ký tự.
Và sau đó tôi sẽ đọc nó bằng cách sử dụng scanf.
Scanf, tham số đầu tiên là kiểu của bộ định dạng cho kiểu dữ liệu.
Đây sẽ là phần trăm d vì tôi đang đọc một số nguyên.
Và sau đó hãy nhớ, scanf lấy một con trỏ.
Bây giờ chúng ta biết rằng các
hàm nhận con trỏ, bạn cần một địa chỉ để chuyển vào.
Vì vậy, nếu tôi sẽ chuyển kích thước, kích thước không phải là một địa chỉ trừ khi tôi sử dụng địa chỉ của toán tử.
Vì vậy, tôi sẽ ký hiệu và và tôi
sẽ nói kích thước, nghĩa là sẽ đọc theo số byte.
Khi tôi có số byte, bây giờ tôi có thể cấp phát bộ nhớ cho nó bằng cách sử dụng hàm malloc.
Và malloc sẽ trả về một con trỏ void.
Và con trỏ sẽ là địa chỉ đầu tiên cho bộ
nhớ mới được cấp phát đó. Vì vậy, bạn có thể gán quyền đó cho văn bản.
Bởi vì hãy nhớ rằng, văn bản là một con trỏ.
Chúng tôi muốn trỏ văn bản đến địa chỉ mới này đang được trả lại.
Bởi vì malloc trả về một con trỏ void nên chúng ta phải ép kiểu nó.
Loại dữ liệu mà chúng ta đang trỏ tới là một ký tự, vì vậy chúng ta muốn nói char
star, và sau đó chúng ta có thể gọi hàm malloc.
Hàm malloc nhận số byte.
Và do đó, số lượng byte, nếu bạn chỉ cần chuyển số byte vào, nó sẽ
chỉ phân bổ nhiều byte đó. Nhưng tùy thuộc vào loại dữ
liệu, loại dữ liệu có thể là hai hoặc bốn byte.
Vì vậy, nếu bạn muốn phân bổ 10 ký
tự, bạn phải đảm bảo rằng bạn
nhân 10 ký tự với kích thước của char.
Vì vậy, bây giờ chúng
ta sẽ nói n lần kích thước. Toán tử sizeof thường được sử dụng trong hàm
malloc vì nó độc lập với máy và
nó sẽ cho bạn biết bạn thực sự cần phân bổ bao nhiêu.
Bây giờ điều này phù hợp hơn khi bạn có số nguyên. Hãy nhớ rằng, số nguyên, tùy thuộc vào
hệ thống bạn đang sử dụng, kiến trúc mà bạn đang chạy,
số nguyên có thể được biểu diễn bằng bốn byte, hai byte, thường
là hai hoặc bốn byte.
Nếu bạn nói tôi muốn lưu trữ một số nguyên, vì vậy
tôi sẽ chỉ tạo bốn byte bộ nhớ, điều đó có thể không chính xác
vì nếu nó là hai byte thì sao.
Vì vậy, bạn luôn muốn
tạo bao nhiêu số nguyên hoặc bao nhiêu ký tự rồi nhân nó với kích thước
của ký tự trên hệ thống của bạn. Toán tử Sizeof sẽ cung cấp cho bạn
số byte mà một char chiếm. Vì vậy, nếu bạn muốn tạo 10 ký
tự, bạn nói kích thước gấp 10 lần ký tự. Nếu bạn muốn tạo 10 số nguyên
để lưu trữ 10 số
nguyên, bạn nói kích thước gấp 10 lần int, điều đó thực sự quan trọng.
Bây giờ với hàm calloc, bạn không cần phải làm điều đó. Calloc thực sự
nhận hai tham số. Và tham số đầu
tiên là con trỏ tôi nghĩ và sau đó
tham số thứ hai là kích thước của byte.
Vì vậy, nếu bạn nói 24 int, thì tất cả những gì bạn làm là bạn phải vượt
qua chỉ trong 24 và tự động phân bổ cho bạn.
Vì vậy, calloc là một công cụ thực sự tốt để sử dụng vì bạn không phải thực hiện phép nhân này.
Vì vậy, đối với calloc, tham số đầu tiên là kích thước.
Vì vậy, nếu bạn muốn tạo 10 int, bạn chỉ cần chuyển vào 10.
Và sau đó tham số thứ hai
là kích thước của byte. Vì vậy, bạn không cần phải thực hiện phép nhân. Nó giúp bạn tiết kiệm một chút bước.
Bây giờ chúng tôi đã cấp phát bộ
nhớ, bạn muốn đảm bảo rằng văn bản không rỗng trước khi cố gắng hủy tham chiếu văn bản.
Vì vậy, bạn luôn muốn bao bọc điều này xung quanh một văn bản không phải là văn bản và
điều đó sẽ nói rằng nó không phải là null hoặc bạn có thể thực hiện một cách
rõ ràng và nói nếu văn bản không bằng null.
Tôi luôn muốn làm điều đó vì rất rất nguy hiểm
khi cố gắng hủy tham chiếu một con trỏ.
Bất cứ điều gì có thể xảy ra. Bạn có thể ghi dữ liệu vào đó.
vào nó. Nó sẽ chỉ ghi nó ở một nơi khác trong bộ nhớ. Vì vậy, nó
sẽ làm hỏng chương trình của bạn hoặc bạn có thể bị lỗi phân đoạn và chương trình có thể bị lỗi.
Nhưng miễn là bạn thực sự phân bổ bộ nhớ đó, bây
giờ bạn có thể thực sự đọc một số dữ liệu.
Bạn có thể sử dụng git s hoặc bạn có thể sử dụng scanf tại đây.
Nhưng những gì bạn muốn làm là
bạn muốn in ra, nhập một số văn
bản và chúng tôi cũng muốn thêm các nguồn cấp dòng ở đây để chúng dễ đọc.
Và chúng tôi sẽ sử dụng scanf vì đó là những gì chúng tôi quen thuộc.
Và scanf sẽ chỉ đọc theo phần
trăm.
Thực ra, tôi sẽ chỉ cho bạn một mẹo nhỏ.
Tôi sẽ sử dụng scanf để đọc ký tự tiếp theo để nó
tạm dừng và sau đó tôi sẽ sử dụng get s để đọc trong văn bản.
Và get chỉ là một hàm khác thường bạn có thể sử dụng f get. Bạn chỉ cần đặt nó thành thiết lập
cho luồng đầu vào.
Nhưng nhận được sẽ đọc từ luồng đầu vào tiêu chuẩn, theo mặc định là bàn phím.
Và sẽ có một con trỏ. Vì vậy, tất cả những gì chúng ta phải làm là chuyển vào
văn bản vì nó đã là một con trỏ, chúng ta không cần phải nhập địa chỉ của toán tử.
Và điều thú vị với get ask là bạn có thể đọc trong nhiều chuỗi được phân tách bằng dấu cách.
Một khi chúng tôi thực sự đọc được, chúng
tôi có thể in nó ra. Vì vậy, chúng ta có thể nói văn bản đã nhập
nếu được nhập là một từ phần trăm s dấu gạch chéo ngược n
và sau đó là văn bản dấu phẩy. Văn bản là một con trỏ.
Printf nhận một con trỏ. Chúng tôi không cần phải hủy tham chiếu nó.
Bởi vì nếu bạn chỉ hiển thị văn
bản, văn bản sẽ hiển thị giá trị của con trỏ sẽ là một địa chỉ.
Chúng tôi thực sự muốn hiển thị giá trị của văn bản đang trỏ đến.
Và sau đó chúng tôi đã hoàn thành. Oh nope, chúng tôi chắc chắn là không xong. Chúng tôi muốn gọi miễn phí của chúng tôi.
Chúng tôi muốn giải phóng con trỏ của chúng tôi.
Mặc dù khi chúng ta thoát ra, bộ nhớ vẫn sẽ trống. Chúng tôi vẫn muốn đảm bảo rằng chúng tôi
giải phóng nó, và sau đó chúng tôi cũng có thể muốn lưu giữ an toàn, chúng tôi muốn đặt văn bản bằng null.
Vì vậy, hãy tiếp tục và xây dựng cái này và xem điều gì sẽ xảy ra.
Và tôi gặp sự cố vì tôi không đọc
đúng biến.
vì vậy ở đây tôi không sử dụng đúng biến. Tôi muốn sử dụng kích thước, và
có vẻ
như chúng tôi ổn.
Vì vậy, ở đây chúng ta có một điểm khác biệt ở đây là bạn không cần phải
hủy tham chiếu văn bản vì văn bản là một con trỏ ký tự.
Bạn chỉ phải hủy tham chiếu nếu trong con trỏ, v.v. Vì vậy, bạn chỉ khi bạn
sử dụng phần trăm s, nó sẽ tự động biết hủy tham chiếu
con trỏ ký tự.
Đó là một điểm khác biệt khi bạn đang sử dụng con trỏ ký
tự so với các con trỏ khác. Các con trỏ khác mà
bạn phải hủy tham chiếu để nhận giá trị bởi vì bạn không
thể thực sự sao chép chuỗi vào mảng chuỗi, v.v.
Bạn sẽ không bao giờ có thể làm văn bản bằng
dấu sao, bạn phải luôn sử dụng bản sao str nếu bạn muốn sao chép văn bản.
Bởi vì hãy nhớ từ các bài giảng, bạn không thể
thực sự gán dữ liệu cho một mảng, và con trỏ ký tự là một mảng.
Vì vậy, ở đây điều này có vẻ chính xác. Không có lý do gì để hủy tham chiếu nó.
Chúng tôi muốn xây dựng cái này, và sau đó chúng tôi muốn chạy nó.
Và bạn sẽ nhận thấy chúng tôi đặt giới hạn của văn bản.
Vì vậy, giả sử chúng tôi nhập 5, 6 cho jason và nó
in ra đầu vào là jason.
Và bạn có thể chơi với chương trình này. Nhưng một lần nữa, những điều rút
ra từ điều này bao gồm lib tiêu chuẩn khi bạn đang thực hiện malloc.
Khởi tạo con trỏ ký tự của bạn thành null. Thực hiện scanf, sử dụng
ký hiệu và vì kích thước không phải là một con trỏ.
Khi bạn đang phân tích lỗi, malloc trả về một con trỏ void, vì vậy bạn phải ép kiểu.
Bạn luôn muốn bên trong malloc của bạn. Thực hiện toán tử
sizeof cho những gì bạn muốn cấp phát. Thời gian, có bao nhiêu ký tự
thực hoặc số nguyên. Điều này áp dụng nhiều hơn cho các số nguyên và
các kiểu dữ liệu nguyên thủy về mặt kỹ thuật cho các ký tự. Bạn chỉ có thể làm kích thước, điều đó sẽ hoạt động tốt.
Bạn luôn muốn kiểm tra null, hãy đảm bảo rằng nó không null.
Khi bạn sử dụng chuỗi ký tự.
Và sau đó chúng tôi chỉ cần nhập một số văn bản, được lưu trữ trong tài liệu của chúng tôi và in nó ra.
Và cuối cùng nhưng không kém phần quan trọng, chúng tôi luôn muốn giải phóng các con trỏ của mình để chúng tôi
có thể đưa nó trở lại đống. Hi vọng điêu nay co ich. Cảm ơn bạn.