C 字符串

C 字符串简介

在 C 语言中,字符串指的就是一串字符,它本质上是一个以 '\0' 结尾的字符数组。在 C 语言中,我们可以使用字符数组的方式来定义一个字符串。

语法:

char 字符串名[] = 值;

说明:

当编译器遇到使用双引号括起来的字符串时,默认情况下会自动在其末尾追加一个 '\0' 字符。比如 char str[] = "lvye"; 的存储结构如下图所示。

C 字符串的存储结构

实际上,定义字符串有以下 3 种方式。

// 方式 1
char str[] = "lvye";

// 方式 2
char* str = "lvye";

// 方式 3
char str[] = {'l', 'v', 'y', 'e', '\0'};

方式 2 使用了指针的语法。关于指针的使用,我们会在后面 “C 指针” 一节中详细介绍,这里简单了解即可。

方式 3 是使用了数组的语法。在这种语法中,'\0' 是必需的。'\0' 是一个终止字符,以表示字符串的结束。如果 '\0' 省略,此时 str 代表的就不再是一个字符串,而是一个普通字符数组。

提示: 如果想要使用 printf() 函数打印一个字符串,应该使用 “%s” 格式。其中 s 是 “string” 的缩写。

示例 1:C 定义字符串

#include <stdio.h>

int main(void)
{
    char str[] = "lvye";

    printf("%s", str);      // 打印字符串
    return 0;
}

运行结果如下。

lvye

分析:

如果小伙伴们接触过其他编程语言(比如 PythonJavaScript),会发现它们都可以使用一个普通变量来保存一个字符串。但 C 语言是没有字符串类型的变量的,而必须使用数组的方式来保存一个字符串。

注意: 字符串字面量(如 "lvye")通常存储在只读内存区域。

示例 2:C 获取字符串中某个字符

#include <stdio.h>

int main(void)
{
    char str[] = "lvye";
    char ch1 = str[0];
    char ch2 = str[1];

    printf("%c\n", ch1);      // 打印第 1 个字符
    printf("%c\n", ch2);      // 打印第 2 个字符
    return 0;
}

运行结果如下。

l
v

分析:

字符串本身就是一个数组,所以可以使用下标的方式来获取某一个字符。需要注意的是,下标是从 0 开始的。

示例 3:C 修改字符串中某个字符

#include <stdio.h>

int main(void)
{
    char str[] = "lvye";
    str[0] = 'L';

    printf("%s", str);
    return 0;
}

运行结果如下。

Lvye

C 字符串常见问题

1. 'a' 和 "a" 这两个是等价的吗?如果不是,那么它们之间的区别是什么?

'a' 和 "a" 并不是一个东西,'a' 是一个字符,而 "a" 是一个字符串。对于字符串来说,编译器会在后面自动加上一个结束符 “\0”,所以 "a" 的存储结构如下图所示。

C 字符串

我们一定要记住,凡是使用单引号的就是一个字符,凡是使用双引号的就是一个字符串。

C 输入字符串

从之前的学习可以知道,字符的输入输出我们可以使用 getchar() 和 putchar() 这 2 个函数。而对于字符串的输入输出,有没有类似的函数呢?其实是有的。

1. gets() 函数

在 C 语言中,我们可以使用 gets() 函数来快速输入一个字符串。其中,gets 是 “get string” 的缩写。

语法:

gets(字符串)

说明:

gets() 本质上是 scanf() 的一种简写方式,下面 2 种方式是等价的。

// 方式 1
gets(str);

// 方式 2
scanf("%s", &str);

注意:

  • gets() 是属于 <stdio.h> 标准库的函数,而不是属于 <string.h> 标准库。
  • gets() 函数存在严重的安全性问题,因为它不会检查输入的字符串是否会超出目标缓冲区的大小,可能会导致缓冲区溢出。因此,我们强烈建议避免使用 gets() 函数,而应该使用更安全的替代方案(如使用 fgets() 函数)。

示例 4:使用 gets() 输入字符串

#include <stdio.h>

int main(void)
{
    char str[10];

    printf("请输入字符串:");
    gets(str);
    printf("%s", str);

    return 0;
}

