特别鸣谢由张老师整理(原出处未知

一、C++ 字符串

C++ 提供了以下两种类型的字符串表示形式:

C 风格字符串

C++ 引入的 string 类类型

1、C 风格字符串

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

下面的声明和初始化创建了一个 "Hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

依据数组初始化规则,您可以把上面的语句写成以下语句:

char greeting[] = "Hello";

以下是 C/C++ 中定义的字符串的内存表示:

![C/C++ 中的字符串表示](file:///C:/Users/user/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)

其实,您不需要把 null 字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 '\0' 放在字符串的末尾。

C++ 中有大量的函数用来操作 null 结尾的字符串:

strcpy(s1, s2); 复制字符串 s2 到字符串 s1。

strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。

strlen(s1); 返回字符串 s1 的长度。

strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。

strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。

strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

2.string类型变量的声明与初始化

首先,为了在程序中使用string类型,必须包含头文件 。如下:

#include

注意这里不是string.h,string.h是C字符串头文件。

string类是一个模板类,位于名字空间std中,通常为方便使用还需要增加:

using namespace std;

声明一个字符串变量很简单:

string str;

示例代码:(下面的代码演示了string类型变量的声明与初始化操作的方法,注意与char类型的字符串比较)

#include <iostream>
#include <string>
using namespace std;
int main ( )
{
string str; //定义了一个空字符串str
str = "Hello world";// 给str赋值为"Hello world"
char cstr[] = "abcde"; //定义了一个C字符串
string s1(str); //调用复制构造函数生成s1,s1为str的复制品
cout<<s1<<endl;
string s2(str,6); //将str内,开始于位置6的部分当作s2的初值
cout<<s2<<endl;
string s3(str,6,3);//将str内,开始于6且长度顶多为3的部分作为s3的初值
cout<<s3<<endl;
string s4(cstr);//将C字符串作为s4的初值
cout<<s4<<endl;
string s5(cstr,3); //将C字符串前3个字符作为字符串s5的初值。
cout<<s5<<endl;
string s6(5,'A'); //生成一个字符串,包含5个'A'字符
cout<<s6<<endl;
string s7(str.begin(),str.begin()+5);
//区间str.begin()和str.begin()+5内的字符作为初值
cout<<s7<<endl;
return 0;
}

结果:

Hello world

world

wor

abcde

abc

AAAAA

Hello

二、string的比较等操作

你可以用 ==、>、<、>=、<=、和!=比较字符串,可以用+或者+=操作符连接两个字符串,并且可以用[]获取特定的字符。

#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cout << "Please input your name:"<<endl;
cin >> str;
if( str == "Li" )// 字符串相等比较
cout << "you are Li!"<<endl;
else if( str != "Wang" ) // 字符串不等比较
cout << "you are not Wang!"<<endl;
else if( str < "Li") // 字符串小于比较,>、>=、<=类似
cout << "your name should be ahead of Li"<<endl;
else
cout << "your name should be after of Li"<<endl;
str += ", Welcome!"; // 字符串+=
cout << str<<endl;
for(int i = 0 ; i < str.size(); i ++)
cout<<str[i]; // 类似数组,通过[]获取特定的字符
return 0;
}

结果:

Please input your name:

Zhang↙

you are not Wang!

Zhang, Welcome!

Zhang, Welcome!

上例中,“ cout<< str[i]; ”可换为: cout<< str.at(i);

三、string特性描述

可用下列函数来获得string的一些特性:

int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)

int max_size()const; //返回string对象中可存放的最大字符串的长度

int size()const; //返回当前字符串的字节数,与length()没有区别,是作为STL容器的属性而存在,便于符合STL的接口规则。

int length()const; //返回当前字符串的字节数,与size()的功能没有区别

bool empty()const; //当前字符串是否为空

void resize(int len,char c); //把字符串当前大小置为len,多去少补,多出的字符c填充不足的部分

测试代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
if (str.empty())
cout<<"str is NULL."<<endl;
else
cout<<"str is not NULL."<<endl;
str = str + "abcdefg";
cout<<"str is "<<str<<endl;
cout<<"str's size is "<<str.size()<<endl;
   cout<<"str's capacity is "<<str.capacity()<<endl;
cout<<"str's max size is "<<str.max_size()<<endl;
cout<<"str's length is "<<str.length()<<endl;
str.resize(20,'c');
cout<<"str is "<<str<<endl;
str.resize(5);
cout<<"str is "<<str<<endl;
return 0;
}

