第 4 章 串(串的堆分配存储实现)

news2024/11/25 14:54:32

1. 背景说明

实现基本与定长分配一致,不过将定长分配改为动态分配,解除了长度限制,实现更加灵活。

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

#define CHECK_NULL(pointer) if (!(pointer)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \
	return NULL; \
}

#define CHECK_RET(ret) if (ret != RET_OK) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \
	return ret; \
}

#define CHECK_VALUE(value, ERR_CODE) if (value) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return ERR_CODE; \
}

#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return FALSE; \
} 

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
#define ERR_FULL_QUEUE			10			/* 队列为满错 */
#define ERR_NOT_FOUND			11			/* 表项不存在 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) hString.h

/* 串的堆分配存储实现头文件 */

#ifndef HSTRING_H
#define HSTRING_H

#include "status.h"

typedef struct {
	char *ch;
	int length;
} HString;

/* 初始化(产生空串)字符串 T */
void InitString(HString *T);

/* 生成一个其值等于串常量 chars 的串 T */
Status StrAssign(const char *chars, HString *T);

/* 初始条件: 串 S 存在
   操作结果: 由串 S 复制得串 T */
Status StrCopy(const HString *S, HString *T);

/* 初始条件: 串 S 存在
   操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const HString *S);

/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
int StrCompare(const HString *S, const HString *T);

/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const HString *S);

/* 将 S 清为空串 */
Status ClearString(HString *S);

/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const HString *S1, const HString *S2, HString *T);

/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
   其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const HString *S, int pos, int len, HString *Sub);

/* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
   则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const HString *S, const HString *T, int pos);

/* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
Status StrInsert(const HString *T, int pos, HString *S);

/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, HString *S);

/* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)
   操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const HString *T, const HString *V, HString *S);

/* 堆分配类型的字符串无法销毁(结构体)*/
void DestroyString(void);

/* 输出 T 字符串 */
void StrPrint(const HString *T);

#endif // !HSTRING_H

3) hString.c

/* 串的堆分配存储实现源文件 */

#include "hString.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* 初始化(产生空串)字符串 T */
void InitString(HString *T)
{
	T->length = 0;
	T->ch = NULL;
}

/* 生成一个其值等于串常量 chars 的串 T */
Status StrAssign(const char *chars, HString *T)
{
	CHECK_VALUE(!chars, ERR_NULL_PTR);
	if (T->ch) {
		free(T->ch);
	}

	int length = (int)strlen(chars);
	if (length == 0) {
		T->ch = NULL;
		T->length = 0;
		return RET_OK;
	}

	T->ch = (char *)malloc(sizeof(char) * length);
	CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
	T->length = length;
	for (int i = 0; i < length; ++i) {
		T->ch[i] = chars[i];
	}

	return RET_OK;
}

/* 初始条件: 串 S 存在
   操作结果: 由串 S 复制得串 T */
Status StrCopy(const HString *S, HString *T)
{
	CHECK_VALUE(!S || !T, ERR_NULL_PTR);
	if (T->ch) {
		free(T->ch);
	}

	T->ch = (char *)malloc(sizeof(char) * (S->length));
	CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
	T->length = S->length;
	for (int i = 0; i < S->length; ++i) {
		T->ch[i] = S->ch[i];
	}

	return RET_OK;
}

/* 初始条件: 串 S 存在
   操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const HString *S)
{
	return ((S->length == 0) && (S->ch == NULL)) ? TRUE : FALSE;
}

/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
int StrCompare(const HString *S, const HString *T)
{
	CHECK_VALUE(!S || !T, ERR_NULL_PTR);
	for (int i = 0; i < S->length && i < T->length; ++i) {
		if (S->ch[i] != T->ch[i]) {
			return S->ch[i] - T->ch[i];
		}
	}

	return S->length - T->length;
}

/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const HString *S)
{
	return S->length;
}

/* 将 S 清为空串 */
Status ClearString(HString *S)
{
	if (S->ch) {
		free(S->ch);
		S->ch = NULL;
	}

	S->length = 0;

	return RET_OK;
}

/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const HString *S1, const HString *S2, HString *T)
{
	CHECK_VALUE(!S1 || !S2 || !T, ERR_NULL_PTR);
	if (T->ch) {
		free(T->ch);
	}

	int length = S1->length + S2->length;
	T->ch = (char *)malloc(sizeof(char) * length);
	CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
	for (int i = 0; i < S1->length; ++i) {
		T->ch[i] = S1->ch[i];
	}

	for (int i = 0; i < S2->length; ++i) {
		T->ch[S1->length + i] = S2->ch[i];
	}

	T->length = length;

	return RET_OK;
}