运行之后,我们输入 “lvye”,然后输出结果如下。

lvye

分析:

特别注意,数组长度必须 “至少” 要比字符串实际长度大 1。这是因为字符串最后自带了一个结束符 '\0',而该结束符本身也占了一个字节。一般情况下,我们只是笼统给一个大于实际长度值的数就可以了,比如 10、20、100 之类的。

2. fgets() 函数

gets() 函数存在严重的安全性问题,因此我们更推荐使用 fgets() 函数来输入一个字符串。fgets() 函数可以指定读取的最大字符数,从而防止缓冲区溢出。

语法:

fgets(str, size, stdin)

说明:

fgets() 函数接收以下 3 个参数。

  • str:是一个字符数组。
  • size:是要读取的最大字节数(包括 '\0')。
  • stdin 表示从标准输入读取。

示例 5:使用 fgets() 输入字符串(推荐)

#include <stdio.h>
int main(void)
{
    char str[10];

    printf("请输入字符串:");
    fgets(str, sizeof(str), stdin);
    printf("%s", str);

    return 0;
}

运行之后,我们输入 “lvye”,然后输出结果如下。

lvye

分析:

特别注意,使用 fgets() 函数时,数组长度必须足够存储输入的字符串加上结尾的 '\0'。fgets() 会读取最多 size - 1 个字符,并在末尾添加 '\0'。另外,fgets() 还会将输入中的换行符(如果存在且未超出读取长度)也读取到字符串中,我们可能需要手动去除结尾的换行符。

C 输出字符串

在 C 语言中,我们可以使用 puts() 函数来输出(打印)一个字符串。puts,是 “put string” 的缩写。

语法:

puts(字符串)

说明:

puts(str) 会自动在末尾添加一个换行符 \n,而 printf("%s", str) 不会。下面 2 种方式是等价的。

// 方式 1
puts(str);

// 方式 2
printf("%s\n", str);

注意: puts() 是属于 <stdio.h> 标准库的函数,而不是属于 <string.h> 标准库。

示例 6:使用 puts() 打印字符串

#include <stdio.h>

int main(void)
{
    char str[] = "lvye";

    puts(str);
    return 0;
}

运行结果如下。

lvye

分析:

在实际开发中,对于字符串的输入输出,我们推荐使用 fgets() 来输入字符串(安全),以及使用 puts() 或 printf() 来输出字符串。

C 字符串函数

在 C 语言中,与字符串相关的函数都存放在 <string.h> 标准库中,常用的函数如下表所示。

C 字符串函数
字符串操作
strlen() 计算字符串的长度(不包含结束符)
strcat() 将一个字符串接到另一个字符串后面
strncat() 将一个字符串的前 n 个字符接到另一个字符串后面
strcmp() 比较两个字符串的大小
strncmp() 比较两个字符串的前 n 个字符的大小
strcpy() 将一个字符串完全复制到另一个地方
strncpy() 将一个字符串的前 n 个字符复制到另一个地方
strtok() 将一个字符串按分隔符切分成多个小段(标记)
strchr() 从字符串 “头部” 开始找某个字符第一次出现的位置
strrchr() 从字符串 “尾部” 开始找某个字符第一次出现的位置(也就是最后一次出现的位置)
strstr() 在字符串中查找某个子串第一次出现的位置
strpbrk() 在字符串中查找第一个属于某个特定字符集合的字符。
strspn() 计算字符串开头连续 “属于” 某个特定字符集合的字符有多长
strcspn() 计算字符串开头连续 “不属于” 某个特定字符集合的字符有多长
内存块操作
memcpy() 将一块内存区域的数据复制到另一块区域(不处理重叠)
memmove() 将一块内存区域的数据复制到另一块区域(能正确处理区域重叠)
memset() 使用一个特定的字节值填充一块内存区域
memcmp() 比较两个内存区域的内容大小
memchr() 在一块内存区域中查找某个字节第一次出现的位置
非标准库函数
strupr() 将字符串转换为纯大写
strlwr() 将字符串转换为纯小写
strrev() 将字符串反转

上一篇: C 打印数组

下一篇: C 字符串长度

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号