程序执行结果为:

str is NULL.

str is abcdefg

str's size is 7

str's capacity is 15

str's max size is 4294967294

str's length is 7

str is abcdefgccc

str is abcde

四、string的查找

由于查找是使用最为频繁的功能之一,string提供了非常丰富的查找函数:(注:string::npos)

size_type find( const basic_string &str, size_type index );

//返回str在字符串中第一次出现的位置(从index开始查找),如果没找到则返回string::npos

size_type find( const char *str, size_type index ); // 同上

size_type find( const char *str, size_type index, size_type length );

//返回str在字符串中第一次出现的位置(从index开始查找,长度为length),如果没找到就返回string::npos

size_type find( char ch, size_type index );

// 返回字符ch在字符串中第一次出现的位置(从index开始查找),如果没找到就返回string::npos

注意:查找字符串a是否包含子串b,不是用 strA.find(strB) > 0 而是 strA.find(strB) != string::npos 这是为什么呢?(初学者比较容易犯的一个错误)

  先看下面的代码

int idx = str.find("abc");

if (idx == string::npos);

  上述代码中,idx的类型被定义为int,这是错误的,即使定义为 unsigned int 也是错的,它必须定义为 string::size_type。npos 是这样定义的: static const size_type npos = -1; 因为 string::size_type (由字符串配置器 allocator 定义) 描述的是 size,故需为无符号整数型别。因为缺省配置器以型别 size_t 作为 size_type,于是 -1 被转换为无符号整数型别,npos 也就成了该型别的最大无符号值。不过实际数值还是取决于型别 size_type 的实际定义。不幸的是这些最大值都不相同。事实上,(unsigned long)-1 和 (unsigned short)-1 不同(前提是两者型别大小不同)。因此,比较式 idx == string::npos 中,如果 idx 的值为-1,由于 idx 和字符串string::npos 型别不同,比较结果可能得到 false。因此要想判断 find()等查找函数的结果是否为npos,最好的办法是直接比较。

测试代码:

#include<iostream>
#include<string>
using namespace std;
int main(){
int loc;
string s="study hard and make progress everyday! every day!!";
loc=s.rfind("make",10);
cout<<"the word make is at index"<<loc<<endl;//-1表示没找到
loc=s.rfind("make");//缺省状态下,从最后一个往前找
cout<<"the word make is at index"<<loc<<endl;
loc=s.find_first_of("day");
cout<<"the word day(first) is at index "<<loc<<endl;
loc=s.find_first_not_of("study");
cout<<"the first word not of study is at index"<<loc<<endl;
loc=s.find_last_of("day");
cout<<"the last word of day is at index"<<loc<<endl;
loc=s.find("day");//缺陷状态下从第一个往后找
cout<<loc;
return 0;
}

运行结果:

meiyou

五、其他常用函数

string &insert(int p,const string &s); //在p位置插入字符串s

string &replace(int p, int n,const char *s); //删除从p开始的n个字符,然后在p处插入串s

string &erase(int p, int n); //删除p开始的n个字符,返回修改后的字符串

string substr(int pos = 0,int n = npos) const; //返回pos开始的n个字符组成的字符串

void swap(string &s2); //交换当前字符串与s2的值

string &append(const char *s);//把字符串s连接到当前字符串结尾

void push_back(char c)//当前字符串尾部加一个字符c

const char data()const;//返回一个非null终止的c字符数组,data():与c_str()类似,用于string转const char其中它返回的数组是不以空字符终止,

例:string s1="1234567890"; char const * ss =s1.data(); //ss中的值为s1的字符串

const char c_str()const; //返回一个以null终止的c字符串,即c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同,用于string转const char

测试代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 = "abc123defg";
string str2 = "swap!";
cout<<str1<<endl;
cout<<str1.erase(3,3)<<endl; //从索引3开始的3个字符,即删除掉了"123"
cout<<str1.insert(0,"123")<<endl; //在头部插入
cout<<str1.append("123")<<endl;//append()方法可以添加字符串
str1.push_back('A'); //push_back()方法只能添加一个字符
cout<<str1<<endl;
cout<<str1.replace(0,3,"hello")<<endl;
//即将索引0开始的3个字符替换成"hello"
cout<<str1.substr(5,7)<<endl; //从索引5开始7个字节
str1.swap(str2);
cout<<str1<<endl;
const char* p = str.c_str();
printf("%s\n",p);
return 0;
}

