c - C嵌套结构语法斗争
问题描述
我有以下代码,我已经多年没有使用 C 语言了,我对语法感到困惑。如何在init
函数中初始化两个顾客?我认为我需要做一些sizeof
/malloc
魔术,但实际上我对语法感到困惑。
我相信我可以像这样访问顾客数据:
t->seating[0].first_name
但是,我无法创建大量座位。是的,我的init
函数是空的,因为我已经删除了我尝试过的所有疯狂代码。
#include <stdio.h>
struct patron {
char last_name[30];
char first_name[30];
};
struct theatre_seating {
struct patron **seating;
};
void init(int elem, struct theatre_seating *t);
int main() {
struct theatre_seating theatre_seating;
int elem = 2;
init(elem, &theatre_seating);
return 1;
}
void init(int elem, struct theatre_seating *t) {
}
解决方案
这是另一种方法,应该更健壮一些。它使用 C99 的灵活数组成员。
代替固定大小的数组,将字符数据放到灵活的数组成员中。首先存储名字,然后是(字符串 NUL 的结尾,\0
和)姓氏(以及字符串 NUL 的另一端)。
为了避免必须找到名字的开始位置,我们可以存储一个指针或一个偏移量。我更喜欢偏移量,但只要你(程序员!)小心,指针也可以正常工作:
struct patron {
char *last_name; /* Points to within the first_name member */
char first_name[]; /* Flexible array member */
};
通常,您编写辅助函数来分配和初始化以及释放此类结构:
void free_patron(struct patron *p)
{
if (p) {
/* "Poisoning" the structure, to help detect possible use-after-free bugs. */
p->last_name = NULL;
p->first_name[0] = '\0';
/* Both names reside in the same dynamically allocated part. */
free(p);
}
}
struct patron *new_patron(const char *first, const char *last)
{
const size_t firstlen = (first) ? strlen(first) : 0;
const size_t lastlen = (last) ? strlen(last) : 0;
struct patron *newpatron;
/* Don't allow unnamed patrons. */
if (firstlen + lastlen < 1) {
fprintf(stderr, "new_patron(): NULL or empty name.\n");
exit(EXIT_FAILURE);
}
/* Allocate enough memory for the structure. */
newpatron = malloc(sizeof (struct patron) + firstlen + 1 + lastlen + 1);
if (!newpatron) {
fprintf(stderr, "new_patron(): Not enough memory.\n");
exit(EXIT_FAILURE);
}
/* First name goes first. */
if (firstlen > 0)
memcpy(newpatron->first_name, first, firstlen);
newpatron->first_name[firstlen] = '\0';
/* Last name follows. */
newpatron->last_name = newpatron->first_name + firstlen + 1;
if (lastlen > 0)
memcpy(newpatron->last_name, last, lastlen);
newpatron->last_name[lastlen] = '\0';
return newpatron;
}
为了管理一个赞助人数组,这次每个条目都是一个指向结构赞助人的指针。这意味着您可以选择是否使用固定大小的数组,通过定位 NULL 指针来定位空座位。
struct seating {
size_t seats;
struct patron **seat;
};
#define NO_VACANCIES (~(size_t)0)
void free_seating(struct seating *s)
{
if (s) {
free(s->seat);
s->seats = 0;
s->seat = NULL;
}
}
void init_seating(struct seating *s, const size_t n)
{
size_t i;
if (!s) {
fprintf(stderr, "init_seating(): NULL pointer to struct seating.\n");
exit(EXIT_FAILURE);
}
/* No seats wanted at all? */
if (n < 1) {
s->seats = 0;
s->seat = NULL;
return;
}
s->seat = malloc(n * sizeof s->seat[0]);
if (!s->seat) {
fprintf(stderr, "init_seating(): Not enough memory.\n");
exit(EXIT_FAILURE);
}
s->seats = n;
/* Initialize all seats as vacant. */
for (i = 0; i < n; i++)
s->seat[i] = NULL;
/* Done. */
}
/* Find a vacant/unused seating.
Returns the seat index, or NO_VACANCIES if all taken. */
size_t vacant_seating(struct seating *s)
{
size_t i;
if (!s || s->seats < 1)
return NO_VACANCIES;
for (i = 0; i < s->seats; i++)
if (!s->seat[i])
return i; /* Seat i is vacant. */
return NO_VACANCIES;
}
/* Removes a patron from a seating.
You'll usually want to call
free_patron(release_seating(&my_threatre, place));
to free the structure naming the patron as well.
This is safe to do even if the seat was vacant. */
struct patron *release_seating(struct seating *s, size_t i)
{
if (s && i < s->seats) {
struct patron *old_patron = s->seat[i];
s->seat[i] = NULL;
return old_patron;
} else
return NULL;
}
在您的程序中,使用这些很简单:
struct seating my_theatre;
size_t place;
/* Small venue with 50 seats. */
init_seating(&my_theatre, 50);
/* Find a vacant seat. */
place = vacant_seating(&my_theatre);
if (place == NO_VACANCIES) {
fprintf(stderr, "Sorry, the theatre is full.\n");
return EXIT_FAILURE;
}
/* Seat DanielN there. */
my_theatre.seat[place] = new_patron("Daniel", "N");
请注意,因为my_theatre.seat
是一个数组,my_theatre.seat + place
所以是指向数组中place
第 th 个元素的指针,与&(my_theatre.seat[place])
.
另请注意,在分配数组时,例如struct something *foo;
,您可以使用 sizeof 运算符:foo = malloc(n * sizeof foo[0]);
尝试为n
任何类型的元素分配足够的内存foo[0]
。请注意,为了帮助我们程序员记住这sizeof
是一个运算符,而不是一个函数。即使foo
是 undefined 或 NULL,sizeof foo[0]
也是有效的,因为 sizeof 运算符只检查其参数的类型以确定类型的大小。
NO_VACANCIES
宏计算为最大值(该size_t
类型可以在非二进制计算机上以二进制形式描述)。该表达式适用于所有无符号整数类型,并且size_t
是无符号(非负)整数类型。最好包含<limits.h>
和使用SIZE_MAX
(类似于该头文件定义的CHAR_MAX
、UCHAR_MAX
、INT_MAX
等),但我不确定是否所有(嗯,微软;他们喜欢以自己的方式做事)定义SIZE_MAX
.
推荐阅读
- javascript - VueJS - 由于其 MIME 类型而未加载 CSS
- macos - 为什么(macOS)grep 在递归搜索时似乎在等待标准输入?
- linux - curl 在一个命令中提交基本身份验证和网站用户身份验证
- r - 根据一个数据帧中的 NA 外观比较两个数据帧结果
- java - 计算特定歌曲在播放列表中收听的次数
- php - 具有天数和用户数组合的php数组
- python - 有没有一种简单的方法可以找到包文件中记录的总帧数?
- php - php条码扫描操作数据web表单
- java - 如何生成 JSON 响应的 POJO 类
- python - 在python中有效地解决具有非零对角的三对角系统