【C语言】学习笔记8——结构struct(1)

简介: 1. 先看个例子 #include #include #define MAXTITL 41 #define MAXAUTL 31 struct book { /*结构模板,标记是 book */ char title[MAXTITL...

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%40s%s\n", " ", "See you soon,");
    printf("%40s%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的指针也行,但是误用会导致严重的问题。

 

相关文章
|
4月前
|
网络协议 编译器 Linux
【C语言】结构体内存对齐:热门面试话题
【C语言】结构体内存对齐:热门面试话题
152 0
|
1月前
|
存储 安全 C语言
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
71 10
|
1月前
|
小程序 C语言
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
40 10
|
1月前
|
存储 编译器 C语言
【C语言程序设计——选择结构程序设计】求一元二次方程的根(头歌实践教学平台习题)【合集】
本任务要求根据求根公式计算并输出一元二次方程的两个实根,精确到小数点后两位。若方程无实根,则输出提示信息。主要内容包括: - **任务描述**:使用求根公式计算一元二次方程的实根。 - **相关知识**:掌握 `sqrt()` 函数的基本使用方法,判断方程是否有实根。 - **编程要求**:根据输入的系数,计算并输出方程的根或提示无实根。 - **测试说明**:提供两组测试数据及预期输出,确保代码正确性。 - **通关代码**:包含完整的 C 语言代码示例,实现上述功能。 通过本任务,你将学会如何处理一元二次方程的求解问题,并熟悉 `sqrt()` 函数的使用。
32 5
|
1月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】按从小到大排序三个数(头歌实践教学平台习题)【合集】
本任务要求从键盘输入三个数,并按从小到大的顺序排序后输出。主要内容包括: - **任务描述**:实现三个数的排序并输出。 - **编程要求**:根据提示在编辑器中补充代码。 - **相关知识**: - 选择结构(if、if-else、switch) - 主要语句类型(条件语句) - 比较操作与交换操作 - **测试说明**:提供两组测试数据及预期输出。 - **通关代码**:完整代码示例。 - **测试结果**:展示测试通过的结果。 通过本任务,你将掌握基本的选择结构和排序算法的应用。祝你成功!
36 4
|
1月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】求阶跃函数的值(头歌实践教学平台习题)【合集】
本任务要求输入x的值,计算并输出特定阶跃函数的结果。主要内容包括: 1. **选择结构基本概念**:介绍if、if-else、switch语句。 2. **主要语句类型**:详细解释if、if-else、switch语句的使用方法。 3. **跃迁函数中变量的取值范围**:说明如何根据条件判断变量范围。 4. **计算阶跃函数的值**:通过示例展示如何根据给定条件计算函数值。 编程要求:在右侧编辑器Begin-End之间补充代码,实现阶跃函数的计算和输出。测试说明提供了多个输入及其预期输出,确保代码正确性。最后提供通关代码和测试结果,帮助理解整个过程。
33 0
|
1月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】判断一个数是不是5和7的倍数(头歌实践教学平台习题)【合集】
本任务要求输入一个正整数,判断其是否同时是5和7的倍数,若是输出&quot;Yes&quot;,否则输出&quot;No&quot;。内容涵盖选择结构的基本概念、主要语句类型(if、if-else、switch)及条件判断逻辑,帮助理解编程中的分支执行与条件表达式。测试用例包括正数、负数及非倍数情况,确保代码逻辑严谨。通关代码示例如下: ```cpp #include &quot;stdio.h&quot; int main(){ int a; scanf(&quot;%d&quot;, &a); if (a &lt;= 0){ printf(&quo
48 0
|
1月前
|
编译器 C语言 C++
【C语言程序设计——选择结构程序设计】求输入的日期是该年的第几天(头歌实践教学平台习题)【合集】
本任务要求编写程序,根据用户输入的年月日(以空格或回车分隔),计算并输出该天是该年的第几天,需注意判断闰年。主要内容包括: 1. **任务描述**:实现从键盘输入年月日,计算该天是当年的第几天。 2. **相关知识**: - `switch` 结构的基本语法及使用注意事项。 - 判断闰年的条件:能被4整除但不能被100整除,或能被400整除的年份为闰年。 3. **编程要求**:根据提示补充代码,确保程序正确处理输入并输出结果。 4. **测试说 示例代码展示了如何使用 `switch` 语句和闰年判断逻辑来完成任务。通过此练习,掌握 `switch` 语句的应用及闰年判断方法。
32 0
|
3月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
151 16
|
4月前
|
C语言
C语言学习笔记-知识点总结上
C语言学习笔记-知识点总结上
119 1

热门文章

最新文章