C/C++字符数组和字符串的区别和联系,字符串拼接,比较,分割,复制

一、字符数组、字符串和C++string类区别

在C/C++中,字符串和字符数组通常会有以下几种表示

char a[] = {'a','b','c','d','e','f'};    //字符数组
char b[]="abcdef";                       //字符串
char *c = (char*)"abcdef";               //字符串
string d = b;                            //C++string类
//string类可接受char * 和char[]的直接赋值
//但是反过来就不可以

cout<<"sizeof(a): "<<sizeof(a)<<endl;
cout<<"sizeof(b): "<<sizeof(b)<<endl;
cout<<"sizeof(c): "<<sizeof(c)<<endl;
cout<<"sizeof(d): "<<sizeof(d)<<endl;

// cout<<a<<endl;                         //输出这个会有一堆乱码
char a1[] = {'a','b','c','d','e','f','\0'};
cout<<a1<<endl;                           //正常输出

cout<<"length of b: "<<strlen(b)<<endl;
cout<<"length of c: "<<strlen(c)<<endl;
cout<<"length of d: "<<d.length()<<endl;

/*
sizeof(a): 6
sizeof(b): 7
sizeof(c): 4
sizeof(d): 4
abcdef
length of b: 6
length of c: 6
length of d: 6
*/

说明:

    1.上面的打印结果字符串b比字符数组a大1,是因为字符串默认结尾有一个'\0'字符,标志结束

    2.我们看到c和d的大小都是4, 说明c和d都是一个指针

    3.当我们直接输出字符串数组是,会出现乱码,且程序无法继续向下运行,是因为,C/C++中字符数组边界是没有约束的,cout时会越界输出乱码。

    4.当我们往字符数组后面加一个'\0'时,cout的时候可以识别到结束,能正常输出

二、C/C++字符串和C++string类的操作不同

字符串可以看成是对字符数组的封装,同样,string类是C++中特有的对字符数组的封装,提供了一些易于操作的函数:

1.用于C字符串的函数:

size_t  strlen(char const *  str)                                               求字符串长度

int      strcmp(char const * str1, char const * str2)                 比较字符串

char * strcat(char *dest, char const *src)                               拼接两个字符串

char * strcpy(char * dest, char const * src)                            复制字符串

char * strtok(char * str, char const * delimiter)                     分割字符串

char * strchr(char * const  str, int const c)                             查找字符串中的字符

char * strncat(char * dest, char const * src, size_t count)      拼接src字符串中的前n个

char * strncpy(char * dest, char const * src, size_t count)     与src字符串中的前n个复制

char str1[50] = "give me ";
char str2[50] = "a cup";

cout<<strlen(str1)<<endl;
cout<<strlen(str2)<<endl;
/*
输出:
8
5
*/

strcat(str1,  str2);
cout<<str1<<endl;
strncat(str1, " of coffee a", 10);
cout<<str1<<endl;
/*
give me a cup
give me a cup of coffee
*/

strcpy(str2, str1);
cout<<str2<<endl;
strncpy(str1, str2, 15);
cout<<str1<<endl;
/*
give me a cup of coffee
give me a cup of coffee
*/

cout<<"compare result = "<<strcmp(str1, str2)<<endl;
//compare result = 0

char * res = strchr(str1, 'e');
cout<<*res<<endl;
cout<<*(res+2)<<endl;

//e
//m


// 获取第一个子字符串 
char * token = strtok(str1, " ");
//继续获取其他的子字符串 
while( token != NULL ) {
   printf( "%s  ", token );
   token = strtok(NULL, " ");
}

//give  me  a  cup  of  coffee

说明:

    当我们使用strcat, strcpy的时候一定要注意dest字符串的大小一定要大于拼接后或复制后字符串的大小,否则可能造成内存冲突

    另外,C++11标准后推出strcat_s()方法,_s的意思就是safe,安全模式,他首先会检查缓存区的大小是否大于结果的大小,以免对内存的其他数据产生影响。而且在Visual Studio2017中上述函数不被支持,可以使用strcat_s()。

    int strcat_s(char *restrict dest, rsize_t destsz, const char *restrict src);

    其中,destsz一般填sizeof(dest), 即告诉编译器dest的大小,若拼接后结果大于该数值,则产生错误,不会对其他数据产生影响。

    同理,也有strcpy_s, strtok_s等。

