文章目录
串
串数据类型的定义
串的定义
串是由零个或多个字符组成的有限序列。串中的个数称为串的串的长度,含有零个元素的串叫做空串。
char str[] = "abcdef";
//输出字符直接
cout<<str;
#include <iostream>
using namespace std;
int main() {
//char *str = "0123456789";//也ok
char *str;
for(int i=0;i<10;++i){
str[i] = i+'0';
}
str[10] = '\0';//莫失莫忘,仙寿恒昌!
cout<<str;
return 0;
}
//输出结果
//0123456789
字符串输出规则:
当我们写cout<<str;
后,无论str是指针还是char数组,其实char *str,和char str[],就是同一个东西(还记得char的动态数组声明吗?char *str = new char[10];),编译器从str[0]开始输出,一直输出直到遇到‘\0’
,才停下来。
char str[10]的越界输出:我们令str[9]='0'
,这样我们就抹除掉了,字符串结尾的'\0'
这样编译器把整个str数组输出完之后,还会继续往后面输出,随机在某个位置停下来,当你的内存区的数字转为char类型恰好是‘\0'
就停下来了(如果一直遇不到\0
,就继续往后面走呗!)。
串的存储结构:
1. 定长顺序存储表示
本书(2021天勤)的定义:给串尾加上‘\0’
结束标记,同时也设定length;
结构体定义:
typedef struct{
//maxSize是串的最大长度,+1存放'\0'
char str[maxSize+1];
int length;
}Str;
2. 变长分配存储
也叫动态分配存储,特点是:执行过程根据需要动态分配。
结构体定义:
typedef struct{
char *ch;
int length;
}Str;
使用时需要用函数malloc()来分配一个长度为length、类型为char型的连续存储空间,分配的空间可以用函数free()释放掉。
(真的不是我要杠一下,我在串的定义写的char *str(就是文章开头),就没用malloc(),照样可以用,问题就是我的str没有分配空间会抹除掉其他空间的数据。还是按照标准的malloc这样分配连续的存储空间比较好。)
3. 串的基本操作
几种串的原子操作。(就是基石操作)
1.赋值操作
串的操作不能直接用“=”。因为串是一个数组。
string的比较:
(考试我不知道啊,但是比赛时建议用string,string不仅可以赋值还能判断是否相等。)
//头文件,<string.h>也可以,但cstring是新的库
#include<cstring>
string str = "123";
string str2 ="456";
str2 = str;//ok的
if(str2 == str)//为真
cout<<"true";
必须对每个元素逐一赋值操作。
strassign(),将常量字符串赋值给str,操作成功返回1,否则返回0;
使用格式:
strassign(str,"test");
要点:
- 检查str.ch的空间分配了没,如果以前就分配了(str.ch为真),就直接free(str.ch)。因为我们不知道以前分配的空间够不够。
- 遍历
ch
得出它的长度,为str.ch的malloc准备。 - 为
str.ch
分配空间时,检查空间是否分配成功,空间分配失败,直接返回赋值失败。
int strassign(Str &str,char* ch) {
if(str.ch)
free(str.ch);
str.length = 0;
//先求出ch字符串的长度,来分配str的连续内存空间
char* c = ch;
while(*c){
++str.length;
++c;
}
if(str.length == 0){
str.ch = NULL;
return 1;
} else
{
str.ch = (char*)malloc(sizeof(char)*(str.length+1));
//+1是为了存放'\0'。不离不弃,芳龄永继!
//这个if是避免malloc分配失败
if(str.ch==NULL)
return 0;
else{
c = ch;
for(int i=0;i<=str.length;++i,++c)
str.ch[i] = *c;
return 1;
}
}
}
2.串的比较操作
int strcompare(Str s1,Str s2){
for(int i=0;i<s1.length && i<s2.length;++i)
if(s1.ch[i]!=s2.ch[i])
return s1.ch[i] - s2.ch[i];
return s1.length - s2.length;
}
3.串连接操作
int concat(Str &str,Str str1,Str str2){
if(str.ch){
free(str.ch);
str.ch = NULL;
}
str.ch = (char*)malloc(sizeof(char)*(str1.length+str.length+1));
if(str.ch==NULL)
return 0;
int i=0;
while(i<str1.length){
str.ch[i] = str1.ch[i];
++i;
}
int j=0;
while (j<=str2.length){
//注意取"=",是为了复制str.ch最后的'\0';
str.ch[i+j] = str2.ch[j];
++j;
}
str.length = str1.length + str2.length;
}
4.求子串操作
实现从str串的pos位置开始,长度为len的字串,由substr返回给用户。
int substring(Str& substr,Str str,int pos,int len){
//对pos和len进行检查
if(pos<0||pos>=str.length||len<0||len>str.length-pos){
return 0;
}
//小心这种情况
if(len==0){
substr.length = 0;
substr.ch = NULL;
return 1;
}else{
substr.ch = (char*)malloc(sizeof(char)*(len+1));
int i=pos;
int j=0;
while(j<pos+len){
substr.ch[j] = str.ch[pos+j];
}
substr.ch[j]='\0';
substr.length = len;
return 1;
}
}
5.串清空操作
int clearstring(Str& str){
//我觉得不直接free(str.ch),是为了避免释放空指针(dangerous)。
if(str.ch){
free(str.ch);
str.ch = NULL;
}
str.length = 0;
return 1;
}
4.2 串的模式匹配算法
注意:本节中的字符存储在1~length的位置上,注意区分0~length-1的存储位置。
4.2.1 简单模式匹配算法
(又称为幼稚模式匹配算法,后续kmp算法)
思想:从主串的第一位置起和模式串的第一个字符开始比较,如果相等就逐一比较后续字符;否则从第二个字符开始再重复前面的操作。
匹配成功返回模式串在主串中的位置;若匹配不成功,返回一个可区别于主串所有位置的标记,比如“0”;
int index(Str str,Str substr){
int i=1,j=1,k=i;
while (i<=str.length && j<=substr.length){
if(str.ch[i]==substr.ch[j]){
++i;
++j;
} else{
j=1;
i=++k;
}
}
if(j>substr.length){
return k;
} else
return 0;
}