/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
   其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const HString *S, int pos, int len, HString *Sub)
{
	CHECK_VALUE(!S || !Sub, ERR_NULL_PTR);
	CHECK_VALUE((pos < 1) || (pos > S->length) || (len < 0) || (len > S->length - pos + 1), ERR_PARA);
	if (Sub->ch) {
		free(Sub->ch);
	}

	if (len == 0) {
		Sub->ch = NULL;
		Sub->length = 0;
	} else {
		Sub->ch = (char *)malloc(sizeof(char) * len);
		CHECK_VALUE(!(Sub->ch), ERR_MEMORY_ALLOCATE);
		for (int i = 0; i < len; ++i) {
			Sub->ch[i] = S->ch[pos - 1 + i];
		}

		Sub->length = len;
	}

	return RET_OK;
}

/* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
   则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const HString *S, const HString *T, int pos)
{
	int maxRange = StrLength(S) - StrLength(T) + 1;
	CHECK_VALUE((pos < 1) || (pos > maxRange), 0);
	HString sub;
	InitString(&sub);
	while (pos <= maxRange) {
		SubString(S, pos, StrLength(T), &sub);
		if (StrCompare(&sub, T) != 0) {
			++pos;
		} else {
			return pos;
		}
	}

	return 0;
}

/* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
Status StrInsert(const HString *T, int pos, HString *S)
{
	CHECK_VALUE(!T || !S, ERR_NULL_PTR);
	CHECK_VALUE((pos < 1) || (pos > S->length + 1), ERR_PARA);
	if (T->length == 0) {
		return RET_OK;
	}

	S->ch = (char *)realloc(S->ch, sizeof(char) * (unsigned int)(S->length + T->length));
	CHECK_VALUE(!(S->ch), ERR_MEMORY_ALLOCATE);
	for (int i = S->length - 1; i >= pos - 1; --i) {
		S->ch[i + T->length] = S->ch[i];
	}

	S->length += T->length;
	for (int i = 0; i < T->length; ++i) {
		S->ch[pos - 1 + i] = T->ch[i];
	}

	return RET_OK;
}

/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, HString *S)
{
	CHECK_VALUE(!S, ERR_NULL_PTR);
	CHECK_VALUE(pos - 1 + len > S->length, ERR_PARA);
	for (int i = pos - 1; i < S->length - len; ++i) {
		S->ch[i] = S->ch[i + len];
	}

	S->length -= len;
	S->ch = (char *)realloc(S->ch, sizeof(char) * S->length);

	return RET_OK;
}

/* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)
   操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const HString *T, const HString *V, HString *S)
{
	CHECK_VALUE(!T || !V || !S, ERR_NULL_PTR);
	int pos = 1;
	do {
		pos = Index(S, T, pos);
		if (pos) {
			StrDelete(pos, StrLength(T), S);
			StrInsert(V, pos, S);
			pos += StrLength(V);
		}
	} while (pos);

	return RET_OK;
}

/* 堆分配类型的字符串无法销毁(结构体)*/
void DestroyString(void)
{
	printf("Do not need to destroy!\n");
}

/* 输出 T 字符串 */
void StrPrint(const HString *T)
{
	for (int i = 0; i < T->length; ++i) {
		putchar(T->ch[i]);
	}
}

4) main.c

/* 入口程序源文件 */

#include "hString.h"
#include <stdio.h>

