串的堆分配存储表示
一、堆分配存储概述
堆分配内存仍是一组地址连续的存储单元来存放串值字符序列,但是存储空间实在程序执行过程中动态分配而得。在C语言中,存在一个称为“堆”的自由存储区,并由C语言的动态分配函数malloc()和free()来管理。利用函数malloc()为每个新产生的串分配一块实际串长所需的存储空间,若分配成功,则返回一个指向起始地址的指针,作为串的基址,同时为了方便以后的处理,约定串长也作为存储结构的一部分。
二、串的堆分配存储结构
三、串的操作
//1、初始化(产生空串)字符串S
void InitString(pHString S);
//2、将S清为空串
void ClearString(pHString S);
//3、生成一个其值等于串常量chars的串S
void StrAssign(pHString S, char *chars);
//4、显示字符串
void StrShow(pHString S);
//5、复制串S到T
void StrCopy(pHString T, pHString S);
//6、判断串是否为空,若为空返回True,否则返回false
bool StrEmpty(pHString S);
//7、比较两个串的最前面字符的ASCII码的大小,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int StrCompare(pHString S, pHString T);
//8、返回S的元素个数,称为串的长度
int StrLength(pHString &S);
//9、用T返回由S1和S2联接而成的新串
void StrConcat(pHString S1, pHString S2, pHString T);
//10、用Sub返回串S的第pos个字符起长度为len的子串。
bool StrSub(pHString Sub, pHString S, int pos, int len);
//11、找出子串T值主串S中的位置(与子串首字符相等的位置)
int Index1(pHString S, pHString T);
//12、 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0,其中,T非空,1≤pos≤StrLength(S)。
int Index2(pHString S, pHString T, int pos);
//13、从串S中删除第pos个字符起长度为len的子串,从新申请空间
bool StrDelete1(pHString S, int pos, int len);
//14、从串S中删除第pos个字符起长度为len的子串,调整内存空间
bool StrDelete2(pHString S, int pos, int len);
typedef struct HString
{
char * ch; // 若是非空串,则按串长分配存储区,否则ch为NULL
int length; // 串长度
}HString,*pHString;
1、初始化(产生空串)字符串S
void InitString(pHString S)
{
S->ch = NULL;
S->length = 0;
}
2、将S清为空串
void ClearString(pHString S)
{
free(S->ch);
S->ch = NULL;
S->length = 0;
}
3、生成一个其值等于串常量chars的串S
void StrAssign(pHString S, char *chars)
{
int i, j;
if (S->ch)//若S的指针不为空则释放S指针域所指向的空间
free(S->ch); // 释放S原有空间
i = strlen(chars); // 求chars的长度i
if (!i)//若果字符串为空则清空S(相当于复制了一个空字符串)
{ // chars的长度为0
S->ch = NULL;
S->length = 0;
}
else
{ // chars的长度不为0
S->ch = (char*)malloc(i * sizeof(char)); // 分配大小跟chars大小相同的串空间
if (!S->ch) // 分配串空间失败
exit(-1);
for (j = 0; j < i; j++) // 复制串
S->ch[j] = chars[j];
S->length = i;
}
}
4、显示字符串
void StrShow(pHString S)
{
int i;
for (i = 0; i < S->length; i++)
printf("%c", S->ch[i]);
printf("\n");
}
5、复制串S到T
void StrCopy(pHString T,pHString S )
{
if (T->ch)
free(T->ch); // 释放T原有空间
T->ch = (char *)malloc(S->length*(sizeof(char)));//申请内存
if (T->ch == NULL)
{
printf("内存分配失败!");
exit(-1);
}
for (int i = 0; i < S->length; i++)//逐一复制
{
T->ch[i] = S->ch[i];
}
T->length = S->length;//复制串长
}
6、判断串是否为空,若为空返回True,否则返回false
bool StrEmpty(pHString S)
{
if (S->length==0&&S->ch==NULL)//空串标志
{
return true;
}
else
{
return false;
}
}
7、比较两个串的最前面字符的ASCII码的大小,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
8、返回S的元素个数,称为串的长度
int StrLength(pHString &S)
{
return S->length;
}
9、用T返回由S1和S2联接而成的新串
void StrConcat(pHString S1, pHString S2, pHString T)
{
if (T->ch)
free(T->ch); // 释放T原有空间
T->ch = (char *)malloc((S1->length + S2->length)*(sizeof(char)));//申请内存
if (T->ch == NULL)
{
printf("内存分配失败!");
exit(-1);
}
for (int i = 0; i < S1->length; i++)//逐一复制S1
{
T->ch[i] = S1->ch[i];
}
for (int i = 0; i < S2->length; i++)//接着逐一复制S2
{
T->ch[S1->length +i] = S2->ch[i];
}
T->length = (S1->length + S2->length);//复制总串长
}
10、用Sub返回串S的第pos个字符起(包括pos位置处的字符)长度为len的子串。
bool StrSub(pHString Sub,pHString S,int pos,int len)
{
if (StrEmpty(S))
{
return false;
}
if (pos<1||pos>S->length||len<0||len>S->length-pos+1)//排除不符合条件的pos和len
{
return false;
}
if (Sub->ch)
free(Sub->ch); // 释放旧空间
if (!len) // 空子串
{
Sub->ch = NULL;
Sub->length = 0;
}
else
{
Sub->ch = (char*)malloc(len * sizeof(char));//申请len个空间
if (!Sub->ch)
exit(-1);
}
for (int i = pos; i < pos+len; i++)//逐个复制
{
Sub->ch[i - pos] = S->ch[i-1];
}
Sub->length = len;//保存长度
return true;
}
11、找出子串T值在主串S中的位置(与子串首字符相等的位置)
int Index1(pHString S, pHString T)
{
int i,j;
for (i = 0; i < S->length; i++)//循环主串
{
if (S->ch[i] == T->ch[0])//如果在主串中找到一个与子串的第一个字符相等的字符时
{
int cont = 1;//计数变量
for (j = 0; j < T->length; j++)//遍历子串
{
if (T->ch[j + 1] != S->ch[i + j+1])//在遍历T[0]时如果有不一致时退出遍历
{
break;
}
else//否则计数
{
cont++;
if (cont == T->length)//当有T[0]个字符相同时则找到子串位置
return i+1;
}
}
}
continue;
}
return 0;//不存在时
}
12、返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0,其中,T非空,1≤pos≤StrLength(S)。![在这里插入图片描述](https://img-blog.csdnimg.cn/20200613231639511.png)
int Index2(pHString S, pHString T, int pos)
{
int i, j;
if (1 <= pos && pos <= S->length)
{
i = pos;//从主串的第pos个字符开始和子串的第一个字符比较
j = 0;
while (i <= S->length && j < T->length)
{
if (S->ch[i] == T->ch[j]) // 若找到主串字符与子串首字符相等时继续比较后继字符
{
++i;
++j;
}
else // 指针后退,主串字符下标后移一位,重新开始匹配
{
i = i + 1;
j = 0;
}
}
if (j == T->length)//条件成立,子串在主串中
return i - T->length+1;//因为i是下标,下标编程序号需要+1
else
return 0;
}
else
return 0;
}
13、从串S中删除第pos个字符起长度为len的子串,从新申请空间
bool StrDelete1(pHString S, int pos, int len)
{
if (StrEmpty(S))//S为空时
{
return false;
}
if (pos<1||pos>S->length||len<0||len>S->length-pos+1)//pos和len不满足条件时
{
return false;
}
char *pNew = (char*)malloc((S->length - len) * sizeof(char));//从新申请空间
if (pNew==NULL)//申请失败
{
return false;
}
for (int i = 0; i < pos-1; i++)//复制pos前的字符
{
pNew[i] = S->ch[i];
}
for (int i = pos+len-1; i < S->length; i++)//复制pos+len-1后的字符
{
pNew[i-len] = S->ch[i];
}
free(S->ch);//释放原内存
S->ch = pNew;
S->length = S->length - len;//更新长度
return true;
}
14、从串S中删除第pos个字符起长度为len的子串,调整内存空间
bool StrDelete2(pHString S, int pos, int len)
{
int i;
if (StrEmpty(S))//S为空时
{
return false;
}
if (S->length < pos + len - 1)//pos和len不满足条件时
return false;
for (i = pos - 1; i <= S->length - len; i++)//从pos + len - 1起,之后的元素向前移动
S->ch[i] = S->ch[i + len];
S->length -= len;
S->ch = (char*)realloc(S->ch, S->length * sizeof(char));//调整S->ch的空间
return true;
}
最后给出完整代码
// 串的堆分配存储.cpp
#include<string.h>
#include<malloc.h> // malloc()等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
typedef struct HString
{
char * ch; // 若是非空串,则按串长分配存储区,否则ch为NULL
int length; // 串长度
}HString,*pHString;
//1、初始化(产生空串)字符串S
void InitString(pHString S);
//2、将S清为空串
void ClearString(pHString S);
//3、生成一个其值等于串常量chars的串S
void StrAssign(pHString S, char *chars);
//4、显示字符串
void StrShow(pHString S);
//5、复制串S到T
void StrCopy(pHString T, pHString S);
//6、判断串是否为空,若为空返回True,否则返回false
bool StrEmpty(pHString S);
//7、比较两个串的最前面字符的ASCII码的大小,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int StrCompare(pHString S, pHString T);
//8、返回S的元素个数,称为串的长度
int StrLength(pHString &S);
//9、用T返回由S1和S2联接而成的新串
void StrConcat(pHString S1, pHString S2, pHString T);
//10、用Sub返回串S的第pos个字符起长度为len的子串。
bool StrSub(pHString Sub, pHString S, int pos, int len);
//11、找出子串T值主串S中的位置(与子串首字符相等的位置)
int Index1(pHString S, pHString T);
//12、 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0,其中,T非空,1≤pos≤StrLength(S)。
int Index2(pHString S, pHString T, int pos);
//13、从串S中删除第pos个字符起长度为len的子串,从新申请空间
bool StrDelete1(pHString S, int pos, int len);
//14、从串S中删除第pos个字符起长度为len的子串,调整内存空间
bool StrDelete2(pHString S, int pos, int len);
int main()
{
HString S, T, S1,Sub;
InitString(&S);
InitString(&S1);
InitString(&T);
InitString(&Sub);
char chars[] = "god bye!";
StrAssign(&S, chars);
StrShow(&S);
StrCopy(&T,&S);
StrShow(&T);
if (StrEmpty(&S))
{
printf("串S为空\n");
}
else
{
printf("串S不为空\n");
}
char char1[] = "god hello!";
StrAssign(&T, char1);
StrShow(&T);
printf("比较S和T的结果%d\n", StrCompare(&S, &T));
StrAssign(&S1, char1);
printf("拼接字符串");
StrShow(&S);
StrShow(&S1);
StrConcat(&S,&S1,&T);
StrShow(&T);
int pos = 3, len = 3;
if (StrSub(&Sub, &S, pos, len))
{
StrShow(&Sub);
}
HString SS, TT;
InitString(&SS);
InitString(&TT);
char char2[] = "abcdefghijklmn";
char char3[] = "bcd";
StrAssign(&SS, char2);
StrShow(&SS);
StrAssign(&TT, char3);
printf("子串T在主串S中的位置为 %d\n", Index1(&SS,&TT));
printf("子串T在主串S中的位置为 %d\n", Index2(&SS,&TT,5));
StrShow(&SS);
StrDelete1(&SS, pos, 3);
StrShow(&SS);
StrDelete2(&SS, pos, 3);
StrShow(&SS);
return 0;
}
//1、初始化(产生空串)字符串S
void InitString(pHString S)
{
S->ch = NULL;
S->length = 0;
}
//2、将S清为空串
void ClearString(pHString S)
{
free(S->ch);
S->ch = NULL;
S->length = 0;
}
//3、生成一个其值等于串常量chars的串S
void StrAssign(pHString S, char *chars)
{
int i, j;
if (S->ch)//若S的指针不为空则释放S指针域所指向的空间
free(S->ch); // 释放S原有空间
i = strlen(chars); // 求chars的长度i
if (!i)//若果字符串为空则清空S(相当于复制了一个空字符串)
{ // chars的长度为0
S->ch = NULL;
S->length = 0;
}
else
{ // chars的长度不为0
S->ch = (char*)malloc(i * sizeof(char)); // 分配大小跟chars大小相同的串空间
if (!S->ch) // 分配串空间失败
exit(-1);
for (j = 0; j < i; j++) // 复制串
S->ch[j] = chars[j];
S->length = i;
}
}
//4、显示字符串
void StrShow(pHString S)
{
int i;
for (i = 0; i < S->length; i++)
printf("%c", S->ch[i]);
printf("\n");
}
//5、复制串S到T
void StrCopy(pHString T,pHString S )
{
if (T->ch)
free(T->ch); // 释放T原有空间
T->ch = (char *)malloc(S->length*(sizeof(char)));//申请内存
if (T->ch == NULL)
{
printf("内存分配失败!");
exit(-1);
}
for (int i = 0; i < S->length; i++)//逐一复制
{
T->ch[i] = S->ch[i];
}
T->length = S->length;//复制串长
}
//6、判断串是否为空,若为空返回True,否则返回false
bool StrEmpty(pHString S)
{
if (S->length==0&&S->ch==NULL)//空串标志
{
return true;
}
else
{
return false;
}
}
//7、比较两个串的最前面字符的ASCII码的大小,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int StrCompare(pHString S, pHString T)
{
for (int i = 0; i < S->length&&T->length; i++)
{
if (S->ch[i]!=T->ch[i])//逐一比较字符
{
return S->ch[i] - T->ch[i];//一旦不相等,则返回不想等字符的ASCII码的差值
}
}
return S->length - T->length;//如果全部相等则返回其长度差值
}
//8、返回S的元素个数,称为串的长度
int StrLength(pHString &S)
{
return S->length;
}
//9、用T返回由S1和S2联接而成的新串
void StrConcat(pHString S1, pHString S2, pHString T)
{
if (T->ch)
free(T->ch); // 释放T原有空间
T->ch = (char *)malloc((S1->length + S2->length)*(sizeof(char)));//申请内存
if (T->ch == NULL)
{
printf("内存分配失败!");
exit(-1);
}
for (int i = 0; i < S1->length; i++)//逐一复制S1
{
T->ch[i] = S1->ch[i];
}
for (int i = 0; i < S2->length; i++)//接着逐一复制S2
{
T->ch[S1->length +i] = S2->ch[i];
}
T->length = (S1->length + S2->length);//复制总串长
}
//10、用Sub返回串S的第pos个字符起(包括pos位置处的字符)长度为len的子串。
bool StrSub(pHString Sub,pHString S,int pos,int len)
{
if (StrEmpty(S))
{
return false;
}
if (pos<1||pos>S->length||len<0||len>S->length-pos+1)//排除不符合条件的pos和len
{
return false;
}
if (Sub->ch)
free(Sub->ch); // 释放旧空间
if (!len) // 空子串
{
Sub->ch = NULL;
Sub->length = 0;
}
else
{
Sub->ch = (char*)malloc(len * sizeof(char));//申请len个空间
if (!Sub->ch)
exit(-1);
}
for (int i = pos; i < pos+len; i++)//逐个复制
{
Sub->ch[i - pos] = S->ch[i-1];
}
Sub->length = len;//保存长度
return true;
}
//11、找出子串T值在主串S中的位置(与子串首字符相等的位置)
int Index1(pHString S, pHString T)
{
int i,j;
for (i = 0; i < S->length; i++)//循环主串
{
if (S->ch[i] == T->ch[0])//如果在主串中找到一个与子串的第一个字符相等的字符时
{
int cont = 1;//计数变量
for (j = 0; j < T->length; j++)//遍历子串
{
if (T->ch[j + 1] != S->ch[i + j+1])//在遍历T[0]时如果有不一致时退出遍历
{
break;
}
else//否则计数
{
cont++;
if (cont == T->length)//当有T[0]个字符相同时则找到子串位置
return i+1;
}
}
}
continue;
}
return 0;//不存在时
}
//12、返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0,其中,T非空,1≤pos≤StrLength(S)。
int Index2(pHString S, pHString T, int pos)
{
int i, j;
if (1 <= pos && pos <= S->length)
{
i = pos;//从主串的第pos个字符开始和子串的第一个字符比较
j = 0;
while (i <= S->length && j < T->length)
{
if (S->ch[i] == T->ch[j]) // 若找到主串字符与子串首字符相等时继续比较后继字符
{
++i;
++j;
}
else // 指针后退,主串字符下标后移一位,重新开始匹配
{
i = i + 1;
j = 0;
}
}
if (j == T->length)//条件成立,子串在主串中
return i - T->length+1;//因为i是下标,下标编程序号需要+1
else
return 0;
}
else
return 0;
}
//13、从串S中删除第pos个字符起长度为len的子串,从新申请空间
bool StrDelete1(pHString S, int pos, int len)
{
if (StrEmpty(S))//S为空时
{
return false;
}
if (pos<1||pos>S->length||len<0||len>S->length-pos+1)//pos和len不满足条件时
{
return false;
}
char *pNew = (char*)malloc((S->length - len) * sizeof(char));//从新申请空间
if (pNew==NULL)//申请失败
{
return false;
}
for (int i = 0; i < pos-1; i++)//复制pos前的字符
{
pNew[i] = S->ch[i];
}
for (int i = pos+len-1; i < S->length; i++)//复制pos+len-1后的字符
{
pNew[i-len] = S->ch[i];
}
free(S->ch);//释放原内存
S->ch = pNew;
S->length = S->length - len;//更新长度
return true;
}
//14、从串S中删除第pos个字符起长度为len的子串,调整内存空间
bool StrDelete2(pHString S, int pos, int len)
{
int i;
if (StrEmpty(S))//S为空时
{
return false;
}
if (S->length < pos + len - 1)//pos和len不满足条件时
return false;
for (i = pos - 1; i <= S->length - len; i++)//从pos + len - 1起,之后的元素向前移动
S->ch[i] = S->ch[i + len];
S->length -= len;
S->ch = (char*)realloc(S->ch, S->length * sizeof(char));//调整S->ch的空间
return true;
}