c语言求最大字符串怎么求字符串的某个子串的个数?可以不连续

C++中的string类 翻译过来就是字符串类型 但是它可不是一个平平无奇的字符串 它具有像线性表一样的增删查改的功能 会自动扩容 还支持迭代器遍历 功能可谓十分齐全 下面就来实现它


以及目录中的相关方法_str是字符指针指向一块用来存储字符串的空间 、_size是用来记录字符串的有效字符的个数、_capacity是用来记录当前空间可以存放多少个字符(容量)

上面介绍了string 类的成员变量 那么构造函数就要对其进行初始化咯

实参传过来的必须是字符串,所以用字符指针接收,细节一点,就是用const修饰一下*str这样实参就不能在构造函数中被改变

然后就用strlen函数计算出传过来的字符串的长度,让该类中的成员变量(属性)_size和_capacity都等于该长度,然后再开辟出比容量大一的空间来存储我们要所要构造的字符串。最后一步就是把实参的字符串拷贝到我们新开辟的空间中;这一波操作下来就构造好了一个string对象,该对象(字符串)的内容,空间大小,长度都是和我们初始化时给的参数一样的了

关于这里为什么要开辟_capacity+1个字符的空间,也不一定非得是这样,只要逻辑上走得通都可以;这里我定义的_capacity 是可以存储有效字符的个数,不包括\0在内,但是字符串是以\0 作为结尾标志的,所以要多开辟一个字节的空间用来存放\0。

二、拷贝构造函数(传统写法和现代写法)

拷贝构造函数就是拿一个已经创建了初始化好了的对象,去初始化新定义的对象。

注意:这里的拷贝够造必须是深拷贝(所有的内容相同,但是原来的和拷贝的是并不是同一个),不能是浅拷贝(光是值的拷贝)。(自身理解,若有考虑不周,还望体谅)

string b(a);//这种方式就是拷贝构造了 因为b是刚定义的对象 // 拿以及定义且初始化的对象a对其进行初识化

但是这里的拷贝构造有两种写法 传统写法及现代写法

思路:开辟空间,把用来构造的对象的数据一一复制给自己

以上面的例子为例说明:

思路:与传统方法不同,传统方法是自己一一去实现拷贝,但是现代方法比较懒,它调写好的构造函数去帮自己构造出一个与传过来的对象一样的对象,在将构造出来的对象的数据和自己交换。

:_str(nullptr)//必须初始化为空指针 否则后面调用析构函数会出错 野指针问题

注:代码中的三个swap可以合并成一个函数简化代码(标准库里也是这样的):

这里需要注意的是自身的_str必须要初始化,不能是随机的!!!

因为利用构造函数构造出来的对象临时tmp出来作用域会自动销毁,那么就会去调用析构函数,但是这里我们把本身对象和临时对象的_str交换了,所以tmp调用析构函数的时候,就是去释放本身对象中_str指向的空间,那么如果本身对象的_str没有初始化指向的就是随机空间是野指针,释放野指针指向的空间是会报错的,所以必须初始化_str 为空指针,这样就不会出错了。

最后对两者进行对比一下:传统写法比较呆板,现代写法比较新颖,也比较简洁

析构函数就比较简单了 ,释放掉_str指向的空间,并将_str置空即可

这里的按下标访问或者修改就是运算符重载的知识了

利用[]的运算符重载即可实现按下标访问或者修改

一、访问的是非const对象

对于非const对象我们可读可写 那么就是返回的就是非const的引用类型

二、访问的是const对象

1、对于const对象,只能读,不能写,那么其[]的运算符重载函数就要用const修饰,const修饰的函数或者接口,修饰的是隐含的this指针指向的对象(*this),所指向对象的成员变量不可以通过该函数或接口改变,起到了保护作用。

2、既然是只读,而返回的是引用,但又不能通过返回的引用去改变对象成员变量,所以引用也要用const来修饰

五、赋值操作(传统写法和现代写法)

赋值操作可以实现可以拿对象赋值给对象

也分传统写法和现代写法,传统写法就是按部就班的走,现代写法就是借助构造函数构造对象在交换

思路:先释放原来的空间,在开辟新的空间,把str对象的_str里的数据拷贝到自己的_str里,再让_size和_capacity都与str对象的_size和_capacity相同

swap(str);//把这三个swap合并成了一个成员函数简化了一下代码

思路:让形参是一个值而不是引用,那么传参的时候编译器就会调用上面的拷贝构造(深拷贝)去构造出与实参有着相同属性的形参,绕后再让自身对象的各个成员变量(属性)一一交换就好了,并且不用去释放空间,因为形参是局部变量出来定义域会自动调用析构函数清理数据,而我们经过交换把自己的各个属性都给了形参,形参就会帮我们调用析构函数自动清理原来的数据了,很棒!

在字符串的尾部插入数据,可以是字符,也可以是字符串。

既然是插入单个字符就是先判断容量够不够,不够就进行扩容,再把结束标准\0设置好,最后把字符插入即可。

