C语言入门-结构体6

结构体入门

编写程序,用struct分别表示平面上的点和平面上的矩形。
#include <stdio.h>

int main() {
struct point {int x; int y;};
struct point p1 = {1, 2};
printf(“(%d, %d)\n”, p1.x, p1.y);

struct rectangle {
    struct point p1;
    struct point p2;
};

struct rectangle square = {{1, 2}, {3, 4}};
printf("p1 = (%d, %d), p2 = (%d, %d)\n", square.p1.x, square.p1.y, square.p2.x, square.p2.y);

}

结构体和函数

在C语言中,结构体和函数可以结合使用,以便更好地组织和管理数据和操作。

结构体与函数的结合使用

传递结构体给函数

你可以将结构体作为参数传递给函数,有两种方式:传值和传引用(通过指针)。

传值
#include <stdio.h>

struct Point {
    int x;
    int y;
};

void printPoint(struct Point p) {
    printf("Point: (%d, %d)\n", p.x, p.y);
}

int main() {
    struct Point p1 = {10, 20};
    printPoint(p1);
    return 0;
}

在这种方式中,结构体的值被复制到函数参数中,函数内的修改不会影响原始结构体。

传引用(指针)
#include <stdio.h>

struct Point {
    int x;
    int y;
};

void movePoint(struct Point *p, int dx, int dy) {
    p->x += dx;
    p->y += dy;
}

int main() {
    struct Point p1 = {10, 20};
    movePoint(&p1, 5, -5);
    printf("Moved Point: (%d, %d)\n", p1.x, p1.y);
    return 0;
}

在这种方式中,传递的是结构体的指针,函数内的修改会影响原始结构体。

使用结构体和函数的完整示例

#include <stdio.h>

// 定义结构体
struct Rectangle {
    int width;
    int height;
};

// 计算面积的函数
int area(struct Rectangle r) {
    return r.width * r.height;
}

// 计算周长的函数
int perimeter(struct Rectangle *r) {
    return 2 * (r->width + r->height);
}

int main() {
    struct Rectangle rect = {10, 20};

    printf("Area: %d\n", area(rect));
    printf("Perimeter: %d\n", perimeter(&rect));

    return 0;
}

结构体数组

考虑编写一个程序来统计每个 C 关键字的出现次数。我们需要一个字符字符串数组来存储关键字的名称,并且需要一个整数数组来存储计数。一个可能的方案是使用两个并行数组,keywordkeycount,如下所示:

char *keyword[NKEYS];
int keycount[NKEYS];

但是,数组是并行的这一事实暗示了一种不同的组织方式,即结构体数组。每个关键字是一对:

char *word;
int count;

并且这是一个包含若干对的数组。结构体声明如下:

struct key {
    char *word;
    int count;
} keytab[NKEYS];

这段代码声明了一个结构体类型 key,定义了一个 keytab 结构体数组,并为这些结构体分配了存储空间。数组的每个元素都是一个结构体。这也可以写成:

struct key {
    char *word;
    int count;
};
struct key keytab[NKEYS];

由于结构体 keytab 包含了一组固定的名称,所以将其设为外部变量并在定义时初始化一次是最简单的做法。结构体的初始化类似于之前的初始化 - 定义之后紧跟着用大括号括起来的初始化列表:

struct key {
    char *word;
    int count;
} keytab[] = {
    "auto", 0,
    "break", 0,
    "case", 0,
    "char", 0,
    "const", 0,
    "continue", 0,
    "default", 0,
    /* ... */
    "unsigned", 0,
    "void", 0,
    "volatile", 0,
    "while", 0
};

实现

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#define MAXWORD 100
#define NKEYS (sizeof(keytab) / sizeof(keytab[0])) // Calculate the number of keywords

struct key {
    char *word;
    int count;
} keytab[] = {
    {"auto", 0}, {"break", 0}, {"case", 0}, {"char", 0}, {"const", 0},
    {"continue", 0}, {"default", 0}, {"unsigned", 0}, {"void", 0}, 
    {"volatile", 0}, {"while", 0}
};

int getword(char *, int);
int binsearch(char *, struct key *, int);

