Đây là một chương trình thử nghiệm mà tôi đã viết cho một dự án lớn hơn mà tôi đang làm việc. Nó có liên quan đến việc viết dữ liệu struct vào đĩa với fwrite() và sau đó đọc dữ liệu đó trở lại với fread(). Một thành viên của cấu trúc được phân bổ động.C fread() đọc một cách kỳ diệu các thành phần cấu trúc được phân bổ động, như thế nào?
Thứ nhất, đây là mã của tôi
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRING_LEN 128
struct Person {
int age;
char *name;
};
int main(int argc, const char *argv[])
{
struct Person *person = calloc(1, sizeof(struct Person));
person->age = 22;
person->name = calloc(STRING_LEN, sizeof(char));
char *name = "Name that is really, really, really, really, really, really, long.";
strncpy(person->name, name, STRING_LEN);
FILE *out_file = fopen("rw.out", "w");
fwrite(person, sizeof(struct Person), 1, out_file);
fclose(out_file);
FILE *in_file = fopen("rw.out", "r");
struct Person *person_read = calloc(1, sizeof(struct Person));
fread(person_read, sizeof(struct Person), 1, in_file);
fclose(in_file);
printf("%d %s\n", person_read->age, person_read->name);
free(person->name);
free(person);
free(person_read);
return 0;
}
Và outpout
22 Name that is really, really, really, really, really, really, long.
Câu hỏi của tôi là, tại sao làm việc này? Không nên viết fwrite() chỉ viết địa chỉ mà 'tên' chứa (tức là địa chỉ bắt đầu của chuỗi)? Đó là, tôi đang đi qua trong sizeof (struct Person) để fwrite() và nó được viết chuỗi các 'tên' được trỏ đến.
Thậm chí còn khó hiểu hơn với tôi là hành vi của fread(). Một lần nữa, nếu tôi đi qua sizeof (struct Person), giá trị thực của 'name' được đọc như thế nào? Làm thế nào là bộ nhớ cho nó được phân bổ?
Sự hiểu biết trước đây của tôi về cách sử dụng fwrite() + fread() là tôi sẽ phải "viết thủ công" dữ liệu mà 'tên' trỏ tới, "theo cách thủ công" đọc dữ liệu đó rồi sao chép chuỗi đó sau khi cấp phát bộ nhớ cho cả cấu trúc và thành viên 'tên'. Nói cách khác, tôi sẽ phải tự đi qua bất kỳ con trỏ nào, ghi dữ liệu, và sau đó đọc dữ liệu đó theo thứ tự giống nhau.
EDIT: Dan và các mục khác là chính xác. Tôi đã xem xét các tập tin đầu ra với xxd:
0000000: 1600 0000 0000 0000 30a0 d900 0000 0000 ........0.......
Nếu tôi in ra địa chỉ đó 'tên' chứa trước khi viết và sau khi đọc nó là như nhau (0xd9a030), mà phù hợp với sản lượng từ xxd.
+1 Bạn có thể kiểm tra điều này bằng kích thước in ấn (struct Person) và/hoặc bằng cách xem bên trong tệp tin văn bản. fread() chỉ đọc một con trỏ (một địa chỉ bộ nhớ), nó xảy ra trùng với tên 'người-> hiện tại'. – leonbloy
Bảo đảm duy nhất là cấu trúc có cùng độ dài trong cùng một cấu hình môi trường. Nó có thể thay đổi thời điểm bạn sử dụng -m32, -m64, thay đổi thông số căn chỉnh chung, v.v. –