串结构之堆分配存储详解(C语言版)


一、定义

        串结构的堆分配存储与定长顺序存储方式一样,也是以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配而得。

二、结构

        在C语言中,存在一个称之为“堆”的自由存储区,并由C语言的动态分配函数malloc()和free()来管理。利用函数malloc()为每个新产生的串分配一块实际串长所需的存储空间,若分配成功,则返回一个指向起始地址的指针,作为串的基址,同时,为了以后处理方便,约定串长也作为存储结构的一部分。

//串结构
typedef struct HString
{
	char *ch;   //指向字符串所在空间首地址
	int   length; //记录字符串长度
}HString;

三、常用操作

1. 初始化

//初始化字符串结构
void InitString(HString *S)
{
	S->ch = NULL;
	S->length = 0;
}

2. 串打印

//打印字符串
void PrintString(HString *S)
{
	//将字符逐一打印
	for(int i=0; i<S->length; ++i)
	{
		printf("%c",S->ch[i]);
	}
	printf("\n");
}

3. 赋值

//赋值:将字符串str赋给字符结构S
void StrAssign(HString *S, char *str)
{
	int len = strlen(str); //求字符串str的长度

	//这一步的目的是防止内存泄漏
	if(S->ch != NULL) //判断这个结构之前是否有为其分配空间
		free(S->ch);//如果有,则释放

	S->ch = (char*)malloc(sizeof(char)*len);//申请符合str大小的空间
	assert(S->ch != NULL);
	for(int i=0; i<len; ++i)//分配成功后,将str中的字符逐个赋给S
	{
		S->ch[i] = str[i];
	}
	S->length = len;//记录此时S的长度
}

4. 拷贝

//字符串拷贝:将T拷贝到S
void StrCopy(HString *S, HString *T)
{
	int len = StrLength(T);//计算T的长度

	//这一步的目的是防止内存泄漏
	if(S->ch != NULL) //判断这个结构之前是否已经分配了空间
		free(S->ch); //如果有,则释放

	//为S申请符合T大小的空间
	S->ch = (char *)malloc(sizeof(char) * len);
	assert(S->ch != NULL);
	//分配成功后,将T中的字符逐个拷贝到S
	for(int i=0; i<len; ++i)
	{
		S->ch[i] = T->ch[i];
	}
	S->length = len;
}

5. 判断空

//判断字符串是否为空
bool StrEmpty(HString *S)
{
	return S->length==0;
}

6. 比较

//字符串比较函数
int  StrCompare(HString *S, HString *T)
{
	//如果两个字符串都为空
	if(S->length==0 && T->length==0)
		return 0;
	int result = 0; //比较相同,返回0
	
	int i=0;
	int j=0;
	//在两个字符串都还有字符可以进行比较时,不断的比较
	while(i<S->length && j<T->length)
	{
		//发现S比T大,返回1
		if(S->ch[i] > T->ch[j])
			return 1;
		//发现T比S大返回-1
		else if(S->ch[i] < T->ch[j])
			return -1;
		else //相同继续往后找
		{
			i++;
			j++;
		}
	}
	//S还有剩余(S的前面部分与T完全相同)
	if(i<S->length)
		result = 1;
	//T还有剩余(T的前面部分与S完全相同)
	if(j<T->length)
		result = -1;
	//两个字符串完全相同
	return result;
}

7. 求长度

//求字符串长度
int  StrLength(HString *S)
{
	return S->length;
}

8. 拼接

//字符串拼接:将s1和s2拼接,存放入T
void StrConcat(HString *T, HString *s1, HString *s2)
{
	//这一步的目的是防止内存泄漏
	if(T->ch != NULL) //判断这个结构之前是否已经分配了空间
		free(T->ch); //如果有,则释放

	//计算s1和s2的长度
	int len1 = StrLength(s1);
	int len2 = StrLength(s2);
	//为T分配足够存入S1和S2大小的空间
	T->ch = (char *)malloc(sizeof(char)*(len1+len2));
	assert(T->ch != NULL);
	//分配成功
	for(int i=0; i<len1; ++i) //放入S1
	{
		T->ch[i] = s1->ch[i];
	}
	for(int j=0; j<len2; ++j) //拼接上S2
	{
		T->ch[i+j] = s2->ch[j];
	}
	//修改拼接后T的长度
	T->length = len1 + len2;
}

9. 取子串