下标问题:这里的_size表示的是有效字符的个数,因为小标从0开始,所以最后一个有效字符即使_str[size-1]了,那么_str[_size]就是\0了。我们插入字符就要把\0往后挪一个字符的位置就是上面的 _str[_size + 1] = '\0'; 然后在\0原来的位置放我们插入的字符_str[_size]

注意:这里的扩容最好用strncpy 否则特定情况会出bug 下面会详细提到

实现一个尾插字符串的函数append(标准库也有的)

//在与当前容量进行比较,判断是否需要扩容

append函数的实现思路也是先判断是否需要扩容,然后把要插入的字符串拷贝到对象的_str中更新_size(插入数据的思路都是大同小异的)

七、加等字符和加等字符串操作

加等字符和加等字符串的操作是和上面的插入字符和字符串的操作一样的 就可以复用上面的pushback 和 append 来实现他们 只是函数名不同,内在的实现逻辑是相同的

因为string是类似线性表的,可以动态扩容,每次插入数据都需要判断是否需要进行扩容,上面那么多的插入,都需要判断是否需要扩容,那么就可以把扩容写成一个成员函数,需要扩容的时候调用它即可。

这里的reserve只是负责开辟空间,不负责初始化空间,只是_capacity会改变,_size是不会改变的

//_str[_capacity] = '\0';//这个不能少 因为开辟的一块新空间最后要设置成\0 防止在析构的时候会出现错误 不知道到哪里结束 注意 //上一行的注释是错的 不需要 这是多此一举 因为你如果插入数据或者扩容 本身的\0 都是会被拷进去的 有效字符的结尾都会有一个\0 //不需要你在扩容后为它最后面加上\0 它自己无论怎样都是\0 在有效字符的最后的

reserve这里就有细节值得扣了,就是上面讲的最好用strncpy不要用strcpy的原因所在

问题就是:当我们调用了resize之后如果没有个默认的初始化空间的字符,就是默认的'\0';或者说我们自己给的初始化空间的字符就是‘\0’,之后再调用reserve就会出现bug了

与reserve不同的是,resize 是开空间并且初始化的,给一个字符,将开辟出来的多于的空间用给的字符填充,更新_size,更新_capacity.

这里是复用了reserve进行扩容然后用memset去初始化多余的空间,初始化空间的范围是

(_str + _size,ch, n-_size),还有考虑缩容的情况,如果是n小于_capacity就是缩容了,直接在n下标对应的空间放上一颗零鸭蛋即可,最后更新_size

这个就比较简单了 直接写个成员函数,返回_size 即可

十一、获取成员变量_str的函数c_str()

这个也比较好实现 写个成员函数返回_str即可

随机插入也是string具有的功能,包括插入字符和字符串,插入的方法有三种。

通过对下标对数据进行挪动,在哪插入就从哪开始把数据往后挪动,空出位置来插入新数据

1.有缺陷的下标法 (不能是从下标为0的位置插入)

2.没有缺陷的下标法(可以在任意下标进行插入)

指针法就直接是对指针指向的数据进行操作了,就没有数的转化了,就不用担心-1的情况了。

这里的两种下标法只是四条代码不同,方法1 是让end等于_size下标(对应的\0),然后让

这样如果是从0开始插入数据,end最后就会变成0 ,最小的情况即使end变成0 ,是不会到-1去的,所以就很好地避开了-1的情况,就解决了缺陷;

具体步骤可以参考俺画的图(老费劲了)

下标法2是怎么解决下标法1的缺陷的具体图解(瞧一瞧吧):

//因为扩容后空间就不是原来的空间了 而是新的空间 原来的空间被释放了 那么end所指向的还是原来的空间上的\0是不可以 //所以把end放在开辟好空间后再赋值 切记不可以放在扩容的前面 又是一个小细节!!

注意:这里也有细节要扣,end是用来记录原来字符串的\0 的位置的,这里的end的初始化要在判断是否扩容的后面进行,否则会出现野指针的问题。因为如果要扩容的话,就会开辟新的空间然后把原来的数据拷贝到新空间,然后把这块空间赋值给原来的_str,相当于是内容没有变,容量变了,空间地址也变了,扩容前后是两块不同的空间,如果在判断扩容之前就初始化了end,那么如果下面进行了扩容_str就会是另一块新的空间了,那么后面循环里对end进行的操作就是非法的了,为什么呢?

因为扩容后是_str指向的是新空间,end本应该新空间中数据中\0的位置的指针,但是在扩容前就初始化了end的话那么end就是扩容前空间中数据中'\0'位置的指针了,在扩容后end还是指向原来空间中\0的位置,但是原来的空间已经被释放了,你这个时候再用end去访问原来的空间就是非法的,这时的end指针就是大名鼎鼎的“野指针”了!!!

在写完随机插入字符的函数后,再写随机插入字符串的函数后,会有一个类比的思想,就是把在插入字符函数中的    _str[end] = _str[end - 1];基础之上想着,既然是插入字符串,那么就要从\0开始往前直到pos位置的数据全部往后挪动插入字符串的长度个位置,也就是

这里是不能想当然地写的,我们要知道把数据往后挪插入字符串长度个距离,两个方括号里的数据差就要是字符串的长度,_str[end+len] = _str[end - 1];中很明显差值不是len 而是len+1

