1.字符串的概念
字符串在C语言中并不是一个独立的类型,而是由字符数组来实现的。数组是由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元,每个单元储存一个字符,如下图所示:
注意图中数组末尾的字符\0,这是空字符,C语言用它来标记字符串的结束。空字符不是数字0,它是非打印字符,它的ASCII码的值为0,C语言中的字符串一定以空字符结束,意味着数组的容量必须至少比待存储字符串中的字符数多1,所以,如果数组有10个存储单元的字符串,则只能存储9个字符,剩下一个字节留给空字符。
那么什么是数组呢? 可以把数组看作是一行连续的多个存储单元,用更正式的说法是,数组是同类型数据元素的有序序列,下面举个例子来声明一个包含10个存储单元(或元素)的数组,每个单元储存一个char类型的值:
char name[10];
name后面的方括号表明这是一个数组,方括号中的10表明该数组中的元素数量,char表明每个元素的类型,见下图:
注意:"x"和'x'是不一样的,区别在于'x'是基本数据类型char类型的,而"x"是char数组类型的,然后"x"实际上是由两个字符组成:'x'和\0
2.字符串的长度
字符串的长度就是它所包含的字符的个数,计算的是从字符串的起始位置到第一个空字符('\0')之间的字符个数,空字符'\0'
本身不计入字符串长度。
例如,有个字符串为:
char str[] = "hello world";
则这个字符串的储存方式是
'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '\0'
注意:这里面有个空格字符 ' '
会占据一个字节,但它并不等同于 '\0'
。
2.1字符串长度的计算
C语言提供了标准库函数 strlen
来计算字符串的长度。该函数定义在 <string.h>
头文件中。
函数原型:
size_t strlen(const char *str);
-
参数:
str
是一个指向字符串的指针。 -
返回值:返回字符串的长度(
size_t
类型,通常是无符号整数)。关于数据类型相关的知识点可以参考我前一个笔记。
例子:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
size_t length = strlen(str);
printf("字符串的长度为: %zu\n", length); // 字符串的长度为: 13
return 0;
}
2.2字符串长度与数组大小的区别
-
字符串长度:是指字符串中有效字符的个数,不包括'\0'
-
数组大小:是指字符数组的总大小,包括'\0'和可能未使用的空间
例如:
char str[10] = "Hello";
-
字符串长度:5(Hello的长度)
-
数组大小:10(数组的总大小,使用sizeof()函数来计算)
3.常用的字符串函数
3.1strlen() - 计算字符串的长度
#include <string.h> size_t strlen(const char *str);
功能:计算以 \0
结尾的字符串 str
的长度,不包括 \0
。
返回值:返回字符串的长度(不包括 \0
),返回类型是 size_t
。
char *str = "hello";
size_t len = strlen(str); // len = 5
3.2strcpy() - 复制字符串
#include <string.h> char *strcpy(char *dest, const char *src);
功能:将字符串 src
复制到 dest
中,包括终止的 \0
。
返回值:返回指向目标字符串 dest
的指针。
注意:dest
必须有足够的空间来容纳 src
字符串,否则会发生缓冲区溢出。
char dest[20]; strcpy(dest, "hello"); // dest = "hello"
3.3strncpy() - 安全地复制字符串
#include <string.h> char *strncpy(char *dest, const char *src, size_t n);
功能:将字符串 src
的前 n
个字符复制到 dest
中,若 src
长度小于 n
,会用 \0
填充多余的位置。
返回值:返回指向目标字符串 dest
的指针。
char dest[10];
strncpy(dest, "hello", 10); // dest = "hello"
3.4strcat() - 连接两个字符串
#include <string.h> char *strcat(char *dest, const char *src);
功能:将字符串 src
连接到 dest
的末尾,并在末尾添加 \0
。
返回值:返回指向目标字符串 dest
的指针。
注意:dest
必须有足够的空间来容纳 src
字符串。
char dest[20] = "Hello "; strcat(dest, "World!"); // dest = "Hello World!"
3.5strncat() - 安全地连接字符串
#include <string.h>
char *strncat(char *dest, const char *src, size_t n);
功能:将 src
字符串的前 n
个字符连接到 dest
字符串末尾,并在末尾添加 \0
。
返回值:返回指向目标字符串 dest
的指针。
char dest[20] = "Hello "; strncat(dest, "World!", 3); // dest = "Hello Wor"
3.6strcmp() - 比较两个字符串
#include <string.h> int strcmp(const char *str1, const char *str2);
功能:比较两个字符串 str1
和 str2
,逐字符地比较它们的大小。
-
返回值:
-
如果
str1
<str2
,返回负值。 -
如果
str1
==str2
,返回 0。 -
如果
str1
>str2
,返回正值。
-
int result = strcmp("hello", "world"); // result < 0,因为 "hello" 小于 "world",比较的是ASCII码,h的ASCII码的值小于w的ASCII码的值
3.7strncmp() - 安全地比较两个字串
#include <string.h> int strncmp(const char *str1, const char *str2, size_t n);
功能:比较两个字符串 str1
和 str2
的前 n
个字符。
返回值:和 strcmp
类似,返回负值、0 或正值,表示字符串的大小关系。
int result = strncmp("hello", "hell", 4); // result == 0,因为比较了前 4 个字符
3.8memcpy() - 复制内存
#include <string.h> void *memcpy(void *dest, const void *src, size_t n);
功能:将 src
指向的内存块中的 n
个字节复制到 dest
指向的内存区域。
返回值:返回指向目标内存区域 dest
的指针。
char src[] = "hello"; char dest[6]; memcpy(dest, src, 6); // dest = "hello"
3.9memset() - 设置内存
#include <string.h> void *memset(void *str, int c, size_t n);
功能:将内存块 str
的前 n
个字节设置为指定的值 c
。
返回值:返回指向内存区域 str
的指针。
char str[10]; memset(str, 'A', 10); // str = "AAAAAAAAAA"
3.10strchr() - 查找字符
#include <string.h> char *strchr(const char *str, int c);
注意:参数2是一个整型值,但是,它包含的是一个字符值
功能:查找字符 c
在字符串 str
中第一次出现的位置,返回指向该字符的指针。如果没有找到,返回 NULL
。
返回值:返回指向第一次出现字符 c
的指针,若找不到返回 NULL
。
char *ptr = strchr("hello world", 'o'); // ptr 指向 "o" 第一次出现的位置,输出o world
3.11strrchr() - 从后向前查找字符
#include <string.h> char *strrchr(const char *str, int c);
注意:参数2是一个整型值,但是,它包含的是一个字符值
功能:从字符串 str
的末尾开始查找字符 c
,返回指向该字符的指针。如果没有找到,返回 NULL
。
char *ptr = strrchr("hello world", 'o'); // ptr 指向 "o" 最后一次出现的位置,输出orld
3.12strstr() - 查找子字符串
#include <string.h> char *strstr(const char *haystack, const char *needle);
功能:在字符串 haystack
中查找子字符串 needle
,返回指向第一次出现位置的指针。如果没有找到,返回 NULL
。
char *ptr = strstr("hello world", "world"); // ptr 指向 "world" 的位置,返回world
4.字符操作
一下的函数包含在ctype.h头文件中
函数名 | 功能 | 返回值说明 |
---|---|---|
isalpha(c) | 检查字符c 是否是字母(A-Z, a-z) | 如果c 是字母,返回非零值;否则返回0。 |
isdigit(c) | 检查字符c 是否是数字(0-9) | 如果c 是数字,返回非零值;否则返回0。 |
islower(c) | 检查字符c 是否是小写字母(a-z) | 如果c 是小写字母,返回非零值;否则返回0。 |
isupper(c) | 检查字符c 是否是大写字母(A-Z) | 如果c 是大写字母,返回非零值;否则返回0。 |
isspace(c) | 检查字符c 是否是空白字符(空格、制表符、换行等) | 如果c 是空白字符,返回非零值;否则返回0。 |
isxdigit(c) | 检查字符c 是否是十六进制数字(0-9, A-F, a-f) | 如果c 是十六进制数字,返回非零值;否则返回0。 |
tolower(c) | 转换字符c 为小写字母 | 如果c 是大写字母,返回其小写形式;否则返回c 本身。 |
toupper(c) | 转换字符c 为大写字母 | 如果c 是小写字母,返回其大写形式;否则返回c 本身。 |
isalnum(c) | 检查字符c 是否是字母或数字 | 如果c 是字母或数字,返回非零值;否则返回0。 |
isprint(c) | 检查字符c 是否是可打印字符 | 如果c 是可打印字符,返回非零值;否则返回0。 |
iscntrl(c) | 检查字符c 是否是控制字符 | 如果c 是控制字符,返回非零值;否则返回0。 |
isgraph(c) | 检查字符c 是否是可打印字符但不包括空白字符 | 如果c 是可打印字符且不是空格,返回非零值;否则返回0。 |
isblank(c) | 检查字符c 是否是空白字符(空格或制表符) | 如果c 是空白字符,返回非零值;否则返回0。 |
举例说明一下:
#include <ctype.h>
#include <stdio.h>
int main() {
char c = 'A';
if (isalpha(c)) {
printf("%c 是字母\n", c); // 输出: A 是字母
}
if (isdigit(c)) {
printf("%c 是数字\n", c); // 不会输出
}
if (islower(c)) {
printf("%c 是小写字母\n", c); // 不会输出
}
if (isupper(c)) {
printf("%c 是大写字母\n", c); // 输出: A 是大写字母
}
c = '9';
if (isdigit(c)) {
printf("%c 是数字\n", c); // 输出: 9 是数字
}
char d = 'b';
printf("%c 转换为大写是 %c\n", d, toupper(d)); // 输出: b 转换为大写是 B
return 0;
}