在这种情况下,通过指针或通过值传递结构有什么区别?
What is the difference between passing a structure by pointer or by value in this case?
所以我正在阅读 C Primer Plus 这本书,并且遇到了关于结构和文件的编程作业。主要目标是做一个飞机座位预定程序。
我定义了以下结构,
typedef struct {
unsigned short identification_number;
unsigned short status;
char last_name[MAX_NAM_LEN];
char first_name[MAX_NAM_LEN];
} Seat;
typedef struct {
unsigned short empty_seats;
Seat seats[]; // Flexible Array Member
} Plane;
并且我有以下函数打印空座位的标识号,
/*
* Function: print_empty_seats_ID
* -------------------------
* Prints a list of empty seats identification numbers of the given plane.
*
*/
void print_empty_seats_ID (Plane* plane, int num_seats) {
// Clear the screen.
system("clear");
printf("Identification number of empty seats:");
for (int i = 0; i < num_seats; i++) {
if (plane->seats[i].status == EMPTY)
printf(" %d", plane->seats[i].identification_number);
}
puts("");
// Redirect the user to the main menu.
puts("Redirecting in 4 seconds...");
sleep(4);
}
这样从另一个函数中调用,print_empty_seats_ID (plane, num_seats);
使得plane
是指向之前在堆上定义的平面结构的指针,num_seats
是座位总数在飞机上。
此函数运行良好,但如果我将其更改为使用按值调用而不是指针,它会打印垃圾值,如下图所示。
/*
* Function: print_empty_seats_ID
* -------------------------
* Prints a list of empty seats identification numbers of the given plane.
*
*/
void print_empty_seats_ID (Plane plane, int num_seats) {
// Clear the screen.
system("clear");
printf("Identification number of empty seats:");
for (int i = 0; i < num_seats; i++) {
if (plane.seats[i].status == EMPTY)
printf(" %d", plane.seats[i].identification_number);
}
puts("");
// Redirect the user to the main menu.
puts("Redirecting in 4 seconds...");
sleep(4);
}
在这种情况下,函数以这种方式调用 print_empty_seats_ID (*plane, num_seats);
并输出以下废话 Identification number of empty seats: 64 0 0
.
我的问题是为什么第一个功能有效而第二个功能无效?
问题是您使用的是所谓的灵活数组成员,规范对此有说明:
In particular, the size of the structure is as if the flexible array
member were omitted except that it may have more trailing padding than
the omission would imply.
因此,当您按值传递时,不会复制座位本身。当你通过指针传递它时,指针指向原来有座位的平面,所以它有效..
问题是您的 Plane
有一个 灵活的数组成员 seats
,即没有指定大小的尾随数组。这些定义在 C11 6.7.2.1p18:
18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.
示例 6.7.2.1p25 阐明了这一点:
25 The assignment:
*s1 = *s2;
[where both are pointers to structures with a flexible array member] only copies the [non-flexible members]; if any of the array elements are within the first sizeof (struct s)
bytes of the structure, they might be copied or simply overwritten with indeterminate values.
C 中的函数参数如同 通过赋值传递,因此这适用于plane
按值传递。
所以我正在阅读 C Primer Plus 这本书,并且遇到了关于结构和文件的编程作业。主要目标是做一个飞机座位预定程序。
我定义了以下结构,
typedef struct {
unsigned short identification_number;
unsigned short status;
char last_name[MAX_NAM_LEN];
char first_name[MAX_NAM_LEN];
} Seat;
typedef struct {
unsigned short empty_seats;
Seat seats[]; // Flexible Array Member
} Plane;
并且我有以下函数打印空座位的标识号,
/*
* Function: print_empty_seats_ID
* -------------------------
* Prints a list of empty seats identification numbers of the given plane.
*
*/
void print_empty_seats_ID (Plane* plane, int num_seats) {
// Clear the screen.
system("clear");
printf("Identification number of empty seats:");
for (int i = 0; i < num_seats; i++) {
if (plane->seats[i].status == EMPTY)
printf(" %d", plane->seats[i].identification_number);
}
puts("");
// Redirect the user to the main menu.
puts("Redirecting in 4 seconds...");
sleep(4);
}
这样从另一个函数中调用,print_empty_seats_ID (plane, num_seats);
使得plane
是指向之前在堆上定义的平面结构的指针,num_seats
是座位总数在飞机上。
此函数运行良好,但如果我将其更改为使用按值调用而不是指针,它会打印垃圾值,如下图所示。
/*
* Function: print_empty_seats_ID
* -------------------------
* Prints a list of empty seats identification numbers of the given plane.
*
*/
void print_empty_seats_ID (Plane plane, int num_seats) {
// Clear the screen.
system("clear");
printf("Identification number of empty seats:");
for (int i = 0; i < num_seats; i++) {
if (plane.seats[i].status == EMPTY)
printf(" %d", plane.seats[i].identification_number);
}
puts("");
// Redirect the user to the main menu.
puts("Redirecting in 4 seconds...");
sleep(4);
}
在这种情况下,函数以这种方式调用 print_empty_seats_ID (*plane, num_seats);
并输出以下废话 Identification number of empty seats: 64 0 0
.
我的问题是为什么第一个功能有效而第二个功能无效?
问题是您使用的是所谓的灵活数组成员,规范对此有说明:
In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.
因此,当您按值传递时,不会复制座位本身。当你通过指针传递它时,指针指向原来有座位的平面,所以它有效..
问题是您的 Plane
有一个 灵活的数组成员 seats
,即没有指定大小的尾随数组。这些定义在 C11 6.7.2.1p18:
18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.
示例 6.7.2.1p25 阐明了这一点:
25 The assignment:
*s1 = *s2;
[where both are pointers to structures with a flexible array member] only copies the [non-flexible members]; if any of the array elements are within the first
sizeof (struct s)
bytes of the structure, they might be copied or simply overwritten with indeterminate values.
C 中的函数参数如同 通过赋值传递,因此这适用于plane
按值传递。