重点是掌握算法,对字符串的存储、操作深入理解,能编程实现和灵活运用,即达到目的。不断扩充...
(一)、子串查找函数 findsub,findSubNum
1-1、查找子串
/*
函数名: findsub
函数原型:const char * findsub(const char * base, const char* sub);
功能:从字符串base中查找是否有字符串sub,如果有,从base中的有sub位置起,返回base在该处的指针,如果没有,返回null。
返回值:返回该位置的指针,如找不到,返回空指针。
思路:对base串的每个字符,依次作为起点和sub字串的逐个匹配,若sub串匹配完毕,则找到,返回base在该处的指针。否则,继续以base的下一个字符为起点,至base串的最后一个字符时仍无匹配,返回NULL。 (匹配,通过监测sub的所有字符是否等于base的某个子序列,通过‘\0’实现)
*/
const char * findSub(const char * base, const char *sub)
{
if((base==NULL)||(sub==NULL))
returnbase;
while(*base) //while(!base)
{
constchar *b = base;
constchar *s = sub;
while(*b++== *s++)
{
if(!*s) //if(!s)
returnbase;
}
base=base+1;
}
return NULL;
}
int main()
{
char base[10] = "chinese";
char sub1[3] = "ne";
char sub2[6] = "tommy";
cout<<findsub(base,sub1)<<endl;
// cout<<findsub(base,sub2)<<endl; 出现运行时错误!cout<<(char *)NULL;
return 0;}
@@小插曲:bug
检查了findsub函数本身无错误,但是main函数出现运行时错误,判断应该是查找不到"子串"时返回NULL的问题。
经测试,发现问题是char *类型指针为NULL时引发的:
由于操作符<<重载,当指针pc是char *型时,<<pc实际上是输出pc指向的内容即*pc。
而本程序中,cout<<findsub(base,sub2)<<endl;编译器会新建临时char *指针,当findsub返回NULL时,该指针为0,试图读数据时,系统认为访问非法。
而当pc为 int *类型的NULL指针时,<<pc不是读内容,则输出pc内存地址;
进行了以下测试:
1)在程序中语句cout<<NULL;是可以的,相当于cout<<0; 18817597901
2)cout<<(int*)(find(base,sub2))<<endl;也是可以的。0
修改了main程序:
int main()
{
char base[10] = "chinese";
char sub1[3] = "ne";
charsub2[6] = "tommy";
if(findsub(base,sub1))
cout<<findsub(base,sub1)<<endl;
else
cout<<"not found!"<<endl;
if(findsub(base,sub2))
cout<<findsub(base,sub2)<<endl;
else
cout<<"not found!"<<endl;
return 0;
}
1-2、变种函数findSubNum:编写函数检查主串中字串出现的次数
/*
函数名: findSubNum
函数原型:int findsub(const char * src, const char *sub);
功能:检查并输出在字串sub在字符串src中出现的次数。
返回值:出现个数。
思路:对base串的每个字符,依次作为起点和sub字串的逐个匹配,若sub串匹配完毕,则找到一个。继续以base的下一个字符为起点,最后统计次数。 (注意如何编程实现匹配的代码段 )
*/
int findSubNum(const char *src, const char *sub)
{
int count =0;
const char *p ;
const char *m ;
while(*src) //遍历src串
{
p = src; //
m = sub; //每次匹配查找前,先check指针p,m的值 !!
while(*p++ == *m++) //以p为起点,和子串逐个比较。如果比较完成*m='\0',则存在
{
if(*m=='\0') // bug:写成了= error C2166: l-value specifiesconst object
{count++; break;}
}
src++;
}
return count;
}
(二)、字符串逆置函数
2-1 将字符串逆置 strReverse
原型:char *strReverse(char *base);
功能:把字符串base的所有字符的顺序颠倒过来(不包括空字符NULL)。
说明:返回指向颠倒顺序后的字符串指针。
char * strRerverse(char * base)
{
if(base==NULL) return NULL; // or
char *top= base; //base内容赋值给p;
char *end=base+strlen(base)-1; //指向字符串尾地址
chartemp;
while(top++< end--)
{
temp =*top;
*top =*end;
*end =temp; // 交换
}
return base;
}
2-2 将字符串的所有单词逆置,单词内部结构不变strReverseByword
原型:char * strReverseByword(char *src)
功能:将字符串src中单词的位置逆置,不改变单词的内部结构!
说明:返回首地址指针
思路:首先将每个单词逆置,最后字符串整体逆置。每个字符逆置2次,以单词为单位的角度看逆置一次。注意编程时的控制结构。
/* 将字符串中的单词顺序逆置,单词内部结构不变 */
char * strReverseByword(char *src)
{
char *start =src;
char *end =src;
char *p =src;
while((*p++)!='\0') //遍历字符串src
{
if((*p=='')||(*p=='\0')) //如果p指向单词尾部或字符串尾部;
{
end =p-1; //单词尾部
while(start<end)
swap(*start++,*end--);
start= p+1; //下一个单词首部 (每次调整首尾指针)
}
} //注意:跳出while循环时p指向'\0'后的第2单元
start = src,end =p-2;
while(start<end)
{
swap(*start++,*end--);
}
return src;
}
// "i amfrom shanghai"
int main()
{
char pt[20]= "i am from shanghai!";
cout<<"string is :"<<pt;
cout<<"\nAfter reversed: "<<strReverseByword(pt);
/* ERROR:字符常量不能写,存放在字符常量区。
char * ptr ="i am from shanghai!";
cout<<"\nAfter reversed: "<<strReverseByword(ptr);
*/
return 0;
}
(三)比较函数 strcmp
/*
原型:int strcmp(const char *s1,const char * s2);
功能:比较字符串s1和s2。
返回值:当s1<s2时,返回值<0
当s1==s2时,返回值=0
当s1>s2时,返回值>0
*/
int strcmp(const char *src, const char *dest)
{
const char *p = src;
const char *t = dest;
assert((src==NULL)&&(dest==NULL));
while(*p == *t)
{
if((*p=='\0')&&(*t=='\0'))
return 0;
p++;
t++;
}
if(*p>*t) return 1;
else return -1;
}