当前位置: 首页 > news >正文

C++编程基础(五):字符数组和字符串

文章目录

  • 一、C 风格字符串(字符数组)
    • 1. 定义与初始化
    • 2.字符和字符串的区别
    • 3.字符数组的地址
    • 4.字符数组的输入输出
      • 安全的行输入:cin.getline()
    • 5. 常用 C 风格字符串函数
    • 6. 字符检查
  • 二、std::string 类
    • 1.构造与初始化
    • 2.常用操作
      • 访问与长度
      • 修改:拼接与附加
      • 修改:插入、删除、替换
      • 比较
      • 查找与子串
      • 输入输出
      • 字符串反转
  • 三、字符串与数值的转换
    • 1. 字符串 -> 数值
      • 传统 C 方式 (`<cstdlib>`)
      • 现代 C++ 方式 (C++11+, `<string>`)
    • 2. 数值 -> 字符串 (C++11+, `<string>`)
  • 四、字符数组 vs. 字符串

在 C++ 中处理文本数据主要有两种方式:继承自 C 语言的字符数组(C 风格字符串),以及 C++ 标准库提供的 std::stringstd::string 提供了更强大、更安全、更易用的接口,是现代 C++ 编程的首选。

本文将详细介绍这两种方式的定义、使用和关键区别。

一、C 风格字符串(字符数组)

C 风格字符串本质上是一个以特殊字符 \0(称为 NULL 终止符)结尾的 char 数组。

1. 定义与初始化

字符数组的声明与其他数组类似,但可以使用字符串字面量(用双引号括起)来快速初始化。

// 数据类型 数组名[长度];
char arr1[10];// 方式一:使用字符串字面量初始化
// 编译器会自动在末尾添加 \0
char arr2[10] = "hello"; // arr2 内容为 {'h', 'e', 'l', 'l', 'o', '\0', ?, ?, ?, ?}
char arr3[] = "world";   // 编译器自动推断长度为 6 (world 5个 + \0 1个)// 方式二:使用字符列表初始化
// 必须手动添加 \0 才能作为字符串使用
char arr4[10] = {'a', 'b', 'c', '\0'};

2.字符和字符串的区别

char是字符,也是0~127的无符号整数。通常能用一个char表示的被称为ASCII编码。

字符串是以NULL结尾的连续地址。常用转义字符\0表示。

为字符串字面量分配空间时,必须确保数组长度至少为字符数 + 1(为 \0 留出空间)。

char arrName[5] = "abcde"; // 错误!没有空间存放 \0!
char arrName[6] = "abcde"; // 正确(5 个字符 + 1 个 \0)
char arrName[5] = {'a', 'b', 'c', 'd', 'e'}; // 正确,是字符数组,不是字符串

3.字符数组的地址

对于字符数组,不能直接取地址,否则输出的是整个字符串,直到遇到\0。所以就算是普通的char单个字符地址,我们也需要(void*)来强转它的类型。(void*)为无类型指针,一般被称为通用指针或泛指针。

char c1[10] = "abcde";
char c2[10] = {'a', 'b', 'c', 'd', 'e'};
char c3[10] = {"abcde"};
cout << c1 << endl; // abcde
cout << &c1[0] << endl;  // abcde
cout << &c1[1] << endl; // bcdecout << (void*)c1 << endl; // 
cout << (void*)&c1[0] << endl;
cout << (void*)&c1[1] << endl;

4.字符数组的输入输出

cincout

  • cout 在遇到 char* 类型时,会假定它是一个 C 风格字符串,并打印直到 \0 为止。
  • cin 在读取 char[] 时,会以空格、制表符或换行符作为分隔符,导致无法读取包含空格的完整句子。
char c[100];cin >> c; // 如果输入 ab scdd
cout << c; // 输出 ab

安全的行输入:cin.getline()

要读取包含空格的一整行,可以使用 cin.getline()

char line[100];
cin.getline(line, 100); // 最多读取 99 个字符(为 \0 留空cout << line << std::endl; // 输出与输入一样
return 0;

5. 常用 C 风格字符串函数

需要包含头文件 <cstring>