/* count C keywords */
int main() {
    int n;
    char word[MAXWORD];
    
    // Read words until end of file
    while (getword(word, MAXWORD) > 0) {
        if (isalpha(word[0])) {
            // If the word is a keyword, increment its count
            if ((n = binsearch(word, keytab, NKEYS)) >= 0) {
                keytab[n].count++;
            }
        }
    }
    
    // Print all keywords that were found
    for (n = 0; n < NKEYS; n++) {
        if (keytab[n].count > 0) {
            printf("%4d %s\n", keytab[n].count, keytab[n].word);
        }
    }
    return 0;
}

/* binsearch: find word in tab[0]...tab[n-1] */
int binsearch(char *word, struct key tab[], int n) {
    int cond;
    int low, high, mid;

    low = 0;
    high = n - 1;
    
    // Perform binary search
    while (low <= high) {
        mid = (low + high) / 2;
        if ((cond = strcmp(word, tab[mid].word)) < 0) {
            high = mid - 1;
        } else if (cond > 0) {
            low = mid + 1;
        } else {
            return mid;
        }
    }
    return -1;
}

int getword(char *s, int lim) {
    int i;

    for (i = 0; i < lim && (*s = getchar()) != EOF && !isblank(*s); s++, i++)
        ;
    *s = '\0';
    return i;
}

结构体指针

用指针的方式重写上面的程序。

#include <stdio.h>   // 标准输入输出头文件
#include <ctype.h>   // 字符处理函数头文件
#include <string.h>  // 字符串处理函数头文件

#define MAXWORD 100  // 定义最大单词长度为100

// 函数声明
int getword(char *, int);
struct key *binsearch(char *, struct key *, int);

// 主函数,统计C语言关键字,指针版本
int main() {
    char word[MAXWORD];  // 用于存储单词的字符数组
    struct key *p;       // 指向关键字表的指针

    // 获取单词并检查是否为字母开头
    while (getword(word, MAXWORD) != EOF) {
        if (isalpha(word[0])) {
            // 在关键字表中查找单词
            if ((p = binsearch(word, keytab, NKEYS)) != NULL) {
                p->count++;  // 如果找到则计数加1
            }
        }
    }

    // 输出关键字出现的次数
    for (p = keytab; p < keytab + NKEYS; p++) {
        if (p->count > 0) {
            printf("%4d %s\n", p->count, p->word);
        }
    }

    return 0;  // 返回0表示程序正常结束
}

/* 
 * binsearch: 在tab[0]...tab[n-1]中查找单词 
 */
struct key *binsearch(char *word, struct key *tab, int n) {
    int cond;  // 比较结果
    struct key *low = &tab[0];  // 指向表首的指针
    struct key *high = &tab[n];  // 指向表尾后一个元素的指针
    struct key *mid;  // 中间元素的指针

    // 二分查找算法
    while (low < high) {
        mid = low + (high - low) / 2;  // 计算中间位置
        if ((cond = strcmp(word, mid->word)) < 0) {
            high = mid;  // 在低半区查找
        } else if (cond > 0) {
            low = mid + 1;  // 在高半区查找
        } else {
            return mid;  // 找到单词,返回指针
        }
    }

    return NULL;  // 未找到单词,返回NULL
}

自引用结构体

假设我们想处理一个更一般的问题,即统计某些输入中所有单词的出现次数。由于单词列表事先未知,我们不能方便地对其进行排序并使用二分查找。然而,我们也不能对每个到来的单词进行线性搜索,以查看它是否已经出现过;这样程序的运行时间会太长。(更准确地说,其运行时间可能会随着输入单词数量的增加而成二次方增长。)我们如何组织数据以有效地处理任意单词列表呢?

一种解决方案是始终保持已见单词的集合按顺序排列,将每个单词按其到达的顺序放入其适当位置。但这不应通过在线性数组中移动单词来完成,这同样会耗费太多时间。相反,我们将使用一种称为二叉树的数据结构。树包含每个不同单词的一个“节点”;每个节点包含:

  • 指向单词文本的指针,
  • 出现次数的计数,
  • 指向左子节点的指针,
  • 指向右子节点的指针。

