一、定义
串结构的堆分配存储与定长顺序存储方式一样,也是以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配而得。
二、结构
在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);
}