字符串字面值的类型就是const char类型的数组。
c风格字符串
c风格字符串既不能确切地归结为C语言的类型,也不能归结为c++类型,而是以空字符null结束的字符数组。
char ch1[] = { 'a', 'b', 'c' };
char ch2[] = { 'a', 'b', 'c', '\0' };
char ch3[] = "abc";
char *ch = ch2;
可以理解成没有以\0结尾的字符数组只是普通的字符数组,而以\0结尾的字符数组,就是字符串,c风格的字符串。
1.c风格字符串的使用
int main()
{
char s[] = "hello";
char *ps = s;
cout << s << endl;
cout << ps << endl;
while (*ps)//若*ps==null则循环终止
{
*ps = toupper(*ps);
++ps;
}
cout << s << endl;
//cout<<ps<<endl;注意此时输出ps指向的字符串没有意义,因为ps指向的位置早已到了字符串末端的下一个位置
getchar();
return 0;
}
如果ps指向的字符串中没有\0(null结束符)则会一直循环下去,知道在内存中找到\0
2.c风格字符串的标准库函数
使用时,添加头文件
#include <cstring>
strlen(s)
strcmp(s1,s2)
strcat(s1,s2)
strcpy(s1,s2)
strncat(s1,s2,n)
strncpy(s1,s2,n)
3.永远不要忘记字符串结束符null
int main()
{
char ch[] = { 'a', 'b', 'c' };
char ch1[] = { 'a', 'b', 'c' ,'\0'};
cout << strlen(ch) << endl;
cout << strlen(ch1) << endl;
getchar();
return 0;
}
对于第一种输出情况,结果是不确定的,strlen遍历字符串,知道遇到空字符才停止,所以一定不要忘记空字符。
4.调用者必须保证目标字符串具有足够的大小
在调用strcpy和strcat等函数时,strcpy(char*,char*);必须确保第一个实参数据有足够的大小,能够实现字符串的拷贝,并且在第二个实参长度发生变化时,第一个参数需要做适当的调整。
5.使用strn函数处理c风格字符串
strncpy和strncat在复制和连接函数时能够控制复制和连接的函数的个数
int main()
{
char *ch1 = "hello";
char *ch2 = "world";
char ch3[20];
strncpy(ch3, ch1, 6);//复制ch1中6个字符到ch3,包括null
cout << ch3 << endl;
cout << strlen(ch3) << endl;//输出ch3字符串的长度,不包括null
strncat(ch3," ", 2);//ch3连接两个字符,一个空格,一个null字符,其中空格会覆盖前面的null
cout << strlen(ch3) << endl;//共有7个字符,字符串的长度为6
strncat(ch3, ch2, 6);//ch3连接ch2中6个字符,包括null,最前面的字符会覆盖前面的null
cout << ch3 << endl;
cout << strlen(ch3) << endl;
getchar();
return 0;
}
标准库将负责处理所有的内存管理问题
创建动态数组
普通数组在编译时必须知道其长度,动态数组则不必在编译时知道其长度,可以在运行时确定数组长度
普通数组只在定义他的域内存在,动态数组则一直存在,直到程序显式释放。
普通数组与动态数组长度都是固定的。
堆区(heap)是程序在运行过程用于存放动态分配的对象的内存空间。
1.动态数组的定义和初始化
int *p=new int[10];//返回分配的内存空间的第一个位置的指针。
初始化:
1)数组元素是类类型,用该类的默认构造函数初始化
2)数组元素是内置类型,不会初始化,可以显式的初始化
int *p=new int[10]();
注意:只能初始化为元素的默认值,不能像数组一样,用初始化列表提供各个元素的初值
int main()
{
int *p = new int[10]();
for (size_t index = 0; index != 10; ++index)
{
cout << p[index] << " ";
}
cout << endl;
getchar();
return 0;
}
int类型的默认值0,char类型的默认值空白字符(空格)
2.const对象的动态数组:
const对象在创建时必须进行初始化
const int *p=new int[10];//error
const int *p=new int[10]();//ok
const string *s=new string[10];//ok default construct function
3.允许动态分配空数组:
char ch[0];//error不允许创建0长度的数组
char *pc=new char[0];//ok
用new创建长度为0的数组时,new返回有效的非零指针,该指针与new返回的其他指针不同,不能进行解引用操作,因为他没有指向任何对象,允许进行比较运算。
4.动态空间的释放
delete [] p;//释放p指向的数组,把相应的内存还给自由存储区(堆区)
[]表示指针指向的是自由存储区的数组,而非单个对象
int main()
{
int *p = new int[10];
for (size_t index = 0; index != 10; ++index)
{
p[index] = index;
cout << p[index] << " ";
}
cout << endl;
cout << p << endl;
delete[] p;
cout << p << endl;//空间释放后,p指向的位置发生变化
getchar();
return 0;
}
新旧代码兼容:
1.混合使用标准库类string和c风格字符串
c风格字符串和字符串字面值具有相同的数据类型,因此可以把c风格字符串用在任何可以使用字符串字面值的地方:
int main()
{
char *s = "hello world";
string s1(s);//ok
string s2("hello world");//ok
cout << s << endl << s1 << endl;
cout << s << endl << s2 << endl;
getchar();
return 0;
}
2.在要求c风格字符串的地方不可直接使用标准库string类型对象
int main()
{
string s("hello world");
//char *p = s;//error
//char *p1 = s.c_str();c_str()返回const类型的c风格字符串
const char *p2 = s.c_str();
cout << p2 << endl;
getchar();
return 0;
}
c_str()返回const类型的c风格字符串。
注意:如果下面的操作改变s的值,则函数的返回值会失效,所以如果持续访问s数据,则应该复制c——str的返回值
int main()
{
string s("hello world");
//char *p = s;//error
//char *p1 = s.c_str();
const char *p2 = s.c_str();
s = "hello";
cout << p2 << endl;
getchar();
return 0;
}
运行结果输出hello
3.使用数组初始化vector对象
必须指出初始化数组的第一个元素和最后一个元素的下一个位置
int a[]={1,2,3,4,5,6};
vector<int> ivec(a,a+3);//1,2,3