任何节点都不能有超过两个子节点;它可能只有零个或一个子节点。节点的维护方式是,使得在任何节点处,左子树仅包含按字典顺序小于该节点单词的单词,而右子树仅包含按字典顺序大于该节点单词的单词。以下是通过逐个插入遇到的单词构建的句子“now is the time for all good men to come to the aid of their party”的树结构。

具体解释

在这个例子中,二叉树的数据结构被用来保持单词的顺序并高效地统计它们的出现次数。以下是一些关键点:

  1. 插入操作

    • 每次插入一个新单词时,比较新单词与当前节点的单词。
    • 如果新单词小于当前节点的单词,则移至左子树继续比较。
    • 如果新单词大于当前节点的单词,则移至右子树继续比较。
    • 如果新单词等于当前节点的单词,则增加该节点的计数。
  2. 二叉树的优势

    • 保持动态排序:新单词可以快速插入到适当位置,而不需要移动其他元素。
    • 查找效率:二叉树的结构使得查找操作在平均情况下可以在对数时间内完成(O(log n)),大大优于线性查找的O(n)时间复杂度。

举例

对于句子“now is the time for all good men to come to the aid of their party”,我们依次插入每个单词,构建的二叉树如下:

  • 第一个单词“now”成为根节点。
  • 第二个单词“is”小于“now”,插入左子树。
  • 第三个单词“the”大于“now”,插入右子树。
  • 依此类推,构建整个树结构。

二叉树示意图

在这里插入图片描述

这个示意图展示了单词按插入顺序构建的二叉树结构,每个节点按上述规则插入。

实现

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define MAXWORD 100
struct tnode *addtree(struct tnode *, char *);
void treeprint(struct tnode *);
int getword(char *, int);
// struct tnode *talloc(void);

struct tnode {
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
};

// 函数声明
struct tnode *addtree(struct tnode *, char *);
void treeprint(struct tnode *);
int getword(char *, int);

/* 
 * 主函数,统计单词频率 
 */
int main() {
    struct tnode *root;  // 根节点指针
    char word[MAXWORD];  // 存储单词的字符数组

    root = NULL;  // 初始化根节点为空

    // 获取单词并检查是否为字母开头
    while (getword(word, MAXWORD) > 0) {
        if (isalpha(word[0])) {
            root = addtree(root, word);  // 添加单词到二叉树
        }
    }

    printf("%s\n", root->word);
    treeprint(root);  // 打印二叉树中的单词及其频率
    return 0;  // 返回0表示程序正常结束
}

int getword(char *s, int lim) {
    int i;

    for (i = 0; i < lim && (*s = getchar()) != EOF && !isblank(*s); s++, i++)
        ;
    *s = '\0';
    return i;
}

#include <stdlib.h> // 标准库,包含 malloc 和相关函数

// 函数声明
struct tnode *talloc(void); 
char *strdup(char *);    

/* 
 * addtree: 在节点 p 及其以下位置添加一个包含单词 w 的节点 
 */
struct tnode *addtree(struct tnode *p, char *w) {
    int cond;

    if (p == NULL) {  // 如果节点为空,说明新单词到达
        p = talloc();  // 创建一个新节点
        p->word = strdup(w);  // 复制单词到新节点
        p->count = 1;  // 初始化计数为 1
        p->left = p->right = NULL;  // 左右子节点设为空
    } else if ((cond = strcmp(w, p->word)) == 0) {
        p->count++;  // 如果单词已存在,计数递增
    } else if (cond < 0) {
        p->left = addtree(p->left, w);  // 如果小于当前节点单词,递归添加到左子树
    } else {
        p->right = addtree(p->right, w);  // 如果大于当前节点单词,递归添加到右子树
    }
    return p;  // 返回节点指针
}

/* 
 * talloc: 分配一个 tnode 节点的空间 
 */
struct tnode *talloc(void) {
    return (struct tnode *) malloc(sizeof(struct tnode));  // 分配内存并转换为 tnode 指针
}

/* 
 * strdup: 复制字符串 s 
 */