程序执行结果为:

abc123defg

abcdefg

123abcdefg

123abcdefg123

123abcdefg123A

helloabcdefg123A

abcdefg

swap!

swap!

六、与字符串相关的其它函数

1.转换字符串为整数stoi,stol,stoll

例如:  std::string str1 = "45";   int myint1 = std::stoi(str1);

2. std::atoi, std::atol, std::atoll

与上述转换string为整数类似的函数还有std::atoi, std::atol, std::atoll 成功时为对应 str 内容的整数值。

    const char *str1 = "3.14159";

​ int num1 = std::atoi(str1);

std::cout << "std::atoi("" << str1 << "") is " << num1 << '\n';

输出:

std::atoi("3.14159") is 3

3. std::to_string

std::string to_string( int value );

std::string to_string( float value );

返回值:一个包含转换后值的字符串

4.std::ctype::tolower, std::ctype::toupper

两个C风格的字符大小写转换函数 std::ctype::tolower, std::ctype::toupper 注意:这两个函数不能用于string类的字符串,只能转换 char类型的字符。

void try_lower(const std::ctype<wchar_t>& f, wchar_t c)

{

​ wchar_t up = f.tolower(c);

​ if (up != c) {

std::wcout << "Lower case form of '" << c << "' is " << up << '\n';

​ } else {

std::wcout << ''' << c << "' has no lower case form\n";

​ }

}

5. c++ transform用法 大小写转换

#include

#include

using namespace std;

char op(char ch)

{ if(ch>='A'&&ch<='Z') return ch+32;

​ else return ch;

}

int main()

{

​ string first,second;

​ cin>>first;

​ second.resize(first.size());

​ transform(first.begin(),first.end(),second.begin(),op);

​ cout<<second<<endl;

​ return 0;

}

6. std::reverse STL函数

可用于反转string以及一些STL容器中的元素。

void reverse( BidirIt first, BidirIt last );

反转 [first, last) 范围中的元素顺序

std::vector v{1,2,3};

std::reverse(std::begin(v), std::end(v));

7. 有两个”XXprintf”函数

sprintf和snprintf,从给定位置加载数据,转换为字符串等价版本,并将结果写入各种池。

sprintf指的是字符串格式化命令,主要功能是把格式化的数据写入某个字符串中。sprintf 是个变参函数。

注意:使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。解决这个问题,可以考虑使用 snprintf函数,该函数可对写入字符数做出限制。类似问题的函数还有strcpy()、strcat(),其对应的安全版为:strncpy() 、strncat()。

1int sprintf( char* buffer, const char* format, ... );

写结果到字符串 buffer 。

2int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );

写结果到字符串 buffer 。至多写 buf_size - 1 个字符。产生的字符串会以空字符终止,除非 buf_size 为零。若 buf_size 为零,则不写入任何内容,且 buffer 可以是空指针,然而依旧计算返回值(会写入的字符数,不包含空终止符)并返回。

参数说明:

buffer - 指向要写入的字符串的指针

format - 指向指定如何转译数据的空终止多字节字符串的指针。

格式字符串由普通多字节字符(除了 % )和转换指定构成,前者被复制到输出流而无更改。每个转换指定拥有下列格式:

示例代码:
double num=3.1415926;
cout <<"double num="<< num <<endl; //输出:
char *s ;
sprintf( s,"%.4lf",num);
cout << "sprintf( s,\"%.4lf\",num) -> s=" <<s<<endl;
return 0;
运行结果:
double num=3.14159
sprintf( s,"%.4lf",num) -> s=3.1416
示例代码:
char a[16];
size_t i;
i = snprintf(a, 13, "%012d", 12345); // 第 1 种情况
printf("i = %lu, a = %s\n", i, a); // 输出:i = 12, a = 000000012345
i = snprintf(a, 9, "%012d", 12345); // 第 2 种情况
printf("i = %lu, a = %s\n", i, a); // 输出:i = 12, a = 00000001

函数的用法与区别

1、cin>>

用法1:最基本,也是最常用的用法,输入一个数字:

#include

using namespace std;

main ()

{

int a,b;

cin>>a>>b;

cout<<a+b<<endl;

}

输入:2[回车]3[回车] 输出:5

用法2:接受一个字符串,遇“空格”、“TAB”、“回车”都结束

#include

using namespace std;

main ()

{

char a[20];

cin>>a;

cout<<a<<endl;

}

输入:jkljkljkl 输出:jkljkljkl

输入:jkljkl jkljkl //遇空格结束,所以不能输入多个单词 输出:jkljkl

2、cin.get()

用法1: cin.get(字符变量名)可以用来接收字符

#include

using namespace std;

main ()

{

char ch;

ch=cin.get(); //或者cin.get(ch);只能获取一个字符

cout<<ch<<endl;

}

输入:jljkljkl 输出:j

用法2:cin.get(字符数组名,接收字符数目)

用来接收一行字符串,可以接收空格

#include

using namespace std;

main ()

{

char a[20];

cin.get(a,20); //有些类似getline。可以输入多个单词,中间空格隔开。

cout<<a<<endl;

}

输入:jkl jkl jkl 输出:jkl jkl jkl

输入:abcdeabcdeabcdeabcdeabcde (输入25个字符)

输出:abcdeabcdeabcdeabcd (接收19个字符+1个'\0')

用法3:cin.get(无参数)

没有参数主要是用于舍弃输入流中的不需要的字符,或者舍弃回车,弥补cin.get(字符数组名,接收字符数目)的不足.

3、cin.getline() //接受一个字符串,可以接收空格并输出

#include

using namespace std;

main ()

{

char m[20];

cin.getline(m,5); //与上面基本相同。

cout<<m<<endl;

}

输入:jkljkljkl 输出:jklj

接受5个字符到m中,其中最后一个为'\0',所以只看到4个字符输出;

如果把5改成20:

输入:jkljkljkl 输出:jkljkljkl

输入:jklf fjlsjf fjsdklf 输出:jklf fjlsjf fjsdklf

//延伸:

//cin.getline()实际上有三个参数,cin.getline(接受字符串到m,接受个数5,结束字符)

//当第三个参数省略时,系统默认为'\0' 是‘/n’吧。

//如果将例子中cin.getline()改为cin.getline(m,5,'a');当输入jlkjkljkl时输出jklj,输入jkaljkljkl时,输出jk

当用在多维数组中的时候,也可以用cin.getline(m[i],20)之类的用法:

#include

#include

using namespace std;

main ()

{

char m[3][20];

for(int i=0;i<3;i++)

{

cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;

cin.getline(m[i],20);

}

cout<<endl;

for(int j=0;j<3;j++)

cout<<"输出m["<<j<<"]的值:"<<m[j]<<endl;

}

请输入第1个字符串:kskr1

请输入第2个字符串:kskr2

请输入第3个字符串:kskr3

输出m[0]的值:kskr1

输出m[1]的值:kskr2

输出m[2]的值:kskr3

4、getline() // 接受一个字符串,可以接收空格并输出,需包含“#include”

#include

#include

using namespace std;

main ()

{

string str;

getline(cin,str);

cout<<str<<endl;

}

输入:jkljkljkl //VC6中有个bug,需要输入两次回车。 输出:jkljkljkl

输入:jkl jfksldfj jklsjfl 输出:jkl jfksldfj jklsjfl

和cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数

5、gets() // 接受一个字符串,可以接收空格并输出,需包含“#include”

#include

#include

using namespace std;

main ()

{

char m[20];

gets(m); //不能写成m=gets();

cout<<m<<endl;

}

输入:jkljkljkl 输出:jkljkljkl

输入:jkl jkl jkl 输出:jkl jkl jkl

类似cin.getline()里面的一个例子,gets()同样可以用在多维数组里面:

#include

#include

using namespace std;

main ()

{

char m[3][20];

for(int i=0;i<3;i++)

{

cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;

gets(m[i]);

}

cout<<endl;

for(int j=0;j<3;j++)

cout<<"输出m["<<j<<"]的值:"<<m[j]<<endl;

}

请输入第1个字符串:kskr1

请输入第2个字符串:kskr2

请输入第3个字符串:kskr3

输出m[0]的值:kskr1

输出m[1]的值:kskr2

输出m[2]的值:kskr3

自我感觉gets()和cin.getline()的用法很类似,只不过cin.getline()多一个参数罢了;

这里顺带说明一下,对于本文中的这个kskr1,kskr2,kskr3的例子,对于cin>>也可以适用,原因是这里输入的没有空格,如果输入了空格,比如“ks kr jkl[回车]”那么cin就会已经接收到3个字符串,“ks,kr,jkl”;再如“kskr 1[回车]kskr 2[回车]”,那么则接收“kskr,1,kskr”;这不是我们所要的结果!而cin.getline()和gets()因为可以接收空格,所以不会产生这个错误;

6、getchar() //接受一个字符,需包含“#include”

#include

using namespace std;

main ()

{

char ch;

ch=getchar(); //不能写成getchar(ch);

cout<<ch<<endl;

}

输入:jkljkljkl 输出:j

//getchar()是C语言的函数,C++也可以兼容,但是尽量不用或少用;

关于c-string类的更多相关文章

  1. 标准库String类

    下面的程序并没有把String类的所有成员方法实现,只参考教程写了大部分重要的成员函数. [cpp] view plain copy #include<iostream> #include ...

  2. 自己实现简单的string类

    1.前言 最近看了下<C++Primer>,觉得受益匪浅.不过纸上得来终觉浅,觉知此事须躬行.今天看了类类型,书中简单实现了String类,自己以前也学过C++,不过说来惭愧,以前都是用C ...

  3. C++ string类的实现

    c++中string类的实现 今天面试被考到了, 全给忘记了!!!   //string类的实现 #include <iostream> #include <string.h> ...

  4. String类的功能

    String类              标红的为较少出现的 1.判断功能 boolean equals(Object obj) :比较字符串内容是否相同,区分大小写 boolean equalsIg ...

  5. java基础复习:final,static,以及String类

    2.final 1)为啥String是final修饰的呢? 自己答: 答案: 主要是为了“效率” 和 “安全性” 的缘故.若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所 ...

  6. String类和StringBuffer类的区别

    首先,String和StringBuffer主要有2个区别: (1)String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,释放原String对象,StringB ...

  7. 05_整理String类的Length()、charAt()、 getChars()、replace()、 toUpperCase()、 toLowerCase()、trim()、toCharArray()使用说明

    Question: 整理String类的Length().charAt(). getChars().replace(). toUpperCase(). toLowerCase().trim().toC ...

  8. 标准C++中的string类的用法总结

    标准C++中的string类的用法总结 相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有 ...

  9. String类常用方法

    1.String类的特点,字符串一旦被初始化就不会被改变. 2.String对象定义的两种方式 ①String s = "affdf";这种定义方式是在字符串常量池中创建一个Str ...

  10. 运用String类实现一个模拟用户登录程序

    package Test; import java.util.Scanner; // 模拟用户登录程序 // 思路: // 1.用两个String类分别接收用户名和密码 // 2.判断输入的用户名和密 ...

随机推荐

  1. VHDL之concurrent之when

    WHEN (simple and selected) It is one of the fundamental concurrent statements (along with operators ...

  2. C++编译错误fatal error C1004: 发现意外的文件尾

    出现这种情况就是类或者结构体的定义后面没有加“;”导致的. 而且这种问题好难排查.

  3. 【sqli-labs】 less38 GET -Stacked Query Injection -String based (GET型堆叠查询字符型注入)

    这个直接用union select就可以 http://192.168.136.128/sqli-labs-master/Less-38/?id=0' union select 1,2,3%23 看一 ...

  4. EF test

    LibraryEntities db = new LibraryEntities(); private void btnSelect_Click(object sender, EventArgs e) ...

  5. python爬虫05 | 年轻人,不会正则表达式你睡得着觉?有点出息没有?

    现在 你已经会使用 python 模拟浏览器 进行一些 Http 的请求了 那么请求完之后 服务器返回给我们一堆源代码 我们可不是啥都要的啊 我们是有原则的 我们想要的东西 怎么能一股脑的啥都往自己兜 ...

  6. 【hihocoder 1297】数论四·扩展欧几里德

    [题目链接]:http://hihocoder.com/problemset/problem/1297 [题意] [题解] 问题可以转化为数学问题 即(s1+v1*t)%m == (s2+v2*t)% ...

  7. fzu 2136

    #include<stdio.h> #define inf 1000000000 #define N 110000 int a[N]; struct node { int start,en ...

  8. 百度之星2014资格赛 1003 - Xor Sum

    先上代码: Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)T ...

  9. php简单的连接数据库

    <?php $conn=@mysql_connect("localhost","root","") or die ("no& ...

  10. linux下Oracle11g RAC搭建(七)

    linux下Oracle11g RAC搭建(七) 六.安装Grid 启动GRID安装界面 方式一:redhat下调整分辨率 [root@node1 ~]# xhost +       //授权 [ro ...