char, char*, char[], int的区别、互转及字符串操作 - C语言笔记
类型转换一直是 C 语言编程中的难点和痛点,本文将介绍 C 语言中 char
, char *
, char []
, int
之间的区别、互转以及一些常见的字符串操作。
一、char 与 int 互转: 直接赋值
char
和int
可以直接互转,但是需要注意的是,char
的范围是 0~255 或 -128~127,而int
的范围是-2147483648~2147483647。
char c1 = 'a';
int i = c1;
char c2 = i;
二、char* 与 int 互转
2.1 int 转 char*: sprintf()
方法一:
itoa(int value, char* str, int base)
函数可以将整数value
以base
进制的形式转换为字符串,并存储到str
所指的字符数组中。方法二:
char* itoa(int value, NULL, int base)
函数可以将整数value
以base
进制的形式转换为字符串,并返回一个指向该字符串的指针。方法三(推荐):
sprintf(char* str, "%d", value)
格式化字符串函数可以将整数value
以十进制的形式转换为字符串,并存储到str
所指的字符数组中。
int value = 123;
char *str;
sprintf(str, "%d", value);
printf("%s\n", str); // 123
提示
理论上itoa()
位于<stdlib.h>
头文件中。 但itoa()
可能不被编译器支持。
2.2 char* 转 int: atoi(), strtol()
方法一:
int atoi(char* str)
函数可将字符串str
转换为整数(仅支持的最大整数值为INT_MAX
)。方法二(推荐):
int strtol(char* str, char** endptr, int base)
函数可将字符串str
逐位转换为整数直到遇到非数字字符或字符串结束,返回转换后的整数值(仅支持的最大整数值为INT_MAX
),并将遇到的非数字字符的地址存储到endptr
所指的指针中。 可通过判断*endptr
是否为NULL
(即endptr
是否指向空指针)来判断整个字符串是否都转换成功。
例如:
char str[] = "123abc";
char *endptr;
int num = strtol(str, &endptr, 10);
printf("%d\n", num); // 123
printf("%p\n", endptr); // 0xff114514
printf("%c\n", *endptr); // a
提示
atoi()
, strtol()
都位于<stdlib.h>
头文件中。
三、char* 字符串操作
3.1 获取字符串长度 strlen()
strlen(const char* str)
函数可以获取字符串str
的长度。
原理就是遍历字符串直到遇到'\0'
结束,并返回遍历的次数。
因此并不一定等于实际分配的内存大小。
char str[] = "hello";
int len = strlen(str);
printf("%d\n", len); // 5
3.2 获取字符串已分配空间 sizeof()
sizeof(char str*)
或sizeof(char str[])
:获取str
指向的字符串所占的字节数。
注意
由于普通字符串char
为 1 个字节,故sizeof(char)
可直接与字符串长度相对应而无需转换。 但由于字符串末尾的'\0'
字符也占用 1 个字节,故在未指定字符串长度时,sizeof()
获取的结果比实际字符串长度多 1。
char str[64] = "hello";
int size = sizeof(str);
printf("%d\n", size); // 64
3.3 字符串拼接 strcat()/strncat()
strcat(char* dest, const char* src)
将src
指向的字符串拼接到dest
指向的字符串的尾部。
strncat(char* dest, const char* src, size_t n)
将src
指向的字符串的前n
个字符拼接到dest
指向的字符串的尾部。
char str1[64] = "hello, ";
char str2 = "world";
strcat(str1, str2);
printf("%s\n", str1); // hello, world
char str1[64] = "hello, ";
char str2 = "world";
strncat(str1, str2, 2);
printf("%s\n", str1); // hello, wo
注意 (仅 C 语言)
如果dest
是直接赋值的指针类型(char *str = "..."
)而不是数组类型(char str[]
),执行strcat()
可能会导致访问未分配的空间而出现段错误。 (Segmentation fault (core dumped)
)
然而,如果是数组类型(char str[]
),虽然不会报错,但是可能导致内存溢出从而修改其它变量的值!
例如:
char *str1 = "hello, ";
char str2[] = "world";
strcat(str1, str2); // 错误,未分配足够的空间容纳str2字符串
改为数组类型后:
char str1[] = "hello, "; // 栈高位地址
char str2[] = "world"; // 栈低位地址
strcat(str1, str2); // 正确,不会报错
printf("%s\n", str1); //hello, world
printf("%s\n", str2); //world
char str2[] = "world"; // 栈高位地址
char str1[] = "hello, "; // 栈低位地址
strcat(str1, str2); // 正确,不会报错,但覆盖了高位的数据
printf("%s\n", str1); //hello, world
printf("%s\n", str2); //olld
改为指向数组类型的指针是同样的结果:
char str[] = "hello, ";
char *str1 = str;
char str2[] = "world";
strcat(str1, str2); // 正确,不会报错
3.4 字符串复制 strcpy()/strncpy()
strcpy(char* dest, const char* src)
函数将src
指向的字符串复制(覆盖)到dest
指向的字符串中。
strncpy(char* dest, const char* src, size_t n)
函数将src
指向的字符串的前n
个字符复制(覆盖)到dest
指向的字符串中。
char str1[64] = "hello,";
char str2[] = "world";
strcpy(str1, str2);
printf("%s\n", str1); //world
char str1[64] = "hello,";
char str2[] = "world";
strncpy(str1, str2, 5);
printf("%s\n", str1); //world,
strncpy(str1, str2, 6); // 末尾的'\0'字符也会被复制
printf("%s\n", str1); //world
注意
与strcat()
类似,如果dest
是直接赋值的指针类型(char *str = "..."
)而不是数组类型(char str[]
),执行strcpy()
可能会导致访问未分配的空间而出现段错误。 (Segmentation fault (core dumped)
)
3.5 字符串比较 strcmp()
int strcmp(const char* str1, const char* str2)
函数可以比较str1
和str2
指向的字符串是否相等,并返回一个整数值。
0 表示相等,负数表示str1
小于str2
,正数表示str1
大于str2
。
char str1[] = "hello, ";
char str2[] = "world";
int cmp = strcmp(str1, str2);
if (cmp == 0) {
printf("str1 == str2\n");
} else if (cmp < 0) {
printf("str1 < str2\n");
} else {
printf("str1 > str2\n");
}
3.6 字符串查找 strchr()
char* strchr(const char* str, int c)
函数可以查找字符串str
中第一个出现字符c
的位置,并返回一个指向该位置的指针。
char str[] = "hello, world";
char* p = strchr(str, 'l');
if (p) {
printf("%s\n", p); // llo, world
} else {
printf("not found\n");
}
3.7 字符串替换 strstr()
char* strstr(const char* str1, const char* str2)
函数可以查找字符串str1
中第一次出现字符串str2
的位置,并返回一个指向该位置的指针。
char str1[] = "hello, world";
char str2[] = "wo";
char* p = strstr(str1, str2);
if (p) {
printf("%s\n", p); // world
} else {
printf("not found\n");
}
3.8 字符串分割 strtok()
char* strtok(char* str, const char* delimiters)
函数可以将字符串str
按照分隔符delimiters
进行分割,并返回一个指向分割后的第一个字符串的指针。
char str[] = "hello, world, goodbye";
char* p = strtok(str, ", ");
while (p) {
printf("%s\n", p);
p = strtok(NULL, ", ");
}
// 输出:
// hello
// world
// goodbye
或
char str[] = "hello, world, goodbye";
for (char *p = strtok(str, ", "); p; p = strtok(NULL, ", "))
printf("%s\n", p);
// 输出:
// hello
// world
// goodbye
3.9 字符串格式化 sprintf()
与printf()
函数类似,sprintf()
函数可以将格式化字符串format
中的占位符替换为实际值,并将结果存储到str
指向的字符串中。
具体详见 printf 与 scanf.md
提示
strcat()
, strcpy()
, strlen()
, strcmp()
, strchr()
, strstr()
, strtok()
, sprintf()
都位于<string.h>
头文件中。
C++
注意
以下为 C++
内容,C 语言没有string
类型。
且C++
中无法通过char *str = "..."
的方式创建字符串指针
(ISO C++ forbids converting a string constant to ‘char\*’
)
四、string 与 char[] 互转
4.1 char[] 转 string: 直接赋值
char str[] = "hello, world";
string s = str;
或
char str[] = "hello, world";
char *p = str;
string s = p;
4.2 string 转 char[]: string.c_str()
const char* c_str(const string& str)
函数可以将string
类型转换为const char*
类型。
例如:
string str = "hello, world";
const char *p = str.c_str(); //必须加上const,否则编译器会报错,const char* 无法转换为 char*
五、int 与 string 互转
5.1 int/float/double 转 string: to_string()
string to_string(int value)
函数可以将整数value
转换为string
类型。
例如:
int value = 123;
string s = to_string(value);
cout << s << endl; // 123
5.2 string 转 int: stoi()
int/float stoi(const string& str, nullptr_t* endptr, int base)
函数可以将字符串str
转换为整数,并返回转换后的整数值。
例如:
string s = "123.456";
int value = stoi(s);
cout << value << endl; // 123
5.3 string 转 float/double: stof()/stod()
float/double stof(const string& str, nullptr_t* endptr)
函数可以将字符串str
转换为浮点数,并返回转换后的浮点数值。
例如:
string s = "123.456";
float value = stof(s);
cout << value << endl; // 123.456
提示
string
类型, to_string()
, stoi()
都位于<string.h>
头文件中。