char *strdup(char *s) {
    char *p;
    p = (char *) malloc(strlen(s) + 1);  // 为字符串分配空间,+1 用于 '\0' 终止符
    if (p != NULL)
        strcpy(p, s);  // 复制字符串到分配的空间
    return p;  // 返回指向新字符串的指针
}

/* 
 * treeprint: 以中序遍历方式打印树 p 
 */
void treeprint(struct tnode *p) {
    if (p != NULL) {
        treeprint(p->left);  // 打印左子树
        printf("%4d %s\n", p->count, p->word);  // 打印当前节点
        treeprint(p->right); // 打印右子树
    }
}

运行

now is the time for all good men to come to the aid of their party
   1 aid
   1 all
   1 come
   1 for
   1 good
   1 is
   1 men
   1 now
   1 of
   1 party

   2 the
   1 their
   1 time
   2 to

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/771407.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电脑回收站删除的文件怎么恢复?5个恢复方法详解汇总!

电脑回收站删除的文件怎么恢复&#xff1f;在我们日常使用电脑的过程中&#xff0c;难免会遇到误删文件的情况。一旦发现自己误删文件了&#xff0c;先不要着急&#xff0c;还是有很多方法可以找回的。市面上还是有很多好用的文件恢复软件可以使用&#xff0c;具体介绍如下。 本…

使用 pyecharts 渲染成图片程序报错: echarts is not defined问题处理

背景 之前写的使用 snapshot_selenium 来保存pyeacharts渲染成的网页截图&#xff0c;可以正常运行。程序搁置了半年&#xff0c;不知道动了电脑哪里&#xff0c;再次运行程序时&#xff0c;程序开始报错&#xff1a;JavascriptException: javascript error: echarts is not d…

土壤养分化验仪:农业生态与可持续发展

随着现代农业技术的不断进步&#xff0c;土壤养分化验仪在农业生产中扮演着越来越重要的角色。这款高科技设备以其高精度、高效率的特点&#xff0c;为农业生态与可持续发展提供了强有力的支撑。 一、农田土壤监测与管理 农田是土壤养分化验仪最主要的应用场所。通过对农田土壤…

软件测试面试200问(含答案+文档)

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

三菱plc gxwork3 0X121201F 报错;三菱标签区域的保留容量不足;

如果占用过多把r文件寄存器的地址范围改小&#xff0c;一般文件寄存器的地址r0-8000足够了

CLAM用于弱监督WSI分析

计算病理学&#xff08;computational pathology&#xff09;下的深度学习方法需要手动注释大型 WSI 数据集&#xff0c;并且通常存在领域适应性和可解释性较差的问题。作者报告了一种可解释的弱监督深度学习方法&#xff0c;只需要WSI级标签。将该方法命名为聚类约束注意力多实…

uniapp自定义富文本现实组件(支持查看和收起)

废话不多说上代码 CollapseText.vue <template><view v-if"descr"><scroll-view class"collapse-text" :style"{maxHeight: computedMaxHeight}"><!-- <slot></slot> --><rich-text :nodes"descr&q…

【双出版加持!录用率高!见刊、检索更稳定!】第六届结构抗震与土木工程研究国际学术会议 (ICSSCER 2024,8月16-18)

随着社会的发展&#xff0c;城市规模的不断扩大&#xff0c;建筑形态也趋于多样化和复杂化&#xff0c;建筑结构形式逐渐由规则简单向高层、大跨甚至特殊复杂的方向发展。而房屋建筑是人们正常生活和生产活动的基本场所&#xff0c;房屋建筑结构的安全必须得到充分保障。但是&a…

揭秘品牌成功秘诀:品牌营销策略的核心要素大公开

品牌营销作为企业战略中至关重要的一环&#xff0c;其核心是建立和传播品牌的独特魅力&#xff0c;使其在消费者心目中占据重要位置。 一个成功的品牌营销策略能够提升品牌的知名度和影响力&#xff0c;带来持续的销售和忠诚客户群体。 在当今竞争激烈的市场环境中&#xff0…

初阶数据结构之二叉树