//子串截取:从S的pos取len长度的字符串放入sub中
void SubString(HString *S, HString *sub,int pos, int len)
{
	//如果输入的条件,是否不符合截取要求
	if(pos<0 ||pos>S->length ||len<0 ||len>S->length-pos)
		return; //不符合,退出
	//符合
	//这一步的目的是防止内存泄漏
	if(sub->ch != NULL)  //判断这个结构之前是否已经分配了空间
		free(sub->ch);  //如果有,则释放

	//为Sub分配足够存入截取子串的存储空间
	sub->ch = (char*)malloc(sizeof(char) * len);
	assert(sub->ch != NULL);
	//分配成功
	int j = pos;//设置开始截取的位置
	for(int i=0; i<len; ++i)//从S中的pos位置开始逐一取出len个字符,放入sub
	{
		sub->ch[i] = S->ch[j+i];
	}
	
	sub->length = len;//更改此时sub的长度
}

10. 插入

//插入字符串:将T插入到S的pos位置
void StrInsert(HString *S, int pos, HString *T)
{
	//判断是否需要进行插入
	if(T->length == 0)
		return;
	//判断是否能够插入
	if(pos<0 || pos>S->length)
		return;
	
	//为S扩充存储空间,存储空间扩充为足够容纳S+T内的字符
	char *ch = (char*)realloc(S->ch,sizeof(char)*(S->length+T->length));
	assert(ch != NULL);
	S->ch = ch;
	
	//将S中最后一个字符到pos位置中的这段字符串向后移动T的长度,供字符串T插入
	for(int i=S->length-1; i>=pos; --i)//移动注意是由后往前,这样才不会将数据覆盖
	{
		S->ch[i+T->length] = S->ch[i];
	}
	
	int j = pos; //设置开始插入位置
	for(i=0; i<T->length; ++i)//将T中的字符逐个放入
	{
		S->ch[j+i] = T->ch[i];
	}
	//更新插入T后的字符串S长度
	S->length += T->length;
}

11. 删除

//删除字符串:删除字符串S中从pos位置开始的len长度子串
void StrDelete(HString *S, int pos, int len)
{
	//判断是否不满足删除条件
	if(pos<0 ||pos>S->length)
		return; 
	if(len <= 0 || len >S->length)
		return;
	
	int j = pos; //设置开始删除的位置
	//将pos+len处及其之后的字符全部往前移动len长度,通过覆盖实现删除
	for(int i=j+len; i<S->length; ++i)
	{
		S->ch[i-len] = S->ch[i];
	}
	//修改删除后S的长度
	S->length -= len;
}

12. 清空

//清空
void StrClear(HString *S)
{
	S->length = 0;//长度设置为0
	//判断是否开辟了空间
	if(S->ch != NULL)
		free(S->ch);//开辟了,就是否
	S->ch = NULL;//指向空
}

13. 模式匹配

//模式匹配
int StrIndex(HString *S, HString *T, int pos)
{
	int i = pos;//主串开始匹配的初始位置
	int j = 0;//模式串开始匹配的初始位置
	//如果还没匹配到模式串且主串中还有字符,则继续匹配
	while(i != S->length && j !=T->length)
	{
		//如果有字符匹配则,将主串和模式串分别下移一个字符
		if(S->ch[i] == T->ch[j])
		{
			i++;
			j++;
		}
		//如果在匹配的过程中,中断了,出现了不匹配
		else
		{
			i = i-j+1;//将主串的i回溯j-1个字符(j-1可看成先回退j个,再下移一个)
			j = 0;//模式串走的j个位置全部回退,即变为0
		}
	}
	//退出原因如果是因为,模式串匹配完成,则返回子串出现的首位置
	if(j ==T->length)
		return i-j;
	//如果没有匹配到,则返回-1
	return -1;

}

14. 替换

//替换字符串:将字符串S中出现的T全部替换成V
void StrReplace(HString *S, HString *T, HString *V)
{
	int s_len = StrLength(S);//计算主串S的长度
	int t_len = StrLength(T);//计算模式串T的长度
	int v_len = StrLength(V);///计算替换字符串V的长度

	int index = -1;//初始化替换的首位置
	int pos = 0;//记录当前匹配到的位置

	//对整个主串进行搜索替换
	while(pos < s_len)
	{
		//查找第一个模式串所在的首位置
		index = StrIndex(S,T,pos);
		if(index == -1)//如果没有找到则结束
			return;
		//如果找到了,则将该模式串从index这个位置中删除
		StrDelete(S,index,t_len);
		//再将要替换的串从index这个位置中插入
		StrInsert(S,index,V);
		//记录此时匹配到的位置
		pos = index + v_len;//这个位置是替换前模式串所在的首位置加上替换的字符串长度
	}

}

结语

        对串结构的堆分配存储的介绍就到这里啦,希望这篇文章能给予你一些帮助,感谢各位人才的:点赞、收藏和评论,我们下次见。

附录

以下提供串结构堆分配存储的测试代码

HString.h

#ifndef __HSTRING_H__
#define __HSTRING_H__

#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#include<string.h>

//串结构
typedef struct HString
{
	char *ch;   //指向字符串所在空间首地址
	int   length; //记录字符串长度
}HString;

