字符串和字符数组
文章目录
1. char[]、char*
-
char*是字符指针,可以指向一片内存,内存中存放着字符串;可以通过以下两种形式初始化:
char * myStr = "Hello!";//方法一 char *myStr1; //方法二 myStr1 = "Hello!";
-
char []是字符数组,与一维数组类似;可以通过以下两种方式初始化:
char myStr[10] = "Hello!"; //方法一 char myStr1[10] = {'H', 'e', 'l', 'l', 'o', '!', '\0'};//方法二,结尾必须有'\0',整数0,非字符0;
-
错误的定义/初始化方式:
//错误一 char myStr2[10]; myStr1 = "Hello!";//虽然都是指针,但是定义char myStr2[10]时,为其分配的是栈内存空间,而"Hello"指向数据区中的字符常量空间,所以两者之间不能直接赋值; //错误二 char *myStr3 = "Hello!"; myStr3[0] = 'h'; //错误原理同上,myStr3指向的是数据区的字符常量,是不可写的内存空间,因此不能通过指针myStr3来修改;
-
针对错误一的疑问:为什么
char myStr4[10] = "Hello!"
不会报错?
myStr4的初始化,执行的是拷贝初始化,此处的等号不是简单的赋值操作,而是一个拷贝操作,也就是说右侧的"Hello!"是被拷贝到myStr4所指向的栈空间中;
2. char* 和const char*
2.1 概要
-
const关键字说明其修饰的变量不可被改变;const可以修饰变量、参数、函数、返回值等,可以提高程序的健壮性,减少程序出错(修饰函数参数(指针)时,可避免传入的参数在函数体中被修改);
-
代码中,声明可以从右往左读,指针读成pointer to,比如:
char * myStr: myStr is a pointer to char
const char * myStr: myStr is a pointer to const char
char * const myStr: myStr is a const pointer to achar -
const char *和char const * :底层const,两者是等价的,const均修饰指针指向的内容,说明指针指向的内容为常量,不可通过该指针来修改其指向的内容;
-
char * const:顶层const,const修饰指针本身,说明指针本身是常量,表示定义的指针不可以再指向其他的地址;
2.2 C语言中处理字符的函数
-
求字符串的长度:
-
strlen:可以用于计算字符数组中,字符的长度;也可用于计算字符指针所指向的字符串长度;
-
sizeof:用于求字符数组的长度;
char *str1 = "hello!";//sizeof(str1)=8如果是32位机器,则sizeof(str1)=4; strlen(str1)=6 const char * str2 = "hello!";//sizeof同上,求得的都是内存地址所占的字节数,strlen(str2)=6 char str3[] = "hello!";//sizeof(str3)=7, 6个字符加结尾的'\0', strlen(str3)=6 char str4[10] = "hello!";//sizeof(str4)=10 strlen(str4)=6
因此,求字符串的实际长度时,经常使用strlen方法;
-
-
字符串拼接和分割
-
strcat:实现两个字符串的拼接,
strcat(char *dst, const char *src);
char *str1 = "hello"; const char *str2 = "world"; char str3[] = "big"; char str4[] = "eye"; char str5[20] = "my"; strcat(str1, str2);//错误,str1指向数据区的字符常量空间,不可修改,也不可拼接; strcat(str3, str4);//不会报错,但是拼接后的结果为"bige",这是由于str3的长度只有5个字符(包含结尾的'\0'); strcat(str5, str2);//正确,结果为"my world" strcat(str5, str3);//正确,结果为"my big"
-
strtok:实现字符串的分割,第一个参数为待分割的字符串,第二个参数为分割符,
strtok(char *src, const char* delimiter)
,需要注意的是,输入的src字符串应是字符数组(字符串定义在栈空间中);同strcat,输入的待分割变量应是字符数组char str2[] = "192.168.1.1"; char *result = strtok(str2, "."); while(result != NULL){ printf("%s\t",result); result = strtok(NULL, "."); } //输出 192 168 1 1
strtok中有一个隐含的第三个参数,每次调用strtok后,其更新为分割符后所有的字符;在上述示例代码中第一次调用strtok后,context为"168.1.1",然后如果接下来传入的字符为NULL,则strtok会对context进行分割,分割后再次更新context;源码如下:
-
-
字符串比较
-
strcmp:逐字符比较输入的两个字符串是否相同,如果相同则返回为0,若不相同,则返回第一个不相同字符的ASCII码差值或正负1(取决于编译器),在windows下的返回情况一般是
-1 0 1
;char *str1 = "Hello!"; //ASCII of 'H' is 72 char *str2 = "hello!"; //ASCII of 'h' is 104 int result = strcmp(str1, str2); //resut = -1 因为两者第一个字符就不相同,且'H'的ASCII码小于'h'
-
-
字符串拷贝
-
strcpy:字符串拷贝,将一个字符串拷贝给另一个字符串,目前参数必须是字符数组(指向栈空间),不能是指向数据区的字符指针;
char str1[] = "Hello"; char *str2 = "Hello world!"; strcpy(str1, str2); //执行后str1 = "Hello world!"
-
3. string
- string是C++中的一个类,使用比较灵活,提供了很多用于处理字符串的方法;
- 初始化:
std::string str1 = "Hello";
//拷贝初始化std::string str2("Hello"); 或者 std::string str2(str1);
//赋值初始化std::string str3(const char*, n);
//使用const char*中的前n个字符初始化stringstd::string str4(n, 'A');
//使用n个字符’A’初始化字符串str4std::string str5(str1, m, n);
//使用字符串str1中,第m到m+n-1个字符来初始化字符串str5
- string类中提供的方法:参考文档1 参考文档2
- length()和size()可以返回string的有效字符串长度;
- clear()清空字符串,empty()用于判断字符串是否为空;
- 访问string中的第n + 1个字符:str.at(n)或者str[n];
- swap(string s)交换两字符串的字面值;compare(string s)比较两字符串的字面值;
- insert(),向string中插入字符,方法提供了多种重载,如insert(int p0, string s)表示从字符串的p0处,插入字符串s;
- substr(int pos, int n)表示从pos位置处开始,截取n个字符;
- copy(char *s, int n, int pos)表示从字符串的pos位置处,拷贝n个字符,赋值给字符数组s;
4. 各类型间的转换
4.1 char[]和char*间的转换
char str1[] = "Hello";
char *str2 = "Hi";
str2 = str1; //正确,str2本质上就是一个指针,此处相当于让指针指向栈空间中的字符串"Hello"
str1 = str2; //错误,str2指向的地址为数据区的字符常量空间,而str1指向栈空间,不能直接赋值,只能通过拷贝的方式
4.2 const char*和char*间的转换
char *str1 = "Hello";
const char *str2 = "Hi";
str2 = str1; //正确 将指针str1指向的地址赋值给
str1 = str2; //错误 不能将const int*类型的指针赋值给const int,此处同理;可以这样理解,const int *表明不能通过指针修改其指向的值,如果能够将其赋值给int *,则可以通过新的指针来修改其指向的内容了,这违背了const本身的原则;
char str3[] = "Test";
str2 = str3; //正确 并且能够通过str2来修改str3字符数组中的内容
str2[2] = 'E'; //正确
4.3 const char *、char *以及char[]间的相互转换
除第一条外,此处的结论均不包含C++中的string
- 字符数组char[]可以作为右值,赋值给任意的字符指针(const char *、char *)或字符串(string);
- const char* 不能作为右值进行赋值操作,除非经过指针类型的强制转化,如:
char * str2 = const_cast<char *>(const char *str1);
; - char* 只能作为右值赋值给const char*
4.4 C++中的string与C中的字符串间的转换规则
-
C中的三种字符串类型均可用来对string进行赋值,此时的赋值可以理解为字符串的拷贝操作,并不会改变string变量的地址;
-
string转const char*:
const char *myStr1 = myStr2.c_str();
其中myStr2为string类型; -
string转char *:使用上述的方式只能转换到const char *,如果需要将sring转换成char *,可以调用上述的copy方法,如:
myStr2.copy(myStr3, myStr2.length() + 1, 0);
,其中myStr2是string类型的字符串,myStr3是char *类型的字符串,加一是因为字符串结尾的’\0’; -
string转char[]:使用strcpy函数实现拷贝赋值,
strncpy(myStr4, myStr2.c_str(), myStr2.length() + 1);
,任何类型的字符串转char[]都可以使用strcpy拷贝赋值方法; -
char *转int:使用atoi函数(
atoi(char * x)
),类似的函数还有,atof(char *转float)、atol(char *转long);如果是单个字符,还可以通过int a = s - '0';
实现,其中s为单个字符char; -
int转char *:使用_itoa或者sprintf函数;_itoa的用法为
_itoa(a, s, int base);
,其中a为int类型,s为char *类型,base表示a的进制类型(10进制、8进制、16进制);sprintf的用法为sprintf(s, "%d", a);
。