C++字符串的不同存放类型 (string/char[])

C++中,有两种类型的字符串表示形式:

  • C-风格字符串
  • C++引入的string类

C-风格字符串中有大量的函数用来操作以 null 结尾的字符串:
1    strcpy(s1,s2)    复制字符串 s2 到字符串 s1
2    strcat(s1,s2)    连接字符串 s2 到字符串 s1 的末尾
3    strlen(s1)    返回字符串 s1 的长度
4    strcmp(s1,s2)    返回s1与s2的比较结果
5    strchr(s1,ch)    返回一个指针,指向字符串s1中字符ch的第一次出现的位置
6    strstr(s1,s2)    返回一个指针,指向字符串s1中s2的第一次出现的位置

C++ 中的 String 类,支持上述所有的操作,另外还增加了其他更多的功能。比如:

append() – 在字符串的末尾添加字符
find() – 在字符串中查找字符串
insert() – 插入字符
length() – 返回字符串的长度
replace() – 替换字符串
substr() – 返回某个子字符串

字符串类型

C++中的字符串一般有以下四种类型,

  1. string
  2. char*
  3. const char*
  4. char[]

1、string是一个C++类库中的一个类,它位于名称空间std中。它包含了对字符串的各种常用操作,它较char*的优势是内容可以动态拓展,以及对字符串操作的方便快捷,用+号进行字符串的连接是最常用的操作。

2、char* 是指向字符串的指针(其实严格来说,它是指向字符串的首个字母),你可以让它指向一串常量字符串。

3、const char*该声明指出,指针指向的是一个const char类型,即不能通过当前的指针对字符串的内容作出修改

注意这里有两个概念:

char * const p [指向字符的静态指针]
const char *p [指向静态字符的指针]

const char*const p :表示既禁止修改指针p本身,又禁止修改p所指向的数据。

  • 前者const修饰的是指针,代表不能改变指针 
  • 后者const修饰的是char,代表字符不能改变,但是指针可以变,也就是说该指针可以指针其他的const char。

4、char[]与char*与许多相同点,代表字符数组,可以对应一个字符串,如

char * a="string1"; (新标准c++中这样写会有警告:ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings] )
char b[]="string2";

这里a是一个指向char变量的指针(新标准c++中"string1"默认是常量,const char * a="string1"这样才对),b则是一个char数组(字符数组) 

(PS: 实际上, char * a=”string1”; 的写法是不规范的! 
     因为a指向了即字符常量,一旦strcpy(a,”string2”)就糟糕了,试图向只读的内存区域写入,程序会崩溃的!尽管VS下的编译器不会警告,但如果你使用了语法严谨的Linux下的C编译器GCC,或者在windows下使用MinGW编译器就会得到警告。

所以,我们还是应当按照”类型相同赋值”的原则来写代码: const char * a=”string1”; 
保证意外赋值语句不会通过编译。)

不同点:

一,char*是变量,值可以改变, char[]是常量,值不能改变! 

a是一个char型指针变量,其值(指向)可以改变; 
b是一个char型数组的名字,也是该数组首元素的地址,是常量,其值不可以改变

二,char[]对应的内存区域总是可写,char*指向的区域有时可写,有时只读 

 a指向的是一个字符串常量,即指向的内存区域只读; b始终指向他所代表的数组在内存中的位置,始终可写!

char b[] 的内容存储在函数栈中,可以被修改,函数一旦返回空间就被释放.

总结:char *本身是一个字符指针变量,但是它既可以指向字符串常量,又可以指向字符串变量,指向的类型决定了对应的字符串能不能改变!区别在于:

             1、char*指针指向的内容是可以改变的,是不固定的。赋值后在数据传递的过程中允许改变。

             2、const char*指针指向的内容是固定的,不可改变的。对传入的参数,不会对指针指向的内容进行修改

char * a=”string1”;是实现了3个操作:

声明一个char*变量(也就是声明了一个指向char的指针变量);

  1. 在内存中的文字常量区中开辟了一个空间存储字符串常量”string1”
  2. 返回这个区域的地址,存放在栈中,作为值,赋给这个字符指针变量a
  3. 最终的结果:指针变量a指向了这一个字符串常量“string1” 

(注意,如果这时候我们再执行:char * c=”string1”;则,c==a,实际上,只会执行上述步骤的1和3,因为这个常量已经在内存中创建)

