Trong trường hợp bạn đã viết:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *) malloc(sizeof(struct Atom) * numAtoms);
/* Immediately lose track of the pointer to that space, once was stored
in atoms, now being lost. */
atoms = (*amino).atoms;
Tôi nghĩ rằng ý định của bạn phải được điều này:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *)malloc(sizeof(struct Atom) * numAtoms);
/* Copy the input parameter into the newly-allocated memory. */
for (i = 0; i < numAtoms; i++)
atoms[i] = (*amino).atoms[i];
mà cũng có thể được viết như sau:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *)malloc(sizeof(struct Atom) * numAtoms);
/* Copy the input parameter into the newly-allocated memory. */
memcpy(atoms, (*amino).atoms, sizeof(struct Atom) * numAtoms);
Trong C không có được xây dựng trong bằng (=
) nhà điều hành để sao chép mảng như bạn có vẻ đã dự định. Những gì bạn có thay vì mất theo dõi của con trỏ để phân bổ bộ nhớ, trước đây được lưu trữ trong biến atoms
, và sau đó tiến hành để bắt đầu lặp đầu tiên của vòng lặp của bạn với atoms
trỏ vào "bản sao đầu vào" của mảng nguyên tử.
Một phần của sự cố là bạn đang gọi số
free
trên bộ nhớ, nhưng sau đó bạn tiếp tục truy cập con trỏ tới bộ nhớ được giải phóng này. Bạn không được truy cập con trỏ để giải phóng bộ nhớ.Để tránh điều này, hãy thay thế tất cả các cuộc gọi của bạn thành miễn phí với:
#ifdef free
# undef free
#endif
#define free(f) freeptr(&f)
void freeptr(void **f)
{
/* This function intentionally segfaults if passed f==NULL, to alert
the programmer that an error has been made. Do not wrap this code
with a check "if (f==NULL)", fix the problem where it is called.
To pass (*f==NULL) is a harmless 'no-op' as per the C standard
free() function.
If you must access the original, built-in free(), use (free)() to
bypass the #define macro replacement of free().
*/
(free)(*f); /* free() must accept NULL happilly; this is safe. */
*f = NULL; /* Set the pointer to NULL, it cannot be used again. */
}
Hiện tại bạn có thể chỉ cần cắt và dán mã ở trên ở đâu đó ở đầu chương trình của mình. Một địa điểm tốt là sau chỉ thị tối hậu #include
, nhưng nó phải xảy ra ở phạm vi cấp tệp và trước khi bạn sử dụng lần đầu tiên free()
trong mã.
Sau khi biên dịch lại mã của bạn, bạn sẽ tìm thấy Lỗi vi phạm và Lỗi vi phạm phân đoạn ngay lập tức sau khi bạn free(atom)
. Điều này là chính xác và mục đích của freeptr()
là dẫn mã của bạn đến một sự cố tức thì thay vì tình huống hiện tại nơi mã của bạn lạm dụng con trỏ và dẫn đến các sự cố rất khó khăn để bạn gỡ lỗi.
Để cuối cùng sửa cấp phát bộ nhớ của bạn, chắc chắn transpose các dòng:
bonds = (int *) malloc(sizeof(int));
free(bonds);
mà nên đọc:
free(bonds);
bonds = (int *) malloc(sizeof(int));
Bạn dùng tham số diff
như thể bạn đang đi qua trong một mảng ít nhất ba (3) yếu tố. Bạn nên xác minh rằng người gọi đang chuyển đủ bộ nhớ.
Khi phân bổ
bonds
, bạn phải phân bổ bộ nhớ cho không một (1) số nguyên, nhưng như nhiều số nguyên như
numBonds
:
free(bonds);
bonds = (int *) malloc(sizeof(int) * numBonds);
hay, tốt cho hầu hết các lập trình viên C:
free(bonds);
/* The calloc function performs the multiplication internally, and
nicely zero-fills the allocated memory. */
bonds = calloc(numBonds, sizeof(int));
Bạn cần sửa lại phân bổ atoms
để phân bổ một số số chính xác. Hiện tại, bạn cũng chỉ phân bổ một phần tử bộ nhớ duy nhất có kích thước sizeof(struct Atom)
. Một mảng các phần tử như vậy yêu cầu bạn nhân kích thước của một phần tử với số phần tử.
Chức năng calloc()
là tốt vì nó phân bổ mảng cho bạn và khởi tạo nội dung của tất cả các phần tử thành 0. malloc()
không có gì để khởi tạo bộ nhớ trả về và có thể dẫn đến các giá trị không thể đoán trước được lan truyền trong chương trình của bạn. Nếu bạn sử dụng malloc()
thay vì calloc()
, bạn phải cẩn thận để khởi tạo các phần tử mảng. Ngay cả khi sử dụng calloc()
, bạn phải khởi tạo mọi phần tử khác 0.
Lưu ý rằng tôi đã xóa bỏ diễn viên khỏi giá trị trả về malloc
. Nếu bạn đang viết mã C, bạn nên biên dịch nó thành mã C. Trình biên dịch sẽ không phàn nàn về việc thiếu một diễn viên từ void *
trừ khi bạn đang biên dịch trong một chế độ C++. Tệp nguồn C phải kết thúc bằng .c
đuôi tệp, không phải là .cpp
.
Như Walter Mundt chỉ ra, bạn đang vô tình gọi free()
về thành viên của một trong các thông số đầu vào của bạn, mà bạn đã gán cho con trỏ atoms
. Bạn sẽ phải tự sửa lỗi này; trên freeptr()
sẽ không làm nổi bật lỗi này cho bạn.
Những người khác đã viết rằng bạn không thể sử dụng printf()
để phát hiện đáng tin cậy nơi chương trình của bạn đang gặp sự cố. Đầu ra từ printf()
được đệm và hình dáng của nó bị trễ.
Đặt cược tốt nhất của bạn là sử dụng gdb
để xác định dòng chính xác mà chương trình của bạn gặp sự cố. Bạn sẽ không phải học bất kỳ lệnh gdb
nào để thực hiện việc này nếu bạn biên dịch mã để gỡ lỗi.
Thiếu rằng, thay thế:
printf("Program ran to point A.\n");
với:
fprintf(stderr, "Program ran to point A.\nPress return.\n");
fflush(stderr); /* Force the output */
fflush(stdin); /* Discard previously-typed keyboard input */
fgetc(stdin); /* Await new input */
fflush(stdin); /* Discard unprocessed input */
Nhìn chung, đề nghị của tôi là bạn không sử dụng ngôn ngữ C trong thời gian tới. Máy vi tính nhanh đến nỗi những ngày này tôi sẽ hỏi tại sao bạn lại coi C ở nơi đầu tiên.
Đừng làm cho tôi sai; Tôi yêu ngôn ngữ C. Nhưng C không dành cho mọi thứ. C là điều tuyệt vời cho các hệ điều hành, các hệ thống nhúng, tính toán hiệu năng cao, và đối với các trường hợp khác, nơi trở ngại chính cho sự thành công là thiếu truy cập cấp thấp đối với máy tính tính toán.
Trong trường hợp của bạn, bạn có vẻ là một nhà khoa học hoặc kỹ sư. Tôi khuyên bạn nên học và sử dụng Python. Python cho vay chính nó để dễ dàng đọc, dễ dàng xác minh các chương trình mà bạn có thể chia sẻ với các nhà hóa học hoặc kỹ sư của bạn. C không cho vay chính nó để nhanh chóng viết mã mạnh mẽ như Python. Trong trường hợp tương lai không chắc rằng Python không đủ nhanh cho các mục đích của bạn, có những giải pháp khác mà bạn sẽ sẵn sàng cho.
điều gì sẽ xảy ra nếu tôi == numBonds và không tìm thấy 'H'? –
bạn đã bị rò rỉ bộ nhớ trong mã này. –
Ban đầu tôi đã nói với nó chỉ cần thoát khỏi mã (với lệnh thoát (7);) nếu không tìm thấy 'H' vì điều đó có nghĩa là tôi đã làm gì đó sai với dữ liệu của mình ở nơi khác, nhưng tôi chưa bao giờ vấn đề, tôi loại bỏ dòng đó. – wolfPack88