1. 先看个例子
- #include <stdio.h>
- #include <string.h>
- #define MAXTITL 41
- #define MAXAUTL 31
- struct book { /* 结构模板, 标记是 book */
- char title[MAXTITL];
- char author[MAXAUTL];
- float value;
- };
- char * s_gets(char *, int);
- int main()
- {
- struct book library; /* 把 library 声明为一个 book 类型的变量 */
- printf("请输入书的标题:\n");
- s_gets(library.title, MAXTITL);
- printf("现在输入书的作者姓名:\n");
- s_gets(library.author, MAXAUTL);
- printf("现在输入书本的价格:\n");
- scanf("%f", &library.value);
- printf("%s by %s: $%.2f\n", library.title, library.author, library.value);
- printf("%s: \"%s\"($%.2f)\n", library.author, library.title, library.value);
- printf("Done.\n");
- return 0;
- }
- char * s_gets(char *st, int n)
- {
- char * ret_val;
- char * find;
- ret_val = fgets(st, n, stdin);
- if (ret_val)
- {
- find = strchr(st, '\n'); // 查找换行符
- if (find) // 如果地址不是 NULL
- *find = '\0'; // 在此放置一个空字符
- else
- while (getchar() != '\n')
- continue; // 处理输入行中剩余的字符
- }
- return ret_val;
- }
- /*
- output:
- 请输入书的标题:
- 我与地坛
- 现在输入书的作者姓名:
- 史铁生
- 现在输入书本的价格:
- 20
- 我与地坛 by 史铁生: $20.00
- 史铁生: "我与地坛"($20.00)
- Done.
- */
结构变量: 为了提高 C 语言表示数据的能力.
比如说描述一本书, 我们会用一个 char 数组表示书名, 再用一个 char 数组表示作者, 一个 float 表示书的描述, 但是我们要描述很 5 本书的时候, 我们就得用 5 个 char 数组分别表示 5 本书名, 5 个 char 数组表示五本书的作者, 5 个 float 表示五本书的价格. 这样做很麻烦, 而且不容易维护他们之间的关系. 所以就有了结构.
结够有点像面向对象, 但是只有属性, 没有行为;
2. 建立结构声明, 并声明一个结构变量
- struct book { /* 带标记定义结构, 可重用 */
- char title[MAXTITL];
- char author[MAXAUTL];
- float value;
- };
- struct book library;
- struct { /* 不带标记定义结构, 不可重用 */
- char title[MAXTITL];
- char author[MAXAUTL];
- float value;
- } library; /* 定义结构的同时, 声明一个结构变量.*/
3. 结构的内存模型
4. 初始化结构变量
- struct book library = { /* 按顺序初始化 */
- "我与地坛",
- "史铁生",
- 20.00
- };
- struct book library = { /* 按成员名称初始化 */
- .value = 20.00,
- .author = "史铁生",
- .title = "我与地坛"
- };
- struct book library = { /* 局部初始化 */
- .value = 20.00
- };
- struct book library = { /* 瞎 j8 初始化 */
- .value = 20.00,
- .author = "史铁生",
- 5.00
- }; // 因为 value 紧跟 author, 最终 value = 5.00,
5. 访问结构的数据, 用结构成员运算符 (. )
6. 声明结构数组
struct book library[5];
7. 结构数组内存模型
8. 嵌套结构
- #include <stdio.h>
- #define LEN 20
- const char * msgs[5] =
- {
- "Thank you for the wonderful evening,",
- "You certainly prove that a",
- "is a special kind of guy. We must get together",
- "over a delicious",
- "and have a few laughs"
- };
- struct names{
- char first[LEN];
- char last[LEN];
- };
- struct guy{
- struct names handle;
- char favfood[LEN];
- char job[LEN];
- float income;
- };
- int main()
- {
- struct guy fellow = {
- {"Ewen", "Villard"},
- "grilled salmon",
- "personality coach",
- 68112.0
- };
- printf("Dear %s, \n\n", fellow.handle.first);
- printf("%s%s.\n", msgs[0], fellow.handle.first);
- printf("%s%s\n", msgs[1], fellow.job);
- printf("%s\n", msgs[2]);
- printf("%s%s%s", msgs[3], fellow.favfood, msgs[4]);
- if (fellow.income> 150000.0)
- puts("!!");
- else if (fellow.income> 75000.0)
- puts("!");
- else
- puts(".");
- printf("\n@s%s\n", "","See you soon,");
- printf("@s%s\n", "","Shalala");
- return 0;
- }
- /*
- output:
- Dear Ewen,
- Thank you for the wonderful evening, Ewen.
- You certainly prove that a personality coach
- is a special kind of guy. We must get together
- over a delicious grilled salmon and have a few laughs.
- See you soon,
- Shalala
- */
9. 指向结构的指针
- #include <stdio.h>
- #define LEN 20
- struct names{
- char first[LEN];
- char last[LEN];
- };
- struct guy{
- struct names handle;
- char favfood[LEN];
- char job[LEN];
- float income;
- };
- int main()
- {
- struct guy fellows[2] = {
- {
- {"Ewen", "Villard"},
- "grilled salmon",
- "personality coach",
- 68112.0
- },
- {
- {"Rondeny", "Swillbelly"},
- "tripe",
- "tabloid editor",
- 432400.00
- }
- };
- struct guy * him; /* 声明一个指向结构的指针 */
- printf("address #1: %p #2: %p\n", &fellows[0], &fellows[1]);
- him = &fellows[0]; /* 告诉编译器该指针指向何处 */
- printf("him->income is $%.2f: (*him).income is $%.2f\n", him->income, (*him).income);
- him++;
- printf("him->favfood is %s: (*him).handle.last is %s\n", him->favfood, (*him).handle.last);
- return 0;
- }
- /*
- output:
- address #1: 000000000062FD90 #2: 000000000062FDE4
- him->income is $68112.00: (*him).income is $68112.00
- him->favfood is tripe: (*him).handle.last is Swillbelly
- */
10. 用指针访问结构成员
- struct guy * him; // 声明一个指向结构变量的指针
- struct guy barney;
- him = &barney; // 让指针指向结构变量 barney
- him->income; // 使用 -> 运算符访问结构的成员变量, 即 barney.income
- (*him).income // 将指针解引用, 即 barney.income
11. 向函数传递结构的信息
a. 传递结构成员
b. 传递结构地址
c. 传递结构
- #include <stdio.h>
- #define FUNDLEN 50
- struct funds {
- char bank[FUNDLEN];
- double bankfund;
- char save[FUNDLEN];
- double savefund;
- };
- double sum1(double, double);
- double sum2(const struct funds *);
- double sum3(struct funds);
- int main()
- {
- struct funds stan = {
- "Garlic-Melon Bank",
- 4032.27,
- "Lucky's Savings and Loan",
- 8543.94
- };
- printf("Stan has a total if $%.3f.\n", sum1(stan.bankfund, stan.savefund)); // 向函数传递结构成员
- printf("Stan has a total if $%.3f.\n", sum2(&stan)); // 向函数传递结构的地址
- printf("Stan has a total if $%.3f.\n", sum3(stan)); // 向函数传递结构
- return 0;
- }
- double sum1(double x, double y)
- {
- return (x + y);
- }
- double sum2(const struct funds * money)
- {
- return (money->bankfund + money->savefund);
- }
- double sum3(struct funds moolah)
- {
- return (moolah.bankfund + moolah.savefund);
- }
- /*
- output:
- Stan has a total if $12576.210.
- Stan has a total if $12576.210.
- Stan has a total if $12576.210.
- --------------------------------
- */
12. 结构中的字符数组和指针
假设有一个结构声明
- #define LEN 20
- struct names{
- char first[LEN];
- char last[LEN];
- };
使用指向 char 的指针来代替字符数组
- struct pnames{
- char * first;
- char * last;
- };
这样做是可以的. 但是会带来麻烦. 考虑以下代码
- struct names veep = {"Talia", "Summers};
- struct pnames treas = {"Brad", "Fallingjaw"};
- printf("%s and %s\n", veep.first, treas.first);
代码运行都没有问题, 内存分配是怎么做的?
对于 struct names 类型的结构变量 veep , 以上字符串都存储在结构内部, 结构总共要分配 40 字节存储姓名.
然而对于 struct pnames 类型结构变量 treas, 以上字符串存储在编译器存储常量的地方, 结构本身只存储了两个地址, 在我们的系统中共占 16 字节 (64 位系统一个地址是 8 字节). struct pnames 结构不用为字符串分配任何存储空间. 他使用的是存储在别处的字符串.
考虑以下代码
- struct names accountant;
- struct pnames attorney;
- puts("Enter the last name of your accountant:");
- scanf("%s", accountant.last);
- puts("Enter the last name of your attorney:");
- scanf("%s", attorney.last); // 潜在的危险
用户的输入存储到哪里去了?
对于 accountant, 它的姓被存储在 names 的 last 中.
对于 attorney, 它的姓被存储在 attorney.last 所指向的地址中. 由于 attorney 未被初始化, 所以 attorney.last 可能指向任何一个地址, 所以这个操作可能会造成不想要的修改.
因此, 如果要用结构存储字符串, 用字符数组作为成员笔记简单. 用指向 char 的指针也行, 但是误用会导致严重的问题.
来源: https://www.cnblogs.com/yeyeck/p/9589344.html