Như với mọi thứ ban đầu có vẻ đáng sợ hơn so với sau này, cách tốt nhất để vượt qua nỗi sợ hãi ban đầu là đắm mình vào sự khó chịu của những điều chưa biết ! Rốt cuộc, đó là lúc chúng ta học hỏi nhiều nhất.
Thật không may, có những hạn chế. Trong khi bạn vẫn đang học cách sử dụng một chức năng, chẳng hạn, bạn không nên đảm nhận vai trò của một giáo viên. Tôi thường đọc câu trả lời từ những người dường như không biết cách sử dụng realloc
(nghĩa là câu trả lời hiện đang được chấp nhận! ) Nói cho người khác biết cách sử dụng không chính xác, đôi khi theo giả định rằng họ đã bỏ qua việc xử lý lỗi , mặc dù đây là một lỗi phổ biến trong đó cần đề cập. Đây là một câu trả lời giải thích làm thế nào để sử dụng realloc
chính xác . Hãy lưu ý rằng câu trả lời là lưu trữ giá trị trả về vào một biến khác để thực hiện kiểm tra lỗi.
Mỗi khi bạn gọi một hàm và mỗi khi bạn sử dụng một mảng, bạn đang sử dụng một con trỏ. Các chuyển đổi đang diễn ra ngầm, nếu có bất cứ điều gì thậm chí còn đáng sợ hơn, vì đó là những điều chúng ta không thấy thường gây ra nhiều vấn đề nhất. Ví dụ, rò rỉ bộ nhớ ...
Toán tử mảng là toán tử con trỏ. array[x]
thực sự là một lối tắt cho *(array + x)
, có thể được chia thành: *
và (array + x)
. Rất có thể đó *
là điều khiến bạn bối rối. Chúng tôi cũng có thể loại bỏ việc bổ sung từ các vấn đề bằng cách giả sử x
là 0
, do đó, array[0]
trở thành *array
vì thêm 0
sẽ không thay đổi giá trị ...
... và do đó chúng ta có thể thấy điều đó *array
tương đương với array[0]
. Bạn có thể sử dụng một nơi mà bạn muốn sử dụng cái khác và ngược lại. Toán tử mảng là toán tử con trỏ.
malloc
, realloc
Và bạn bè không phát minh ra khái niệm về một con trỏ mà bạn đã sử dụng tất cả cùng; họ chỉ sử dụng điều này để thực hiện một số tính năng khác, đây là một dạng thời lượng lưu trữ khác, phù hợp nhất khi bạn muốn thay đổi mạnh mẽ, năng động về kích thước .
Thật xấu hổ khi câu trả lời hiện đang được chấp nhận cũng đi ngược lại với một số lời khuyên rất có căn cứ khác về StackOverflow , đồng thời, bỏ lỡ một cơ hội để giới thiệu một tính năng ít được biết đến tỏa sáng cho chính xác usecase này: mảng linh hoạt các thành viên! Đó thực sự là một câu trả lời khá bị hỏng ... :(
Khi bạn xác định struct
, khai báo mảng của bạn ở cuối cấu trúc, không có giới hạn trên. Ví dụ:
struct int_list {
size_t size;
int value[];
};
Điều này sẽ cho phép bạn hợp nhất mảng của bạn int
thành phân bổ giống như của bạn count
và việc ràng buộc chúng như thế này có thể rất tiện lợi !
sizeof (struct int_list)
sẽ hoạt động như thể value
có kích thước bằng 0, vì vậy nó sẽ cho bạn biết kích thước của cấu trúc với một danh sách trống . Bạn vẫn cần thêm vào kích thước được truyền realloc
để xác định kích thước danh sách của bạn.
Một mẹo hữu ích khác là hãy nhớ rằng realloc(NULL, x)
nó tương đương với malloc(x)
và chúng ta có thể sử dụng điều này để đơn giản hóa mã của mình. Ví dụ:
int push_back(struct int_list **fubar, int value) {
size_t x = *fubar ? fubar[0]->size : 0
, y = x + 1;
if ((x & y) == 0) {
void *temp = realloc(*fubar, sizeof **fubar
+ (x + y) * sizeof fubar[0]->value[0]);
if (!temp) { return 1; }
*fubar = temp; // or, if you like, `fubar[0] = temp;`
}
fubar[0]->value[x] = value;
fubar[0]->size = y;
return 0;
}
struct int_list *array = NULL;
Lý do tôi chọn sử dụng struct int_list **
làm đối số thứ nhất có vẻ không rõ ràng ngay lập tức, nhưng nếu bạn nghĩ về đối số thứ hai, mọi thay đổi được thực hiện value
từ bên trong push_back
sẽ không hiển thị đối với chức năng mà chúng ta đang gọi, phải không? Điều tương tự cũng xảy ra với đối số đầu tiên và chúng ta cần có thể sửa đổi array
, không chỉ ở đây mà còn ở bất kỳ chức năng nào khác mà chúng ta chuyển nó sang ...
array
bắt đầu chỉ vào không có gì; nó là một danh sách trống Khởi tạo nó cũng giống như thêm vào nó. Ví dụ:
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
PS Hãy nhớfree(array);
khi bạn hoàn thành nó!