void InitString(HString *S);
void PrintString(HString *S);

void StrAssign(HString *S, char *str);
void StrCopy(HString *S, HString *T);
bool StrEmpty(HString *S);
int  StrCompare(HString *S, HString *T);
int  StrLength(HString *S);
void StrConcat(HString *T, HString *s1, HString *s2);
void SubString(HString *S, HString *sub,int pos, int len);
void StrInsert(HString *S, int pos, HString *T);
void StrDelete(HString *S, int pos, int len);
void StrClear(HString *S);
/
int StrIndex(HString *S, HString *T, int pos);
void StrReplace(HString *S, HString *T, HString *V);

#endif //__HSTRING_H__

HString.cpp

//串结构之堆分配存储

#include"HString.h"

//初始化字符串结构
void InitString(HString *S)
{
	S->ch = NULL;
	S->length = 0;
}

//赋值:将字符串str赋给字符结构S
void StrAssign(HString *S, char *str)
{
	int len = strlen(str); //求字符串str的长度

	//这一步的目的是防止内存泄漏
	if(S->ch != NULL) //判断这个结构之前是否有为其分配空间
		free(S->ch);//如果有,则释放

	S->ch = (char*)malloc(sizeof(char)*len);//申请符合str大小的空间
	assert(S->ch != NULL);
	for(int i=0; i<len; ++i)//分配成功后,将str中的字符逐个赋给S
	{
		S->ch[i] = str[i];
	}
	S->length = len;//记录此时S的长度
}

//打印字符串
void PrintString(HString *S)
{
	//将字符逐一打印
	for(int i=0; i<S->length; ++i)
	{
		printf("%c",S->ch[i]);
	}
	printf("\n");
}

//求字符串长度
int  StrLength(HString *S)
{
	return S->length;
}

//字符串拷贝:将T拷贝到S
void StrCopy(HString *S, HString *T)
{
	int len = StrLength(T);//计算T的长度

	//这一步的目的是防止内存泄漏
	if(S->ch != NULL) //判断这个结构之前是否已经分配了空间
		free(S->ch); //如果有,则释放

	//为S申请符合T大小的空间
	S->ch = (char *)malloc(sizeof(char) * len);
	assert(S->ch != NULL);
	//分配成功后,将T中的字符逐个拷贝到S
	for(int i=0; i<len; ++i)
	{
		S->ch[i] = T->ch[i];
	}
	S->length = len;
}

//判断字符串是否为空
bool StrEmpty(HString *S)
{
	return S->length==0;
}

//字符串比较函数
int  StrCompare(HString *S, HString *T)
{
	//如果两个字符串都为空
	if(S->length==0 && T->length==0)
		return 0;
	int result = 0; //比较相同,返回0
	
	int i=0;
	int j=0;
	//在两个字符串都还有字符可以进行比较时,不断的比较
	while(i<S->length && j<T->length)
	{
		//发现S比T大,返回1
		if(S->ch[i] > T->ch[j])
			return 1;
		//发现T比S大返回-1
		else if(S->ch[i] < T->ch[j])
			return -1;
		else //相同继续往后找
		{
			i++;
			j++;
		}
	}
	//S还有剩余(S的前面部分与T完全相同)
	if(i<S->length)
		result = 1;
	//T还有剩余(T的前面部分与S完全相同)
	if(j<T->length)
		result = -1;
	//两个字符串完全相同
	return result;
}

//字符串拼接:将s1和s2拼接,存放入T
void StrConcat(HString *T, HString *s1, HString *s2)
{
	//这一步的目的是防止内存泄漏
	if(T->ch != NULL) //判断这个结构之前是否已经分配了空间
		free(T->ch); //如果有,则释放

	//计算s1和s2的长度
	int len1 = StrLength(s1);
	int len2 = StrLength(s2);
	//为T分配足够存入S1和S2大小的空间
	T->ch = (char *)malloc(sizeof(char)*(len1+len2));
	assert(T->ch != NULL);
	//分配成功
	for(int i=0; i<len1; ++i) //放入S1
	{
		T->ch[i] = s1->ch[i];
	}
	for(int j=0; j<len2; ++j) //拼接上S2
	{
		T->ch[i+j] = s2->ch[j];
	}
	//修改拼接后T的长度
	T->length = len1 + len2;
}

//子串截取:从S的pos取len长度的字符串放入sub中
void SubString(HString *S, HString *sub,int pos, int len)
{
	//如果输入的条件,是否不符合截取要求
	if(pos<0 ||pos>S->length ||len<0 ||len>S->length-pos)
		return; //不符合,退出
	//符合
	//这一步的目的是防止内存泄漏
	if(sub->ch != NULL)  //判断这个结构之前是否已经分配了空间
		free(sub->ch);  //如果有,则释放

	//为Sub分配足够存入截取子串的存储空间
	sub->ch = (char*)malloc(sizeof(char) * len);
	assert(sub->ch != NULL);
	//分配成功
	int j = pos;//设置开始截取的位置
	for(int i=0; i<len; ++i)//从S中的pos位置开始逐一取出len个字符,放入sub
	{
		sub->ch[i] = S->ch[j+i];
	}
	
	sub->length = len;//更改此时sub的长度
}