那么本篇文是初阶数据结构这个系列的最后一篇文章&#xff0c;那么闲话少叙&#xff0c;我们直接进入正题 在讲二叉树的一些之前知识点之前&#xff0c;我先给大家送个小礼物哈 手搓二叉树 typedef int BTDataType ; typedef struct BinaryTreeNode { BTDataType _data …

Mybatis-Plus eq ne gt lt ge le分别代表含义 条件构造器

一、条件构造器函数列表 函数名说明说明/例子allEq入参都满足条件例&#xff1a;allEq({"id": 1, "name": "张三", "age": null})--->id 1 and name 张三 and age is nulleq等于例&#xff1a;eq("name", "张三…

dc-3靶机渗透

环境准备 dc-3靶机下载链接&#xff1a; https://download.vulnhub.com/dc/DC-3-2.zip 启动靶机遇到的问题解决文章在下面 http://t.csdnimg.cn/zLQAI kali最新版 dc-3靶机 两台机器都在vmware上运行 网络设置NAT模式 渗透过程 信息收集 首先使用ifconfig获取kali的IP地址 可…

day04-组织架构

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.组织架构-树组件应用树形组件-用层级结构展示信息&#xff0c;可展开或折叠。 2.组织架构-树组件自定义结构3.组织架构-获取组织架构数据4.组织架构-递归转化树形…

CSS filter(滤镜)属性,并实现页面置灰效果

目录 一、filter&#xff08;滤镜&#xff09;属性 二、准备工作 三、常用的filter属性值 1、blur(px) 2、brightness(%) 3、contrast(%) 4、grayscale(%) 5、opacity(%) 6、saturate(%) 7、sepia(%) 8、invert(%) 9、hue-rotate(deg) 10、drop-shadow(h-shadow v…

【Godot4.2】用PlantUML和语雀画UML类图

概述 UML&#xff1a;统一建模语言(Unified Modeling Language,UML)是用来设计软件的可视化建模语言。PlantUML&#xff1a;是一个开源工具&#xff0c;它允许我们用文本形式来描绘和创建UML图。在VSCode中可以安装扩展来绘制&#xff0c;而在语雀的MarkDown编辑器中&#xff…

震惊!运气竟能如此放大!运气的惊人作用,你了解吗?

芒格&#xff1a;得到你想要的东西&#xff0c;最保险的办法&#xff0c;就是让自己配得上你想要的那个东西。今天仔细想了想这句话&#xff0c;他其实说的是无数成功人士的心声 —— “我配得上&#xff01;” 美剧《绝命毒师》有个导演叫文斯吉里根&#xff08;Vince Gilliga…

如何看待制造业数字化转型?从不同维度来聊一聊

作为一名TOB行业9年经验的老兵&#xff0c;近期我们团队拜访了不少制造企业&#xff0c;其以中小型企业居多&#xff0c;在与企业负责人交流数字化转型话题时&#xff0c;感触最多的还是管理者对“数字化转型”的认知。在数字化转型方面从国家层面到地方政府进行大量的宣传与政…

数据结构 1.1 数据结构的基本概念

本章总览&#xff1a; 一.什么是数据 1.数据 数据是信息的载体&#xff0c;是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程 序识别和处理的符号的集合。数据是计算机程序加工的原料。 早期计算机只能处理纯数值的问题&#xff0c;如世界第一题计算机ENI…

【京存】AI人工智能时代的分布式存储

如今&#xff0c;AI人工智能的浪潮席卷全球&#xff0c;数据以前所未有的速度增长与积累。如何高效存储、管理和利用海量数据&#xff0c;成为推动AI发展的关键。 今日&#xff0c;我们将为您深度剖析AI人工智能分布式存储方案&#xff0c;伴随AI技术在图像识别、自然语言处理…

金融(基金)行业信创国产化特点及统一身份认证解决方案

金融业在政策支持及自主驱动下&#xff0c;金融信创取得快速发展。从2020年开始&#xff0c;三期试点已扩容至5000余家&#xff0c;进入全面推广阶段。而基金行业信创建设与银行、证券、保险这些试点行业相比&#xff0c;进展较为缓慢。 基金行业信创当前面临的问题 与多家基…