#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
char *s1 = "hello";
char s2[] = "hello";
//char s2[5] = "hello"; //这里会报错,因为s2末尾还有一个'\0'结束符,字符数组长度少1;
string st = "hello"; //st存在栈中,"hello"可以经由st修改;
cout << "sizeof s1:" << sizeof(s1) << endl;
/* 程序输出的是4,即32位系统中指针变量的大小*/
/*char *s1 = "hello";实际上先是在文字常量区分配了一块内存放"hello",
然后在栈上分配一地址给s1并指向这块地址*/
cout << "strlen s1:" << strlen(s1) << endl;
/*程序输出5,strlen遇到'\0'即结束计算,char *s1 最后包含一个'\0'结束符*/
cout << "sizeof s2:" << sizeof(s2) << endl;
/*程序输出6,sizeof计算字符串实际占有的空间大小,包括了结尾的'\0'结束符*/
cout << "strlen s2:" << strlen(s2) << endl;
/*程序输出5,strlen遇到'\0'即结束计算,s2最后包含一个'\0'结束符*/
//cout << "lenght of st:" << strlen(st) << endl;
//报错,因为strlen只接受char *类型参数;
cout << "length of st:" << st.length() << endl;
//程序输出5,结尾不含有'\0';
cout << s1 << endl;
//返回从s1开始的字符串"hello";
cout << s2 << endl;
//返回从s2开始的字符串"hello"
cout << *s2 << endl;
//返回第一个字符'h'
cout << *(s2 + 1) << endl;
//返回第二个字符'e'
cout << (s1 + 1) << endl;
//s1自身就是地址,无法取*操作,返回第二个字符开始的字符串"ello"
cout << &s2[1] << endl;
//返回从第二个字符开始的字符串"ello"
//s1[4] = 'M';
//程序报错,因为s1指向的"hello"是常量,不能通过s1修改;
s2[4] = 'M';
cout << s2 << endl;
//程序正常运行,输出"hellM";
//s2 = "world";
/*该句报错,系统提示:s2是一个普通字符数组首地址,"hello"存在栈区,可以通过s2修改"hello",s2必须
是可修改的左值,s2类似一个const指针*/
st[4] = 'M';
cout << st << endl;
//程序输出"hellM"
return 0;
}
总结如下:
1. char[] p表示p是一个数组指针,相当于const pointer,不允许对该指针进行修改。但该指针所指向的数组内容,是分配在栈上面的,是可以修改的。
2. char * pp表示pp是一个可变指针,允许对其进行修改,即可以指向其他地方,如pp = p也是可以的。对于*pp = "abc";这样的情况,由于编译器优化,一般都会将abc存放在常量区域内,然后pp指针是局部变量,存放在栈中,因此,在函数返回中,允许返回该地址(实际上指向一个常量地址,字符串常量区);而,char[] p是局部变量,当函数结束,存在栈中的数组内容均被销毁,因此返回p地址是不允许的。
同时,从上面的例子可以看出,cout确实存在一些规律:
1、对于数字指针如int *p=new int; 那么cout<<p只会输出这个指针的值,而不会输出这个指针指向的内容。
2、对于字符指针入char *p="sdf f";那么cout<<p就会输出指针指向的数据,即sdf f
那么,像&(p+1),由于p+1指向的是一个地址,不是一个指针,无法进行取址操作。
&p[1] = &p + 1,这样取到的实际上是从p+1开始的字符串内容。
分析上面的程序:
*pp = "abc";
p[] = "abc";
*pp指向的是字符串中的第一个字符。
cout << pp; // 返回pp地址开始的字符串:abc
cout << p; // 返回p地址开始的字符串:abc
cout << *p; // 返回第一个字符:a
cout << *(p+1); // 返回第二个字符:b
cout << &p[1];// 返回从第二个字符开始的字符串:bc