int main(void)
{
	HString t, s, r;
	InitString(&t);
	InitString(&s);
	InitString(&r);
	char *p = "Good bye!", *q = "Good luck!";
	StrAssign(p, &t);
	printf("The length of t is %d, and t is %s, and t is: ", StrLength(&t),
		(StrEmpty(&t) == TRUE) ? "empty" : "not empty");
	StrPrint(&t);
	putchar('\n');
	StrAssign(q, &s);
	printf("The length of s is %d, and s is %s, and s is: ", StrLength(&s),
		(StrEmpty(&s) == TRUE) ? "empty" : "not empty");
	StrPrint(&s);
	putchar('\n');
	Status ret = StrCompare(&s, &t);
	char ch = (ret == 0) ? '=' : ((ret < 0) ? '<' : '>');
	printf("s %c t\n", ch);
	Concat(&s, &t, &r);
	printf("The conncection of s and t is: ");
	StrPrint(&r);
	putchar('\n');
	printf("Now s is: ");
	StrAssign("oo", &s);
	StrPrint(&s);
	putchar('\n');
	printf("Now t is: ");
	StrAssign("o", &t);
	StrPrint(&t);
	putchar('\n');
	Replace(&t, &s, &r);
	printf("After use s replace t, r is: ");
	StrPrint(&r);
	putchar('\n');
	ClearString(&s);
	printf("After clear s, the length of s is %d, and s is %s, and s is: ", StrLength(&s),
		(StrEmpty(&s) == TRUE) ? "empty" : "not empty");
	StrPrint(&s);
	putchar('\n');
	SubString(&r, 6, 4, &s);
	printf("s is the string of r from 6th and length is %d\n", s.length);
	StrPrint(&s);
	putchar('\n');
	StrCopy(&r, &t);
	printf("After copy string r into string t, t is: ");
	StrPrint(&t);
	putchar('\n');
	StrInsert(&s, 6, &t);
	printf("After insert s into the 6th character of t, t is: ");
	StrPrint(&t);
	putchar('\n');
	StrDelete(1, 5, &t);
	printf("After delete 5 characters of t from 1th character, t is: ");
	StrPrint(&t);
	putchar('\n');
	printf("The position of the 1th same string with s from 1th character of t is %d\n",
		Index(&t, &s, 1));
	printf("The position of the 1th same string with s from 2th character of t is %d\n",
		Index(&t, &s, 2));
	ClearString(&s);
	ClearString(&t);
	ClearString(&r);
	DestroyString();

	return 0;
}

3. 输出示例

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[JAVAee]spring-Bean对象的执行流程与生命周期

执行流程 spring中Bean对象的执行流程大致分为四步: 启动Spring容器实例化Bean对象Bean对象注册到Spring容器中将Bean对象装配到所需的类中 ①启动Spring容器,在main方法中获取spring上下文对象并配备spring. import demo.*;import org.springframework.context.Applicati…

nacos动态配置刷新机制原理

nacos动态配置刷新机制原理 项目里面许多业务场景以及灵活配置的需求经常要用到动态配置。一般就是apollo和nacos两种选型。 nacos动态刷新导致的bug nacos一般为了实现动态配置一般会加入RefreshScope注解进行实现&#xff0c;例如下面的代码加入了RefreshScope想要实现跨域…

智能家居监控管理系统项目需求分析

目录 一、引言 1、目的 2、背景 二、项目系统概述 1、项目产品概述 2、项目功能架构 3、项目市场需求 三、项目硬件需求 1、核心开发板 2、实时检测模块 3、实时信息交互模块 4、用户安全登录模块 5、开发板可扩展模块 6、硬件之间连接设备 四、项…

网络安全进阶学习第二十课——CTF之文件操作与隐写

