【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的指针也行,但是误用会导致严重的问题。

 

相关文章
|
1月前
|
网络协议 编译器 Linux
【C语言】结构体内存对齐:热门面试话题
【C语言】结构体内存对齐:热门面试话题
|
2天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
33 16
|
27天前
|
C语言
C语言学习笔记-知识点总结上
C语言学习笔记-知识点总结上
62 1
|
24天前
|
编译器 C语言 Python
C语言结构
C语言结构
14 0
|
2月前
|
存储 编译器 程序员
C语言程序的基本结构
C语言程序的基本结构包括:1)预处理指令,如 `#include` 和 `#define`;2)主函数 `main()`,程序从这里开始执行;3)函数声明与定义,执行特定任务的代码块;4)变量声明与初始化,用于存储数据;5)语句和表达式,构成程序基本执行单位;6)注释,解释代码功能。示例代码展示了这些组成部分的应用。
87 10
|
2月前
|
C语言
C语言程序设计核心详解 第四章&&第五章 选择结构程序设计&&循环结构程序设计
本章节介绍了C语言中的选择结构,包括关系表达式、逻辑表达式及其运算符的优先级,并通过示例详细解释了 `if` 语句的不同形式和 `switch` 语句的使用方法。此外,还概述了循环结构,包括 `while`、`do-while` 和 `for` 循环,并解释了 `break` 和 `continue` 控制语句的功能。最后,提供了两道例题以加深理解。
|
2月前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
2月前
|
C语言
C语言程序设计核心详解 第三章:顺序结构,printf(),scanf()详解
本章介绍顺序结构的基本框架及C语言的标准输入输出。程序从`main()`开始依次执行,框架包括输入、计算和输出三部分。重点讲解了`printf()`与`scanf()`函数:`printf()`用于格式化输出,支持多种占位符;`scanf()`用于格式化输入,需注意普通字符与占位符的区别。此外还介绍了`putchar()`和`getchar()`函数,分别用于输出和接收单个字符。
|
2月前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
3月前
|
C语言
C语言------选择结构
这篇文章是C语言选择结构的入门实训,包括多个练习题及其源代码,旨在帮助读者熟练掌握条件语句和选择结构程序设计方法,并熟悉switch语句和程序调试过程。
C语言------选择结构