//插入字符串:将T插入到S的pos位置
void StrInsert(HString *S, int pos, HString *T)
{
	//判断是否需要进行插入
	if(T->length == 0)
		return;
	//判断是否能够插入
	if(pos<0 || pos>S->length)
		return;
	
	//为S扩充存储空间,存储空间扩充为足够容纳S+T内的字符
	char *ch = (char*)realloc(S->ch,sizeof(char)*(S->length+T->length));
	assert(ch != NULL);
	S->ch = ch;
	
	//将S中最后一个字符到pos位置中的这段字符串向后移动T的长度,供字符串T插入
	for(int i=S->length-1; i>=pos; --i)//移动注意是由后往前,这样才不会将数据覆盖
	{
		S->ch[i+T->length] = S->ch[i];
	}
	
	int j = pos; //设置开始插入位置
	for(i=0; i<T->length; ++i)//将T中的字符逐个放入
	{
		S->ch[j+i] = T->ch[i];
	}
	//更新插入T后的字符串S长度
	S->length += T->length;
}


//删除字符串:删除字符串S中从pos位置开始的len长度子串
void StrDelete(HString *S, int pos, int len)
{
	//判断是否不满足删除条件
	if(pos<0 ||pos>S->length)
		return; 
	if(len <= 0 || len >S->length)
		return;
	
	int j = pos; //设置开始删除的位置
	//将pos+len处及其之后的字符全部往前移动len长度,通过覆盖实现删除
	for(int i=j+len; i<S->length; ++i)
	{
		S->ch[i-len] = S->ch[i];
	}
	//修改删除后S的长度
	S->length -= len;
}

//清空
void StrClear(HString *S)
{
	S->length = 0;//长度设置为0
	//判断是否开辟了空间
	if(S->ch != NULL)
		free(S->ch);//开辟了,就是否
	S->ch = NULL;//指向空
}


//模式匹配
int StrIndex(HString *S, HString *T, int pos)
{
	int i = pos;//主串开始匹配的初始位置
	int j = 0;//模式串开始匹配的初始位置
	//如果还没匹配到模式串且主串中还有字符,则继续匹配
	while(i != S->length && j !=T->length)
	{
		//如果有字符匹配则,将主串和模式串分别下移一个字符
		if(S->ch[i] == T->ch[j])
		{
			i++;
			j++;
		}
		//如果在匹配的过程中,中断了,出现了不匹配
		else
		{
			i = i-j+1;//将主串的i回溯j-1个字符(j-1可看成先回退j个,再下移一个)
			j = 0;//模式串走的j个位置全部回退,即变为0
		}
	}
	//退出原因如果是因为,模式串匹配完成,则返回子串出现的首位置
	if(j ==T->length)
		return i-j;
	//如果没有匹配到,则返回-1
	return -1;

}

//替换字符串:将字符串S中出现的T全部替换成V
void StrReplace(HString *S, HString *T, HString *V)
{
	int s_len = StrLength(S);//计算主串S的长度
	int t_len = StrLength(T);//计算模式串T的长度
	int v_len = StrLength(V);///计算替换字符串V的长度

	int index = -1;//初始化替换的首位置
	int pos = 0;//记录当前匹配到的位置

	//对整个主串进行搜索替换
	while(pos < s_len)
	{
		//查找第一个模式串所在的首位置
		index = StrIndex(S,T,pos);
		if(index == -1)//如果没有找到则结束
			return;
		//如果找到了,则将该模式串从index这个位置中删除
		StrDelete(S,index,t_len);
		//再将要替换的串从index这个位置中插入
		StrInsert(S,index,V);
		//记录此时匹配到的位置
		pos = index + v_len;//这个位置是替换前模式串所在的首位置加上替换的字符串长度
	}

}

Main.cpp

#include"HString.h"

void main()
{
	HString S;
	InitString(&S);
	StrAssign(&S,"abcdefghij");

	StrDelete(&S,2,3);

	PrintString(&S); //cde


	HString T;
	InitString(&T);
	StrAssign(&T,"ij");
	PrintString(&T); 

	printf("%d\n",StrIndex(&S, &T, 0));

	HString V;
	InitString(&V);
	StrAssign(&V,"lty");
	PrintString(&V); 

	StrReplace(&S, &T, &V);
	PrintString(&S); 

}
  • 28
    点赞
  • 121
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值