char b[]=”string2”;则是实现了2个操作:

  1. 在常量区存储"string2"
  2. 在栈中,声明一个char 的数组,在栈上分配一个7字节的char数组,然后把常量储存区的那个"Hello World!"复制过来。即将”string2”的每一个字符分别赋值给数组的每一个元素

最终的结果:“数组的值”(注意不是b的值)等于”string2”,而不是b指向一个字符串常量

详情from:https://blog.csdn.net/ksws0292756/article/details/79432329


String

     C++提供了一种新的数据类型——字符串类型(string类型),在使用方法上,它和char、int类型一样,可以用来定义变量,这就是字符串变量——用一个名字代表一个字符序列。实际上,string并不是C++语言本身具有的基本类型,它是在C++标准库中声明的一个字符串类,用这种类可以定义对象。每一个字符串变量都是string类的一个对象。

一、字符串变量的定义和引用

1. 定义字符串变量

和其他类型变量一样,字符串变量必须先定义后使用,定义字符串变量要用类名string。如
string string1; //定义string1为字符串变量
string string2=″China″; //定义string2同时对其初始化

注意: 要使用string类的功能时,必须在本文件的开头将C++标准库中的string头文件包含进来,即应加上
#include <string> //注意头文件名不是string.h

2. 对字符串变量的赋值

在定义了字符串变量后,既可以用字符串常量给字符串变量赋值,也可以用一个字符串变量给另一个字符串变量赋值。如

string1=″Canada″;   string2=string1; //假设string2和string1均已定义为字符串变量,string2和string1长度可以不相同。在定义字符串变量时不需指定长度,长度随其中的字符串长度而改变。

可以对字符串变量中某一字符进行操作,因为它是变量,存在栈中,如

string word=″Then″; //定义并初始化字符串变量word
word[2]=′a′;      //修改序号为2的字符,修改后word的值为″Than″

注意:单引号表示一个字符变量char,双引号表示一个字符数组char[]

(区分字符数组和字符串,一个是C风格,一个是C++类)

3. 字符串变量的输入输出

可以在输入输出语句中用字符串变量名,输入输出字符串,如

cin>> string1; //从键盘输入一个字符串给字符串变量string1
cout<< string2; //将字符串string2输出

二、字符串变量的运算

     在以字符数组存放字符串时,字符串的运算要用字符串函数,如strcat(连接)、strcmp(比较)、strcpy(复制),而对string类对象,可以不用这些函数,而直接用简单的运算符。

  1. 字符串复制用赋值号
        string1=string2;      //其作用与“strcpy(string1,string2);”相同。
  2. 字符串连接用加号
    string string1=″C++″; //定义string1并赋初值
    string string2=″Language″;//定义string2并赋初值
    string1=string1 + string2;//连接string1和string2
    连接后string1为″C++ Language″。
  3. 字符串比较直接用关系运算符
    可以直接用 ==(等于)、>(大于)、<(小于)、!=(不等于)、>=(大于或等于)、<=(小于或等于)等关系运算符来进行字符串的比较。

      比较的时候,从字符串左边开始,一次比较每个字符,直到出现差异、或者其中一个串结束为止。比如ABC与ACDE比较,第一个字符相同,继续比较第二个字符,由于第二个字符是后面一个串大,所以不再继续比较,结果就是后面个串大。再如ABC与ABC123比较,比较三个字符后第一个串结束,所以就是后面一个串大。所以,长度不能直接决定大小字符串的大小是由左边开始最前面的字符决定的。

三、字符串数组

    string不仅可以定义字符串变量,也可以定义字符串数组(是一个数组,数组中每个元素是一个字符串变量)。如

string name[5]; //定义一个字符串数组,它包含5个字符串元素
string name[5]={″Zhang″,″Li″,″Fun″,″Wang″,″Tan″};//定义一个字符串数组并初始化
此时name数组的状况如下图所示。

                            

关于字符串数组的几点说明:

  1. 并不要求每个字符串元素具有相同的长度,即使对同一个元素而言,它的长度也是可以变化的,当向某一个元素重新赋值,其长度就可能发生变化
  2. 在字符串数组的每一个元素中存放一个字符串,而不是一个字符,这是字符串数组与字符数组的区别。如果用字符数组存放字符串,一个元素只能存放一个字符,用一个一维字符数组存放一个字符串。
  3. 每一个字符串元素中只包含字符串本身的字符而不包括′\0′。