函数描述
strlen(p)返回字符串 p 的长度(不包括 \0)。
strcpy(p1, p2)p2 复制到 p1
strncpy(p1, p2, n)最多将 p2n 个字符复制到 p1
strcat(p1, p2)p2 拼接到 p1 的末尾。
strncat(p1, p2, n)最多将 p2n 个字符拼接到 `p1。
strcmp(p1, p2)按字典序比较 p1p2p1<p2 返回-1, ==返回0, p1>p2 返回1)。
strncmp(p1, p2, n)比较前 n 个字符。
stricmp(p1, p2)/strcasecmp(p1, p2)不区分大小写比较两个字符串
strnicmp(p1, p2, n)不区分大小写比较字符串p1p2n个字符。
strchr(p, c)查找 cp 中首次出现的位置,返回指针,否则返回 NULL
strrchr(p, c)查找 cp 中最后出现的位置。
strlwr将字符串中大写字母转成小写字母
strupr将字符串中小写字母转成大写字母
memset(void *s, int c, size_t n)s 指向的 n 字节内存设为字节值 c;常用于清零,仅对 0 或 -1 安全用于多字节类型。

strcpystrcat 假定目标数组 p1 有足够的空间,如果空间不足,它们会写入数组边界之外,破坏内存。在 C++ 中应避免使用它们,优先使用 std::stringmemset 按字节赋值,假设 int 是 4 字节,那么每个 int 会被设为 0x01010101(十进制 16843009),而不是 1。

6. 字符检查

头文件 <cctype> 提供了一系列用于检查单个字符类型的函数。

函数作用
isalpha(int c)检查字符是否为字母(大小写)
isupper(int c)检查是否为大写字母(‘A’–‘Z’)
islower(int c)检查是否为小写字母(‘a’–‘z’)
isdigit(int c)检查是否为十进制数字(‘0’–‘9’)
isxdigit(int c)检查是否为十六进制数字(‘0’–‘9’, ‘a’–‘f’, ‘A’–‘F’)
isspace(int c)检查是否为空白字符(空格、换行、回车、制表等)
iscntrl(int c)检查是否为控制字符(如 \n, \r, \t, \0 等)
ispunct(int c)检查是否为标点符号(可打印但非字母、数字、空格)
isalnum(int c)检查字符是否为字母或数字(alphanumeric)
isprint(int c)检查是否为可打印字符(包括空格)
isgraph(int c)检查是否为图形字符,等效于isalnum(int c)

二、std::string 类

std::string 是 C++ 标准库中的类(在 <string> 头文件中),定义隐藏了字符串的数组性质,可以像处理普通变量一样处理字符串。string对象和字符数组的主要区别是:可以将string对象声明为简单变量,而不是数组。

1.构造与初始化

// 1. 默认构造
std::string s1; // s1 = ""// 2. C 风格字符串构造
std::string s2 = "Hello";
std::string s3("World");// 3. 复制构造
std::string s4(s2); // s4 = "Hello"
std::string s5 = s3; // s5 = "World"// 4. 填充构造 (n 个 c)
std::string s6(10, 'A'); // s6 = "AAAAAAAAAA"

2.常用操作

std::string 提供了丰富的成员函数来处理字符串。

访问与长度

std::string s = "Hello";// 获取长度
std::cout << s.length() << std::endl; // 5
std::cout << s.size() << std::endl;   // 5 (与 length 相同)// 判断是否为空
std::cout << s.empty() << std::endl; // 0 (false)// 访问单个字符 (同数组)
std::cout << s[1] << std::endl; // 'e'// 安全访问 (带边界检查,会抛出异常)
std::cout << s.at(1) << std::endl; // 'e'

修改:拼接与附加

std::string s1 = "Hello";
std::string s2 = "World";// 1. 使用 + 运算符
std::string s3 = s1 + " " + s2; // s3 = "Hello World"// 2. 使用 += 运算符
s1 += "!"; // s1 = "Hello!"// 3. 使用 append()
s2.append(" C++"); // s2 = "World C++"// 4. 使用 push_back() (仅限单个字符)
s2.push_back('!'); // s2 = "World C++!"

修改:插入、删除、替换

std::string s = "Hello C++";// 1. 插入 (insert)
s.insert(6, "Beautiful "); // 在索引 6 处插入
// s = "Hello Beautiful C++"// 2. 删除 (erase)
s.erase(6, 10); // 从索引 6 开始,删除 10 个字符
// s = "Hello C++"// 3. 替换 (replace)
s.replace(6, 3, "World"); // 从索引 6 开始,替换 3 个字符
// s = "Hello World"

比较

可以直接使用关系运算符进行字典序比较。

std::string s1 = "abc";
std::string s2 = "abd";
if (s1 < s2) {std::cout << "s1 小于 s2" << std::endl;
}
if (s1 == "abc") {std::cout << "s1 等于 \"abc\"" << std::endl;
}

查找与子串

find() 是最常用的查找函数,如果找不到,它返回一个特殊值 std::string::npos

std::string s = "Hello World, World";// 1. 查找 (find)
size_t pos1 = s.find("World"); // 从头开始查找
if (pos1 != std::string::npos) {std::cout << "第一次出现 'World' 的索引: " << pos1 << std::endl; // 6
}// 2. 反向查找 (rfind)
size_t pos2 = s.rfind("World"); // 从末尾开始查找
std::cout << "最后一次出现 'World' 的索引: " << pos2 << std::endl; // 13// 3. 截取子串 (substr)
std::string sub = s.substr(6, 5); // 从索引 6 开始,截取 5 个字符
std::cout << "子串: " << sub << std::endl; // "World"

输入输出

cin 同样会遇到空格停止。读取整行应使用 std::getline

string str1,str2;
//读入方式1遇到换行停止
getline(cin, str1);
//读入方式2遇到空格停止
cin>>str2;//输出方式1
printf("%s\n",str1.c_str());
//输出方式2
cout<<str2<<end1;

字符串反转

使用<algorithm> 头文件里面的reverse函数

#include <iostream>
#include <algorithm>
using namespace std;int main() {string s1;cin >> s1;reverse(s1.begin(),s1.end());cout << s1 << endl;return 0;
}

三、字符串与数值的转换

1. 字符串 -> 数值

传统 C 方式 (<cstdlib>)

这些函数不进行错误检查。如果转换失败,通常返回 0。

  • atoi(p): 字符串 (const char*) 转 int
  • atof(p): 字符串转 double
  • atol(p): 字符串转 long

现代 C++ 方式 (C++11+, <string>)

这些函数更安全,如果无法转换会抛出异常。

  • std::stoi(s): std::stringint
  • std::stod(s): std::stringdouble
  • std::stol(s): std::stringlong
#include <string>
#include <iostream>int main() {std::string s_num = "123.45";int i = std::stoi(s_num);     // 转换 "123" (遇到 . 停止)double d = std::stod(s_num);  // 转换 "123.45"std::cout << "Int: " << i << ", Double: " << d << std::endl;return 0;
}

2. 数值 -> 字符串 (C++11+, <string>)

使用 std::to_string 是最简单的方式。

#include <string>
#include <iostream>int main() {int i = 42;double pi = 3.14;std::string s_i = std::to_string(i);    // "42"std::string s_pi = std::to_string(pi);  // "3.140000"std::cout << s_i << " 和 " << s_pi << std::endl;return 0;
}

四、字符数组 vs. 字符串

特性C 风格字符串 (char[])std::string
内存管理手动(大小固定,易溢出)自动(动态调整大小)
安全性低(strcpy, gets 等)高(边界检查,at())
功能基础(需 )丰富(查找、替换、插入等)
易用性复杂,易错简单直观
http://www.dtcms.com/a/531886.html

相关文章:

  • 在线旅游网站平台有哪些山东泰安房价2023最新价格
  • [3D Max 基础知识分享]—多孔结构模型编辑
  • 【C++篇】C++11入门:踏入C++新世界的大门
  • 爬虫数据清洗可视化案例之全球灾害数据
  • QT(c++)开发自学笔记:4.Qt 3D简易实现
  • Vue3 自定义事件
  • 上海住房和城乡建设厅网站个人备案网站可以做产品推广
  • Android OpenGLES视频剪辑示例源码
  • 做淘宝客导购网站推广wordpress 明星
  • WebForms 页面
  • Leetcode 39
  • 【STM32项目开源】基于STM32的智能水质检测系统
  • 设计模式-迭代器模式(Iterator)
  • GitHub等平台形成的开源文化正在重塑天热e
  • 做网站需要用什么开发软件有哪些制作视频的软件
  • github中获得Personal Access Token
  • 从RDPDD!DrvEscape到RDPWD!ShareClass::UPSendOrders
  • RiPro数据转换CeoMax插件
  • IA复习笔记4 路由
  • 邯郸手机网站建设服务常见的网络推广工具
  • NTRU 加密系统原理及示例:NTRU、CTRU以及ITRU
  • k8s高频面试题汇总
  • 一篇文章理解LRC校验:
  • 石家庄免费网站建设百度收录入口提交查询
  • 专业提供网站建设服务培训学校 网站费用
  • 找做网站公司需要注意什么条件国外网站建设什么价格
  • 阮一峰《TypeScript 教程》学习笔记——tsconfig.json 文件
  • python如何做声音识别
  • 解决Docker磁盘空间不足导致MySQL启动失败
  • 【微服务组件】Springboot结合Dubbo实现RPC调用