文章目录 一、文件类型识别1、File命令2、Winhex3、文件头残缺/错误 二、文件分离操作1、Binwalk工具2、Foremost3、dd4、Winhex 三、文件合并操作1、Linux下的文件合并2、Windowsa下的文件合并 四、文件内容隐写Winhex 五、图片文件隐写1、图片混合2、LSB(最低有效位 Least Si…

slickEdit 2022 (v27.0.2)Ubuntu安装以及破解

1去官网下载安装包 SlickEdit 也可以从我这里下载源码包 https://download.csdn.net/download/m0_38012470/88343180 2.解压压缩包并进入根目录 3.sudo ./vsinst 4按住回车不松手一直到显示需要你输入yes的时候 5.一路通过需要输入Y的时候就输入 6.一直到弹出对话框关闭…

c++11的一些新特性

c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化 在C中&#xff0c;使用花括号初始化的方式被称为列表初始化。列表初始化…

Windows C++ 环境下 eigen、osqp、osqp-eigen安装教程

本文是Windows环境下安装eigen、osqp、osqp-eigen的一个简单教程。 osqp是用于二次规划的一种求解器&#xff0c;提供包括C、Matlab、Python等在内的接口&#xff0c;但是不包含C接口。为了能在C 中使用osqp&#xff0c;可以使用osqp-eigen接口进行调用。 第一步&#xff1a;…

第二章 进程与线程 七、处理机调度(概念、层次)

目录 一、基本概念 二、三个层次 1、高级调度&#xff08;作业调度&#xff09; 2、低级调度&#xff08;进程调度/处理机调度&#xff09; 3、中级调度&#xff08;内存调度&#xff09; 三、三次调度的联系、对比 四、七状态模型 五、总结 一、基本概念 当有一堆任务…

利用群论来研究魔方

文章灵感来源于&#xff1a; 魔方与群论&#xff08;二&#xff09;&#xff08;交换子牛啤&#xff01;&#xff09; - 知乎并参考了&#xff1a;https://www.gap-system.org/Doc/Examples/rubik.html使用了这里的小程序&#xff1a;Cubie 先汇制一张&#xff0c;魔方图 ----…

MySQL数据库upsert使用

本文翻译自&#xff1a;MySQL UPSERT - javatpoint&#xff0c;并附带自己的一些理解和使用经验. MySQL UPSERT UPSERT是数据库管理系统管理数据库的基本功能之一&#xff0c;它允许数据库操作语言在表中插入一条新的数据或更新已有的数据。UPSERT是一个原子操作&#xff0c;…

手刻 Deep Learning -第壹章-PyTorch入门教学-基础概念与再探线性回归

一、前言 本章会需要 微分、线性回归与矩阵的基本观念 这次我们要来做 PyTorch 的简单教学&#xff0c;我们先从简单的计算与自动导数&#xff08; auto grad / 微分 &#xff09;开始&#xff0c;使用优化器与误差计算&#xff0c;然后使用 PyTorch 做线性回归&#xff0c;还有…

office mac苹果办公软件安装包安装教程详解

软件下载 软件&#xff1a;mac office版本&#xff1a;2021语言&#xff1a;简体中文大小&#xff1a;4.27G安装环境&#xff1a;mac硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道 百度网盘 https://pan.baidu.com/s/1WGSB-icELUxweFkI8iIbzA 首先&#…

恒源云GPU使用tensorboard || 以OpenMMLab系列为例 || 定时复制可视化日志

序言 在训练过程中使用可视化工具向来是很有效的。相比于shell中的输出&#xff0c;可视化能够更好地向我们展现在训练过程中各项指标的变化。 但是&#xff0c;由于深度学习所需要的设备性能要求较高&#xff0c;我们常常使用云GPU进行训练。但是一些云平台的可视化工具让人摸…

2023国赛B题:多波束测线问题 评阅要点完整分析

本文所有分析仅代表个人观点&#xff0c;不代表官方&#xff0c;仅供参考 制作人&#xff1a;川川徒弟 demoo CSDN&#xff1a;川川菜鸟公众号&#xff1a;川川带你学AI 全文采用非编程做法  需要工具&#xff1a; geogebra、matlab工具箱   注&#xff1a; 本文全文不考虑…

02 java ---- Android 基础app开发

目录 相对布局 显示一个美女 显示两个美女 安卓APP启动过程 安卓布局控件 常用布局之相对布局 常用布局之相对布局 padding和margin 按键美化 常用布局之线性布局 安卓按键响应的几种方式 直接设置按键的onClick绑定的函数 自定义类实现按键监听事件的接口 匿名内…

字节一面:说说var、let、const之间的区别

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;作为一名前端开发工程师&#xff0c;熟练掌握js是我们的必备技能&#xff0c;var、let、const之间的区别我们也得熟练掌握&#xff0c;博主在这给大家细细道来。 &#x1f…

Linux驱动中断与时间篇——高精度定时器hrtimer

文章目录 前言相关接口使用示例单次定时循环定时 前言 低分辨率定时器是用jiffies来定时的&#xff0c;所以会受到HZ影响&#xff0c;如果HZ为200&#xff0c;代表每秒种产生200次中断&#xff0c;那一个jiffies就需要5毫秒&#xff0c;所以精度为5毫秒。 如果精度需要达到纳秒…

如何实现一个简单的Promise/A+规范的Promise库?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Promise/A规范的Promise⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚…

uni-app:通过ECharts实现数据可视化-如何引入项目

效果 引入文件位置 代码 <template><view id"myChart"></view> </template> <script> import echarts from /static/js/echarts.js // 引入文件 export default {mounted() {// 初始化EChartsconst myChart echarts.init(document…

【JVM 内存结构丨堆】

堆 定义内存分配特点:分代结构对象分配过程Full GC /Major GC 触发条件引用方式堆参数堆内存实例 主页传送门&#xff1a;&#x1f4c0; 传送 定义 JVM&#xff08;Java Virtual Machine&#xff09;堆是Java应用程序运行时内存管理的重要组成部分之一。堆内存用于存储Java对象…