分配存储空间:

    实际上,编译系统为每一个字符串变量分配4个字节,在这个存储单元中,并不是直接存放字符串本身,而是存放字符串的地址。在本例中,就是把字符串″Zhang″的地址存放在name[0],把字符串″Li″ 的地址存放在name[1],把字符串″Fun″的地址存放在name[2]……

1、string的构造函数的形式

string str:生成空字符串
string s(str):生成字符串为str的复制品
string s(str, strbegin,strlen):将字符串str中从下标strbegin开始、长度为strlen的部分作为字符串初值
string s(cstr, char_len):以C_string类型cstr的前char_len个字符串作为字符串s的初值
string s(num ,c):生成num个c字符的字符串
string s(str, stridx):将字符串str中从下标stridx开始到字符串结束的位置作为字符串初值

eg:
    string str1;               //生成空字符串
    string str2("123456789");  //生成"1234456789"的复制品
    string str3("12345", 0, 3);//结果为"123"
    string str4("012345", 5);  //结果为"01234"
    string str5(5, '1');       //结果为"11111"
    string str6(str2, 2);      //结果为"3456789"

 2、string的大小和容量

1. size()和length():返回string对象的字符个数,他们执行效果相同。

2. max_size():返回string对象最多包含的字符数,超出会抛出length_error异常

3. capacity():重新分配内存之前,string对象能包含的最大字符数

string s("1234567");
    cout << "size=" << s.size() << endl;         //7
    cout << "length=" << s.length() << endl;     //7
    cout << "max_size=" << s.max_size() << endl;//4294967294
    cout << "capacity=" << s.capacity() << endl;//15

3、string的插入:push_back() 和 insert()

string s1;
// 尾插一个字符
    s1.push_back('a');
    s1.push_back('b');
    s1.push_back('c');
    cout<<"s1:"<<s1<<endl; // s1:abc

    // insert(pos,char):在制定的位置pos前插入字符char
    s1.insert(s1.begin(),'1');
    cout<<"s1:"<<s1<<endl; // s1:1abc

4、拼接字符串:append() & + 操作符

// 方法一:append()
    string s1("abc");
    s1.append("def");
    cout<<"s1:"<<s1<<endl; // s1:abcdef

    // 方法二:+ 操作符
    string s2 = "abc";
    /*s2 += "def";*/
    string s3 = "def";
    s2 += s3.c_str();
    cout<<"s2:"<<s2<<endl; // s2:abcdef

 5、string的遍历:借助迭代器 或者 下标法

string s1("abcdef"); // 调用一次构造函数
    // 方法一: 下标法
    for( int i = 0; i < s1.size() ; i++ )
    {
        cout<<s1[i];
    }
    cout<<endl;
    // 方法二:正向迭代器
    string::iterator iter = s1.begin();
    for( ; iter < s1.end() ; iter++)
    {
        cout<<*iter;
    }
    cout<<endl;

     两个string常用的方法是find和substr。在下面的代码当中:find函数从str的第3个下标查起,找到ssdf这个子串后,返回子串的下标位置。

string str = "aaaaddddssdfsasdf";
size_t pos = str.find("ssdf", 3);
string str2 = str.substr(pos, 5);

 而substr函数从pos下标开始,截取5个字符,赋值给str2。也就是说,str2之后的内容将是ssdfs。

 C++string类总结https://www.cnblogs.com/X-Do-Better/p/8628492.html

from:https://blog.csdn.net/qq_37941471/article/details/82107077


下面介绍不适用string类的字符表示情况: 

字符数组 

1、strcat

strcat(char[],const char[]);

    strcat是string catenate的缩写。该函数有两个字符数组的参数,函数的作用是:将第二个字符数组中的字符串连接到前面字符数组的字符串的后面。第二个字符数组被指定为const,以保证该数组中的内容不会在函数调用期间修改。连接后的字符串放在第一个字符数组中,函数调用后得到的函数值,就是第一个字符数组的地址。例如:

char str1[30]=″People′s Republic of ″;
char str2[]=″China″;
cout<<strcat(str1,str2));//调用strcat函数
输出:
People′s Republic of China
连接前后的状况如图所示。

2、strcpy
strcpy(char[],const char[]);

