char *p=”computer”;其最后一个是’\0’,并且操作的时候以遇到’\0’认为字符串结束了。
不可以更改常量字符串,因为这样是放到了静态常量区。
这样就更改了。”computer”存储的位置更改了。
为什么a输出不了,因为数组p[10]能存10个字符,布局如下
‘c’ |
‘o’ |
‘m’ |
‘p’ |
‘u’ |
‘t’ |
‘e’ |
‘r’ |
‘\0’ |
‘a’ |
字符串是以‘\0’结尾的。检测到‘\0’即认为字符串结束。故a输出不了。
字符串只能存在字符数组中。
在c中没有字符串类型,所以只能采用字符指针或字符数组进行操作,对于一个字符串,若赋给字符指针,则字符串存放的位置是静态常量区,不可对其更改。若赋给字符数组,则字符串就放在系统分给该字符数组的内存中,可以对其更改。存放的结果相当于存入一个个字符,例如”computer”,放在长度为10的字符数组中,布局如下:
‘c’ |
‘o’ |
‘m’ |
‘p’ |
‘u’ |
‘t’ |
‘e’ |
‘r’ |
‘\0’ |
‘\0’ |
字符串是以‘\0’结尾的。检测到‘\0’即认为字符串结束。
sprintf_s函数功能:将数据格式化输出到字符串,
int sprintf_s(char*buffer,size_t sizeOfBuffer,const char *format [,argument] ...);
需要包含的头文件:stdio.h
注意:sprintf_s()是sprintf()的安全版本,通过指定缓冲区长度来避免sprintf()存在的溢出风险。
c++中可以使用stringstream类
描述:是对istringstream和ostringstream类的综合,支持<<,>>操作符,可以进行字符串到其它类型的快速转换
作用:
1、stringstream通常是用来做数据转换的
2、将文件的所有数据一次性读入内存
注意加上stream.clear();否则每次输出都是10. stream.clear()相当于把以前的流清空了。由于stringstream构造函数会特别消耗内存,似乎不打算主动释放内存(或许是为了提高效率),但如果你要在程序中用同一个流,反复读写大量的数据,将会造成大量的内存消耗,因些这时候,需要适时地清除一下缓冲 (用 stream.str("") )。
#include
#include
using namespace std;
int main()
{
//(1)、对于整型字符型数组
int A[] = { 1, 4, 5, 2, 8, 6, 0 };
//求整型数组A所占的字节数
cout << "sizeof(A) = " << sizeof(A) << endl; //整型数组A所占的总空间的字节数
cout<<"sizeof(A) / sizeof(int)="<
strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止(注意存储在数组中时易出错),然后返回计数器值。 --就是指实际字符串或字符数组的实际长度(不是所占空间的字节数)。
#include
#include
using namespace std;
class Syf
{
int i;
int j;
char k;
};
Syf x;
class A1
{
};
class A2
{
};
class B1 :public A1
{
};
class C1 :virtual public B1
{
};
class D1 :public A1, public A2
{
};
int main()
{
char A[6] = { 'a', 'b', '\0', 'd', 'e', 'r' };
cout << "strlen(A)="<
表明空类所占空间为1个字节,单一继承的空类空间也为1,多重继承的空类空间还是1,但虚继承涉及虚表(虚指针),所以sizeof(C)为 4。
sizeof()返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个操作符,strlen是函数。
为了兼容等,这两个函数一样。 length是因为沿用C语言的习惯而保留下来的,string类最初只有length,引入STL之后,为了兼容又加入了size,它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。
string类的size()/length()方法返回的是字节数,不管是否有汉字。
之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联。我们尽可以把它看成是C++的基本数据类型。
首先,为了在我们的程序中使用string类型,我们必须包含头文件
如下:
#include
using namespace std;
这段摘自:http://blog.csdn.net/wangshubo1989/article/details/50281869
标准库的string类提供了3个成员函数来从一个string得到c类型的字符数组:c_str()、data()、copy(p,n)。
1. c_str():生成一个const char*指针,指向以空字符终止的数组。注:
①这个数组的数据是临时的,当有一个改变这些数据的成员函数被调用后,其中的数据就会失效。因此要么现用先转换,要么把它的数据复制到用户自己可以管理的内存中。注意。看下例:
string s = "what fucking day";
char* c;
const int len = s.length();
c =new char[len+1];
strcpy(c,s.c_str());
也可以使用copy:
int main()
{
std::string foo("quuuux");
char bar[7];
foo.copy(bar, sizeof bar);
bar[6] = '\0';
std::cout << bar << '\n';
}
char* c ="abc";
string s(c);
================================================================
string和char*指针一样大的实现很常见,也很容易找到string是char*7倍大小的string实现。为什么会有差别?为了理解这一点,我们必须知道string可能存什么数据和它可能决定保存在哪里。
实际上每个string实现都容纳了下面的信息:
另外,一个string可能容纳
依赖引用计数的string实现也包含了
不同的string实现以不同的方式把这些信息放在一起。
上面提到了data和c_str的区别,那么究竟区别在哪呢?
二者原型:
const value_type *c_str( ) const;
const value_type *data( ) const;
data只是返回原始数据序列,没有保证会用traits::eos(),或者说’\0’来作字符串结束. 当然,可能多数实现都这样做了。
c_str是标准的做法,返回的char* 一定指向一个合法的用’\0’终止的C兼容的字符串。
所以,如果需要C兼容的字符串,c_str是标准的做法,data并不保证所有STL的实现的一致性。
你或许会问,c_str()的功能包含data(),那还需要data()函数干什么?看看源码:
const charT* c_str () const
{
if (length () == 0)
return "";
terminate ();
return data ();
}
原来c_str()的流程是:先调用terminate(),然后在返回data()。因此如果你对效率要求比较高,而且你的处理又不一定需要以\0的方式结束,你最好选择data()。但是对于一般的C函数中,需要以const char*为输入参数,你就要使用c_str()函数。
对于c_str() data()函数,返回的数组都是由string本身拥有,千万不可修改其内容。其原因是许多string实现的时候采用了引用机制,也就是说,有可能几个string使用同一个字符存储空间。而且你不能使用sizeof(string)来查看其大小。详细的解释和实现查看Effective STL的条款15:小心string实现的多样性。
另外在你的程序中,只在需要时才使用c_str()或者data()得到字符串,每调用一次,下次再使用就会失效。
针对第一个作者有句话,在segmentfault上的一个问题及得分较多的一个解答,以供参考
C++中的std::string和C-style string是两种不同的字符串,前者是标准库中定义的一个类,后者是字符数组的别名。
C-style string中一般不能包含\0字符(因为这个字符被当作表示字符串结束的特殊字符处理了),如果包含这个字符,那么其后的字符将会被忽略。即:
char s[] ="ab\0c";
cout << s << endl; //输出 ab
而std::string没有这个限制。即:
std::string s{'a','b','\0','c'};
//std::string s ="ab\0c"; //这里由于是从C-style string构造std::string,所以仍然会忽略 \0之后的字符
cout<< s << endl; //输出 ab c
附录
通过c_str()或data()(二者在 C++11 及以后是等价的)来把std::string转换为const char *时,会发现最后一个字符是\0。想理解这个问题需要一点背景知识:
一,std::string 是 std::basic_string
template<
class CharT,
class Traits =std::char_traits
class Allocator =std::allocator
> classbasic_string;
中的参数CharT为char时的特例。
二,s.size()会返回std::string中字符的个数,即:
string s{'a','b','\0','c'};
cout << s.size() << endl; //输出 4
s += '\0';
s += 'd';
cout << s.size() << endl; //输出 6
三,使用[]运算符(即std::basic_string::referencestd::basic_string::operator[](size_type pos);)获取std::string中的字符时,其字符的范围pos是从0到size()。其中0到size()-1是所存储的字符,而对于pos == size()有如下规定:
If pos == size(), a reference tothe character with value CharT() (the null character) is returned. Forthe first (non-const) version, the behavior is undefined if this character ismodified.
意思是当访问s[s.size()]时,会返回CharT()的返回值的引用,而CharT对于std::string是char,且char()返回的是\000,所以s[s.size()]会返回\0。
四,通过c_str()或data()(const CharT* c_str()const;)返回的指针访问字符串时,其效果为:
Returns: Apointer p such that p + i == &operator[](i) for each i in [0,size()].
即p[s.size()]等价于p + s.size()等价于&s.operator[](s.size())等价于s[s.size()],所以会发现返回值是\0。
下面是我在Visual2013上的一些操作测试:
#include
#include
using namespace std;
int main()
{
std::cout << "string 初始化及一些操作测试" << endl;
string str = "Then";
std::cout << "测试这样能否输出字符,可以。str[2]:" << str[2] << endl;
// cout << "str[5]:" << str[5] << endl;//出现异常
str[2] = 'a';
std::cout << "测试这样能否修改字符串,可以。str[2]:" << str[2] << endl;
str.insert(1, "h");
string str1 = str;
std::cout << "测试插入与直接复制string。str1:" << str1 << endl;
std::cout << "string 中字符\0与字符串\0的测试" << endl;
char *p = "ab\0c";
string s = "ab\0c";
string s1{ 'a', 'b', '\0', 'c' };
string s2 = "myself";
std::cout << "p:" <
我们可以使用下标操作符[]和函数at()对元素包含的字符进行访问。但是应该注意的是操作符[]并不检查索引是否有效(有效索引0~str.length()),如果索引失效,会引起未定义的行为。而at()会检查,如果使用 at()的时候索引无效,会抛出out_of_range异常。
有一个例外不得不说,const string a;的操作符[]对索引值是a.length()仍然有效,其返回值是'/0'。其他的各种情况,a.length()索引都是无效的。
也许你需要在string中间的某个位置插入字符串,这时候你可以用insert()函数,这个函数需要你指定一个安插位置的索引,被插入的字符串将放在这个索引的后面。
s.insert(0,”my name”);
s.insert(1,str);
这种形式的insert()函数不支持传入单个字符,这时的单个字符必须写成字符串形式(让人恶心)。既然你觉得恶心,那就不得不继续读下面一段话:为了插 入单个字符,insert()函数提供了两个对插入单个字符操作的重载函数:insert(size_type index,size_type num,chart c)和insert(iterator pos,size_type num,chart c)。其中size_type是无符号整数,iterator是char*,所以,你这么调用insert函数是不行的:insert(0,1, 'j');这时候第一个参数将转换成哪一个呢?所以你必须这么写:insert((string::size_type)0,1,'j')!第二种形式指 出了使用迭代器安插字符的形式,在后面会提及。顺便提一下,string有很多操作是使用STL的迭代器的,他也尽量做得和STL靠近。
删除函数erase()的形式也有好几种(真烦!),替换函数replace()也有好几个。