删除数据的思路与插入数据的思路相似,也是通过挪动数据,对要删除的数据进行覆盖处理,这里是用的strcpy来实现数据的挪动

size_t leftlen = _size - pos;//pos 是标从0开始 _size是长度不是从零开始 因为两个长度一剪再加1才是两者之间的个数 所以这里刚刚好减出来就是之间的元素个数

1.pos位置后剩下的字符个数小于要删除的字符个数

这种情况直接就把下标为pos的位置放上\0 即可,即使代表把pos位置之后的所有数据全部删除

2.pos位置之后剩下的字符个数大于要删除的字符个数

这种情况就是把从下标从pos+len的位置往后的字符全部拷贝到从pos下标位置开始往后的空间中

十四、查找单个字符和子串

这里用到了strstr函数来实现找子串的功能

遍历思想,如果找到了就返回下标,否则返回string中的npos (无符号整形的-1 )

十五、简易迭代器遍历的实现

然后各自写两个函数begin()和end()作为迭代器的开始和结束

在函数中使用实现的简易的迭代器去遍历输出字符串

实现像比较数字一样比较类(字符串)的大小

这里用到了strcmp来实现

//比较两个字符串 可以用函数strcmp
 
实现了大于小于等于,剩下的借口就可以复用他们来实现了




十七、类的直接输入输出

 
 
实现像基本类型一样直接输出string对象总的字符串
//ch++; 因为这里是范围for 所以不用自己写加加 他自己会自动加的
这里要返回的是输出流的引用,使得可以连续地输出,out 是ostream的对象。
//如果是本来就有数据的字符串再输入 那就要把原来的数据清理掉 然后size变成0
注意这里不能直接用in来输入,因为in遇到字符'\0'和字符'\n'就会自动忽略,然后程序就不动了,崩了。要用ostream类的in对象的get方法来接收输入的值,相当于C语言中的getchar(),可以接收\n 和 \0.除了EOF其他都可以接收。

十八、标准库中getline简易的实现

 
 
getline 是输入一个串 要包括空格在内 cin和cout 都是遇到\n 和 \0 就停止的,根据上面的输入可以改变一下条件实现输入的是一个可以包括空格的字符串,那就是把while里的ch!= '\0' 去掉就可以了。

好了 本文到此就结束了~

如果喜欢的话就留下你来过的痕迹吧!

先来看一个使用C语言从字符串中提取子字符串的基本方法总结:

判断对称子字符串最大长度的方法

先重写一个判断回文字串的方法,用指针实现,而不是数组了


判断子串是否为回文,可以考虑从内向外比较。例如字符串“google”,如果我们判断第二个字符o是对称的,只需要再向左、和向右各移一位就可以判断下一个字符串是否是对称的了
需要注意的一点是,针对原字符串中的每一个字符有两种情况:

以该字符为中心的对称分布,也就是回文子串为奇数
以该字符和该字符前一个字符为中心的对称分布,也就是说回文子串是偶数

外层需要n - 1层循环,内层对于每个字符,都由中间向两边遍历一遍,为n,因此总的时间复杂度为O(n * n)

输入一个字符串,输出该字符串中对称的子字符串的最大长度。
比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
存在多组数据,每组数据一行字符串,长度不大于100。
输出回文子串的最大长度。

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

字符串就是多个只读字符组成的数组。

只读是因为字符串的所有方法都不会改变原字符串,包括通过下标修改,字符串依旧是保持原样。

为什么说字符串也是数组?

(2)能够通过下标获取某个字符;

(2)能够使用.length获取字符串的长度;

(3)能够通过循环遍历得到每一个字符。

字符串的创建也分两种:字面量和构造函数

字符串也可以获取长度,通过.length。所以可以对字符串进行遍历。

注意:不能通过下标去修改字符串中某一个字符的值,修改不会生效。

一个字符集∑是一个建立了全序关系的集合,即任意属于∑的元素可以比较,字符集中的元素叫做字符。

一个字符串S将n个字符顺次排列组成,n为S的长度,计作|S|,此文使用的字符串均从1下标开始

字符串S的子序列是从S中将若干元素提取出来并不改变相对位置形成的序列,即S[p1],S[p2],...,S[pt],1≤p1≤p1≤...≤pt≤|S|。

是指从某个位置i开始到整个串末尾结束的一个特殊子串。字符串S的从i开头的后缀表示为Suffix(S,i),也就是Suffix(S,i)=S[i...|S|],suf(S,k)表示S后k个字符组成的后缀。

是指从串首开始到某个位置i结束的一个特殊子串。字符串S的从i结尾的前缀表示为Preffix(S,i),也就是Preffix(S,i)=S[1...i],pre(S,k)表示S前k个字符组成的前缀。

真前缀指除了S本身的S的前缀。

使用 char 数组存储,用空字符 \0 表示字符串的结尾(C 风格字符串)。

字符串常量可以用字符串字面量(用双引号括起来的字符串)表示。

我要回帖

更多关于 c语言求最大字符串 的文章

 

随机推荐