1.c风格字符串:没啥好说的
2.一些标准库提供的字符串处理函数
strlen函数:
自定义函数实现strlen的功能:
#include
#include
#include
using namespace std;
int strlen_1(const char *str)
{
assert(str != NULL);
int len = 0;
while(*(str++) != '\0')
len++;
return len;
}
int strlen_2(const char *str)
{
assert(str != NULL);
return *str == '\0' ? 0 : (1 + strlen_2(++str));
}
int main()
{
char *a = "hhh";
cout << strlen_1(a) << endl;
cout << strlen_2(a) << endl;
return 0;
}
n = 4 x[4] == '\0' *x = '\0' x++
所以就显而易见了
strcmp函数:
自定义实现:
int strcmp(const char *str1, const char *str2)
{
assert(str1 != NULL && str2 != NULL)
int ret = 0;
while(!(ret = *(unsigned char *)str1 - *(unsigned char *)str2) && *str1)
{
str1++;
str2++;
}
if(ret < 0)
ret = -1;
else
ret = 1;
return ret;
}
strcat和strcpy函数:
自定义实现strcat:
char *strcat(char *strDest, const char *strSrc)
{
char *adr = strDest;
assert(strDest != NULL && strSrc != NULL);
while(*strDest)
{
strDest++;
}
while(*strDest++ = *strSrc++);
return adr;
}
自定义实现strcpy:
char *strcpy(char *strDest, const char *strSrc)
{
assert(strDest != NULL && strSrc != NULL);
char *adr = strDest;
while((*strDest++ = *strSrc++) != '\0'))
return adr;
}
memcpy函数:
void *memcpy(void *dest, const void *src, size_t n);
请简述strcpy和memcpy的区别?
1).复制的内容不同,strcpy只能复制字符串,而memcpy能够复制任意内容。
2).strcpy不需要指定长度。
3)用途不同
memset函数:
void *memset(void *s, int ch, size_t n);
2.字符串的包含问题
1)串的模式匹配算法:查找子串
使用最基础的算法(BF算法)
char *strFind(const char *str, const char *substr)
{
assert(str != NULL && substr != NULL);
int m = strlen(str);
int n = strlen(substr);
if(m < n)
return NULL;
for(int i = 0; i <= m - n; i++)
{
int j = 0;
for(; j < n; j++)
{
if(str[i + j] != substr[j])
break;
}
if(j == n)
return str + i;
}
return NULL;
}
KMP算法:
原理参考:http://www.cnblogs.com/SYCstudio/p/7194315.html
算法复杂度为O(M+N)
//计算next数组的函数
void get_nextval(char const *ptrn, int plen, int *nextval)
{
int i = 0;
nextval[i] = -1;
int j = -1;
while(i < plen - 1)
{
if(j == -1 || ptrn[i] == ptrn[j])
{
++i;
++j;
nextval[i] = j;
}
else
{
j = nextval[j];
}
}
}
//改进的计算next数组的函数
void get_nextval(char const *ptrn, int plen, int nextval)
{
int i = 0;
nextval[i] = -1;
int j = -1;
while(i < plen - 1)
{
if(j == -1 || ptrn[i] == ptrn[j])
{
++i;
++j;
if(ptrn[i] != ptrn[j])
nextval[i] = j;
else
{
nextval[i] = nextval[j];
}
}
else
{
j = nextval[j];
}
}
}
int kmp_search(const char *src, int slen, const char *patn, int plen, const int *nextval, int pos)
{
int i = pos, j = 0;
while(i < slen && j < plen)
{
if(j == -1 || src[i] == patn[j])
{
++i;
++j;
}
else
{
j = nextval[j]; //当匹配失败时直接用p[j_next]与s[i]比较
}
}
if(j >= plen)
return i - plen;
else
return -1;
}
3.字符串的移位包含问题:
其实就是s1s1中求是否包含s2
4.字符串转换为数字
atoi函数 itoa函数
#include
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
long long atoq(const char *nptr);
char *itoa( int value, char *string,int radix);
以及c++11
std::string to_string(int value);
std::string to_string(long int value);
std::string to_string(long long int value);
std::string to_string(unsigned int value);
std::string to_string(unsigned long long int value);
std::string to_string(float value);
std::string to_string(double value);
std::wstring to_wstring(int value);
std::wstring to_wstring(long int value);
std::wstring to_wstring(long long int value);
std::wstring to_wstring(unsigned int value);
std::wstring to_wstring(unsigned long long int value);
std::wstring to_wstring(float value);
std::wstring to_wstring(double value);
std::string str = "1000";
int val = std::stoi(str);
long val = std::stol(str);
float val = std::stof(str);
atoi: 将字符串转换为 int
atol: 将字符串转换为long
atoll:将字符串转换为 long long
atof: 将字符串转换为浮点数
宽窄字符转换
std::wstring wide_str = L"中国人";
std::wstring_convert>
converter(new std::codecvt("CHS");
std::string narrow_str = converter.to_bytes(wide_str);
std::wstring wstr = converter.from_bytes(narrow_str);
std::cout << narrow_str << std::endl;
wcout.imbue(std::locale("chs"));
std::wcout << wstr << std::endl;
std::cout << wstr.size() << " " << wstr.length() << endl;
std::cout << narrow_str.size() << " " << narrow_str.length() << endl;
itoa c实现:
#include
#include
int atoi (char s[]);
int main(void )
{
char s[100];
gets(s);
printf("integer=%d\n",atoi(s));
return 0;
}
int atoi (char s[])
{
int i,n,sign;
for(i=0;isspace(s[i]);i++)//跳过空白符;
sign=(s[i]=='-')?-1:1;
if(s[i]=='+'||s[i]==' -')//跳过符号
i++;
for(n=0;isdigit(s[i]);i++)
n=10*n+(s[i]-'0');//将数字字符转换成整形数字
return sign *n;
}
atoi c实现:转自编程珠玑公众号
#include
#include
#include
#include
#define NULL_PTR_ERR 1
#define ERANGE 2
int errCode = 0;
int my_atoi(char* str) {
int negative = 0;
char c = 0;
/*计算结果存储*/
long long ret = 0;
errCode = 0;
if(NULL == str)
{
errCode = NULL_PTR_ERR;
return 0;
}
/*跳过开始的空格*/
while(' ' == (*str))
str++;
/*跳过空格之后,到达了字符串结尾,则退出*/
if(0 == *str)
return 0;
/*负数*/
if(*str == '-' )
{
negative = 1;
str++;
}
/*正数*/
else if(*str == '+')
{
negative = 0;
str++;
}
/*正数*/
else if(isdigit(*str))
{
negative = 0;
}
/*如果不是以上内容,则直接退出*/
else
{
return 0;
}
while(isdigit(*str))
{
/*计算结果*/
ret = ret*10 + *str -'0';
/*如果发现结果大于INT_MAX或者小于INT_MIN,则溢出,返回最值*/
if(ret > (negative?-(long long )INT_MIN:INT_MAX))
{
/*溢出,返回最大值*/
errCode = ERANGE;
return negative?INT_MIN:INT_MAX;
}
str++;
}
/*根据正负号返回正确的结果*/
return negative?-ret:ret;
}
int main(void)
{
/*只有一个负号*/
int result = my_atoi("-");
printf("-:%d,errCode:%d\n",result,errCode);
/*空指针*/
result = my_atoi(NULL);
printf("NULL:%d,errCode:%d\n",result,errCode);
/*空字符串*/
result = my_atoi(" ");
printf(" :%d,errCode:%d\n",result,errCode);
/*负数*/
result = my_atoi("-1");
printf(" -1:%d,errCode:%d\n",result,errCode);
/*负数溢出*/
result = my_atoi(" -11111111111");
printf(" -11111111111:%d,errCode:%d\n",result,errCode);
/*正数*/
result = my_atoi("+123");
printf("+123:%d,errCode:%d\n",result,errCode);
/*正数溢出*/
result = my_atoi("+123111111111111111");
printf("+123111111111111111:%d,errCode:%d\n",result,errCode);
return 0;
}
如何写出一个不含bug的itoa和atoi函数其实也挺考功夫的。
一个tx2018年的笔试题
/*
题目描述
有两个用字符串表示的非常大的大整数,算出他们的乘积,也是用字符串表示。不能用系统自带的大整数类型。
输入描述:
空格分隔的两个字符串,代表输入的两个大整数
输出描述:
输入的乘积,用字符串表示
示例1
输入
72106547548473106236 982161082972751393
输出
70820244829634538040848656466105986748
*/
#include
#include
using namespace std;
//移位进位法
string Mul(string left, string right)
{
size_t Lsize = left.size();
size_t Rsize = right.size();
size_t Size = Lsize + Rsize;
string res(Size, '0');
int takevoer = 0;//进位
int offset = 0;//移位
size_t idx = 1, j = 1;
for (idx = 1; idx <= Rsize; ++idx)
{
takevoer = 0;
int rightnum = right[Rsize - idx] - '0';
//计算每一位与left相乘
for (j = 1; j <= Lsize; ++j)
{
char resBit = res[Size - j - offset] - '0';
int num = rightnum * (left[Lsize - j] - '0') + takevoer + resBit;
takevoer = num / 10;
res[Size - j - offset] = num % 10 + '0';
}
if (takevoer != 0)
res[Size - j - offset] = takevoer + '0';
offset++;
}
//如果没有进位的话,res最高位没有数字
if (res[0] == '0')
res.erase(0, 1);
return res;
}
int main()
{
string s1, s2;
cin >>s1 >> s2;
string str=Mul(s1,s2);
cout << str << endl;
}
关于字符串的题有很多,可以去LeetCode上去刷一刷。