2.string类的函数

   很遗憾。C++标准库里面没有字符分割函数split

(1)字符串长度

    i. str.length()

(2)字符串拼接

    i. str = str1+ str2 直接相加,由于string类重载了+运算符,所以可以直接相加,跟python类似

    ii. str1.append(const char * str2) 

    iii. str1.append(const char *  str2,   int start,   int num)

    start代表开始的下标,num代表append的字符数

(3)字符串比较

    i. str1.compare(str2)

    ii. str1==str2 或者使用 >, <,>=, <=, !=, 返回True或者False

(4)字符串删除某段

    i. str.erase(int start,  int num)

    ii. str.erase(str.begin()+i, str.begin()+j)

    后者跟vector的一样:vect.erase(vect.begin()+i, vect.begin()+j)

(5)截取子字符串

    substring = str.substr(int start,   int num)

(6)插入字符串

    i. str1.insert(int start,   const char * str2)

    ii. str1.insert(int start,   const char * str2,   int str2_start,   int num)

 (7)替换字符串

    i. str1.replace(int str1_start,  int num1,  const char * str2,  int str2_start,  int num2)

    将str1中从str1_start开始的num1个字符替换为str2中从str2_start2开始的num2个字符

(8)查找字符串

    str1.find(const char * str2, int str1_start)   ->返回下标 ,   找不到的话返回 -1 

(9)copy函数

    很有趣的是这个copy函数跟strcpy不太一样,它是将string类的内容拷贝到字符串中

    str1.copy(char *  str2, int num,, int str1_start)

    这里的str2不能替换成string类的对象,这是跟上面8个函数所不同的, 上面8个char * 可以替换成string类对象。

(10)string类转换成普通C字符串

    str1.c_str()

string str1 = "give me";
string str2 = " a cup";
str1.append(str2);
cout<<str1<<endl;
//give me a cup

str1.replace(0,1, "Give", 0,1);
cout<<str1<<endl;
//Give me a cup

str1.insert(0, "abc", 1, 2);
cout<<str1<<endl;
//bcGive me a cup

str1.erase(1,1);
cout<<str1<<endl;
//bGive me a cup

int index = str1.find("ve", 0);
cout<<"index="<<index<<endl;
//index=3

const char* str4;
str4 = str1.c_str();
string a = str4;
cout<<a<<endl;
//bGive me a cup

//拷贝,将string对象的内容拷贝到普通C字符串中
char str3[10] = "defg";
str1.copy(str3, 7, 1);
cout<<str3<<endl;
//Give me

string类里面的设计思想不会使用int start , int end,这样的取子字符串的方式,而是int start , int num,这个常常会让人搞混。

3.字符串和int类型,float类型等互相转换

#include<sstream>

//const char *类型转换成int类型 ,a-to-int -> atoi
int a;
a = std::atoi("11");
cout<<a<<endl;

//const char *类型转换成float类型 ,a-to-float -> atof
float b;
b = std::atof("11.12");
cout<<b<<endl;

//int类型转换成string类型
string c;
ostringstream ostr;
ostr << "I am a string:"<< a ;
c = ostr.str();
cout<<c<<endl;

/*输出:
11
11.12
I am a string:11
*/

//char *类型转换成double类型
char str[30] = "2030300 This is test";
char *ptr;
long ret;
ret = strtol(str, &ptr, 10);
printf("数字(无符号长整数)是 %ld\n", ret);
printf("字符串部分是 |%s|", ptr);

/*输出:
数字(无符号长整数)是 2030300
字符串部分是 | This is test|
*/
原创文章 26 获赞 33 访问量 1918

猜你喜欢

转载自blog.csdn.net/qq_40765537/article/details/105187341