strcpy是string copy(字符串复制)的缩写。它的作用是将第二个字符数组中的字符串复制到第一个字符数组中去,将第一个字符数组中的相应字符覆盖。例如
char str1[10],str2[]=″China″;
strcpy(str1,str2);
执行后,str2中的5个字符″China″和′\0′(共6个字符)复制到数组str1中。

关于字符串复制函数strcpy的几点说明:

  1. 在调用strcpy函数时,第一个参数必须是数组名(如str1),第二个参数可以是字符数组名,也可以是一个字符串常量。
  2. 可以用strcpy函数将一个字符串中前若干个字符复制到字符数组中去。
  3. 只能通过调用strcpy函数来实现将一个字符串赋给一个字符数组,而不能用赋值语句将一个字符串常量或字符数组直接赋给一个字符数组。

3、strcmp
strcmp(const char[],const char[]);

strcmp是string compare(字符串比较)的缩写。作用是比较两个字符串。由于这两个字符数组只参加比较而不应改变其内容,因此两个参数都加上const声明。以下写法是合法的:
strcmp(str1,str2);
strcmp(″China″,″Korea″);
strcmp(str1,″Beijing″);
比较的结果由函数值带回:

  1. 如果字符串1=字符串2,函数值为0。
  2. 如果字符串1>字符串2,函数值为一正整数。
  3. 如果字符串1<字符串2,函数值为一负整数。

注意:对两个字符串比较,不能用以下形式:if(str1>str2) cout<<″yes″;

     字符数组名str1和str2代表数组地址,上面写法表示将两个数组地址进行比较,而不是对数组中的字符串进行比较。对两个字符串比较应该用  if(strcmp(str1,str2)>0) cout<<″yes″;

但是如果我们定义的是字符串变量,就可以使用">”,因为这是我们使用了string类。

4、strlen
strlen(const char[]);

   strlen是string length(字符串长度)的缩写。它是测试字符串长度的函数。其函数的值为字符串中的实际长度,从左到右,到\0为止,但不包括′\0′在内。如
char str[10]=″China\0as″;
cout<<strlen(str);
输出结果不是10,也不是6,而是5。

couy<<sizeof(str)  这个就输出的是 10

from:https://blog.csdn.net/Xiao_Yanci/article/details/79111186

      string s = "you";要取得其中某一个字元,和传统C 的字串一样是用 s[i] 的方式取得。比较不一样的是如果 s 有三个字元,传統 C 的字串的 s[3] 是'\0' 字符,但是 C++ 的 string 则是只到 s[2] 这个字符而已。

做一个对照:


   实例:给定一个字符串,输出字符串中连续最长的数字串,并把这个最长数字串的长度输出来,中间以逗号(,)隔开。如果存在长度一样的的连续数字串,返回最后一个连续数字串。

本文分别使用字符数组和字符指针进行实现:

int main() {

	string str;
	string out;
	cin >> str;
	int i = 0; int Maxlen = 0; int end = 0; int ed;
	while (str[i] != '\0') {
		int count = 0;
		while(str[i] >= '0'&& str[i] <= '9'){
				count++;
				ed = i;
				if (i != str.length() - 1)
					i++;
				else if(i == str.length() - 1) {
					break;
				}
					

		}
		i++;
		if (count > Maxlen) {
			Maxlen = count;
			end = ed;
		}
	}
	cout << Maxlen<<endl<<end<<endl;
	int start = end - Maxlen + 1;
	for (int i = start; i <= end; i++) {
		out = out+str[i];

	}
	cout << out;
	system("pause");
	return 1;
}

完整代码请参考:https://github.com/liuzheCSDN/Cinterview/tree/master/maxnumcontinue

代码疑问注解:

char **x ; 定义一个二维指针变量x,x中可以存储一个char *类型变量的地址

char *x ; 定义一个一维指针变量x,x中可以存储一个char类型变量的地址

一维指针:通过指针变量x的值(地址),可以找到数据

二维指针:通过指针变量x的值(地址),找到的还是个地址值,再通过这个新的地址值,才能找到数据

如:

char ch='a' ;
char *p=&ch;
char **pp=&p ;
 
*p就是ch
*pp就是p, **pp是ch

char *p 和 char *p=(char*)malloc(sizeof(char))

char *p只是定义了一个指针类型的变量,并没有给该指针分配空间,进行初始化,不能通过该指针进行返问。char *p=(char*)malloc(sizeof(char)),定义了一个指针类型的变量p,并给该指针动态分配了一个字符的空间,可以通过该指针进行访问该空间。

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值