string str_s = "abc";
char *str_cp = "abc";
char str_ca[] = "abc";
1. str_cp是指针,指向一段数据有四个元素,分别是'a', 'b', 'c', '/0'。
2. str_ca是数组,它包含四个元素,分别是'a', 'b', 'c', '/0'。
引用:我知道*str_cp的"abc"多了一个'/0'
这个说法不正确。数组str_ca也会有'/0'。但如果你写char str_ca[] = {'a', 'b', 'c'}则不会有'/0'。
3.
引用:str_ca相当于一个char * const str_cp
这个说法不正确。数组和指针是不同的,数组不能看作常指针。证据就是:
char* const s = "abcdef";
char a[] = "abcdef";
则sizeof(s)一般为2或者4,而sizeof(a)为7。
指针只保存了所指向的地址,数组既包括首地址的信息,还包括长度的信息。不过数组在作为参数传递时,可以转化为指针的形式(数组首地址作为指针所指地址,数组长度信息被丢弃)。
4.
引用:string str_s 本质上是什么呢?
从对象的观点看。str_s就是一个对象,其中包含了字符串数据,如此而已。至于对象内部是如何操作,以保证正确的包含这个字符串数据,这完全取决于string类的作者。这种现象体现了面向对象编程思想中的一个重要观点——封装。作为类的使用者,我们只要知道它应该怎么用即可,不需要知道它是如何工作的。也就是说不需要知道它的本质。
当然我们也不能一无所知。为了更好的使用这个类,它的基本特性要了然于心。比如,我们要知道string中的字符是连续存储的,而不是通过链表来进行存储的。等等。
5.
引用:一般做开发都得转换成 char*的吗?
不是的。C++本身的输入输出就直接支持string。比如:
string s;
cin >> s;
cout << s;
虽然string是鼓励的,但这并不意味着char*就是应该被抛弃的。很多时候还是会用到char*。例如你从zip包中解压出一个文件,因为很多zip压缩解压的程序都用C语言写,因此文件解压得到的数据在内存中很可能就是以char*的形式存在的。
6.
引用:我可以在一个函数里返回一个 数组名称/string变量/char *,然后给一个 char * /string/char[] 这样赋值行吗?
这个问题比较细,下面一点一点的分析。
(1) 返回一个char*,赋值给char*。可以。
(2) 返回一个char*,赋值给string。可以。运行时实际的情况是,根据char*的值构造一个临时的string对象,把这个临时的string对象赋值给你的string变量,最后销毁临时的string对象。
(3) 返回一个char*,赋值给char[]。不可以。char[]是数组,数组是不允许赋值的。只有数组的元素才能赋值。
(4) 返回一个string变量,赋值给char*。不可以。因为string不能转化为char*。你可以通过string类的c_str方法取得它的指针,但是要注意,如果string对象本身被销毁了,则指针所指的数据也跟着无效。例如:
string func() {
return string("abc");
}
int main() {
char* s = func().c_str();
cout << s; // 错误!!
}
因为函数func()返回后,它的返回值是临时的。通过c_str取得它的指针赋值给s后,临时值被销毁,因此s指向的是一个无效的位置。
(5) 返回一个string变量,赋值给string。可以。
(6) 返回一个string变量,赋值给char[]。不可以。char[]是数组,数组是不允许赋值的。只有数组的元素才能赋值。
(7) 如果返回数组的名字,其实是返回数组的首地址,也就是一个指针。所以这其实跟返回char*是非常类似的。唯一需要注意的问题是,如果数组是局部变量,并且不是static的,则函数返回时数组会被销毁,所以返回的指针所指向的位置也是无效的。例如:
char* func() {
char a[] = {"abc"};
return a;
}
int main() {
char* s = func();
cout << s; // 错误!!
}
7.
引用:我如果cout < <str_cp[1] 此时指向'b'如果以'/0'为结束标志的话,应该输出的是bc 啊
这个涉及到数据类型的问题。cout会根据数据的类型和数据的值来确定最终的输出。对于char类型,cout只输出一个字符,对于char*类型,cout输出多个字符,直到遇到'/0'才结束。
因为str_cp是char*类型,所以str_cp[1]是char类型。所以cout << str_cp[1]实际上是输出char类型,因此只输出一个字符。
但str_cp + 1是char*类型,所以cout << (str_cp+1)实际上是输出char*类型,因此输出多个字符,遇到'/0'才结束。
如果觉得(str_cp+1)不够直观,可以写为&str_cp[1]。(虽然后一种写法看起来执行了两步操作,但实际上两种写法编译后得到的代码是一样的,不会有效率问题)