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

C++:字符数组

一、字符数组介绍

数组的元素如果是字符类型,这种数组就是字符数组,字符数组可以是一维数组,可以是二维数组
(多维数组)。我们接下来主要讨论的是一维的字符数组。
char arr1[5]; //⼀维字符数组
char arr2[3][5];//⼆维字符数组
C 语言中使用双引号括起来一串字符表示字符串,这种方式虽然在 C++ 中也是支持的,但是一般我们会将这种字符串称为C语言风格的字符串。如果需要将一个C语言风格的字符串存储起来,就可以是字符数组。
1. 字符数组的初始化
char a[10]; //字符数组的创建
字符数组的创建同一维数组的创建我就不再赘述了,但是字符串数的初始化有2种方式,如下:
//方式1
char ch1[10] = "abcdef";
char ch2[] = "abcdef";//如果数组初始化的时候,数组的大小可以省略不写,数组大小会根据初
始化内容来确定
//方式2
char ch3[10] = {'a', 'b', 'c', 'd', 'e', 'f'};//对数组中的元素逐个初始化,但是最后不会有'\0'
char ch4[] = {'a', 'b', 'c', 'd', 'e', 'f'};
如果调试看⼀下 ch2 ch4 数组的内容,我们会明显的发现,数组 ch2 中多一个 '\0' 字符,这
是因为字符串的末尾其实隐藏一个 '\0' 字符,这个 '\0' 是字符串的结束标志,在打印字符串的时
候遇到 '\0' ,打印结束。当我们把字符串存放在一个字符数组中的时候,这时候也可以把字符数组当做字符串看待。
2. 字符串长度-strlen
字符数组中存放的着字符串,这个字符数组有自己的长度,也就是数组的元素个数,这个可以使用
sizeof计算,那数组中存放的字符串的长度是多少?其实C/C++中有一个库函数叫:strlen,可以求字符串的长度,其实统计的就是字符串中 \0之前的字符个数。strlen需要的头文件是<cstring> 。
size_t strlen ( const char * str );
//str - 指针,存放的是字符串的起始地址,从这个地址开始计算字符串的⻓度

那我们应该怎么使用这个函数呢?下面给出代码演示:

#include <iostream>
#include <cstring>
using namespace std;
int main()
{
 char arr[20] = "abcdef";
 cout << "数组的⻓度:" << sizeof(arr)/sizeof(arr[0]) << endl;
 cout << "字符串的⻓度:" << strlen(arr) << endl;
 return 0;
}

二、字符数组的输入

1.输入没有空格字符串

使用scanf函数和字符数组来实现:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	char arr[20] = { 0 };
	//输入
	scanf("%s", arr);
	//输出
	printf("%s", arr);
	return 0;
}
使用cin和字符数组来实现:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	char arr[20] = { 0 };
	//输入
	cin >> arr;
	//输出
	printf("%s", arr);
	return 0;
}
上面两个代码都是将字符串读取后从数组的起始位置开始存放的,当然我们也可以指定位置位置存放,比如从数组的第二个元素的位置开始存放,如下代码:
#include <iostream>
using namespace std;
int main()
{
	char arr[20] = { 0 };
	//输入
	cin >> arr + 1;//arr表示数组的起始位置,+1意思是跳过一个元素,就是第二个元素的位置
	//可以通过调试观察一下arr的内容
	cout << arr + 1;
	return 0;
}

当我们输入hello时,通过调试可以发现是从数组的第二个位置开始存放的。

2.输入有空格的字符串

scanf的方式:
当输入"hello world"的时候,实际上scanf只读取了hello就结束了,也就是遇到空格就结束了。我们在使用占位符%s输入字符串时需要注意 它其实不能简单地等同于字符串。它的规则是,从当前第一个非 空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。 因为 %s 的读取不会包含空白字符,所以无法用来读取多个单词,除非多个 %s一 起使用。 这也意味着, scanf() 不适合读取可能包含空格的字符串,比如书名或歌曲名。另外有一 个细节注意⼀下, scanf() 遇到 %s 占位符,会在字符串变量末尾存储一个 \0 字符。
同时 scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串
时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用 %s 占位符时,可以指定读入字符串的最长长度,即写成 %[m]s ,其中的 [m] 是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃,这样就不会有数组溢出的风险了。
cin的方式:
我们可以发现 结果也是一样,没有任何区别。 其实cin在读取一个字符串的时候,在遇到空白字符的时候,就认为字符串结束了,不再继续 往后读取剩余的字符,同时将已经读取到的字符串末尾加上\0,直接存储起来。
那我们应该使用什么方式来解决这种情况的问题呢?
(1) gets 和 fgets
使用  gets 函数的方式,这种方式能解决问题,但是因为 gets 存在安全性问题,在C++11中取消了
gets ,给出了更加安全的方案: fgets。
gets 是从第一个字符开始读取,一直读取到 \n 停止,但是不会读取 \n ,也就是读取到的内容中没有包含 \n ,但是会在读取到的内容后自动加上 \0 。gets 虽然在一些编译器中能够运行成功,但也会存在警告以及潜在的问题。

scanf("%d",&n);读取一个整数后,它不会消耗输入缓冲区中的换行符(即用户按下的Enter键)。这个换行符会被gets(arr);视为有效的输入,因此gets()实际上可能不会等待用户进一步输入。当然gets()还有除此之外的不足之处,这里就不赘述了。所以在代码中还是慎用gets函数。

fgets 也是从第一个字符开始读取,最多读取 num-1 个字符,最后⼀个位置留给 \0 ,如果 num 的长度是远大于输⼊的字符串长度,就会一直读取到 \n 停止,并且会读取 \n ,将 \n 作为读取到内容的一部分,同时在读取到的内容后自动加上 \0
#include <iostream>
using namespace std;
int main()
{
	char arr[20] = { 0 };
	//输入
	fgets(arr, sizeof(arr), stdin);
	//输出
	printf("%s", arr);
	return 0;
}

在这里说明一下它的三个参数,第一个是我们输入的数组的地址,第二个是要输入到数组中的最大字符数(包括终止符'\0'),第三个是输入流的来源,因为我们是使用键盘输入的,所以可以使用stdin用作从标准输入中读取的参数。

char * fgets ( char * str, int num, FILE * stream );

(2)scanf

当然C语言中使用  scanf 函数其实也能做到读取带有空格的字符串,只是不常见而已。方式就是
"%s" 改成 "%[^\n]s" ,其中在 % s 之间加上了 [^\n] ,意思是一直读取,直到遇到\n ,这样即使遇到空格也就不会结束了。这种方式读取,不会将 \n 读取进来,但会在读取到的字符串末尾加上 \0。
#include <cstdio>
int main()
{
	char arr[20];
	scanf("%[^\n]s", arr);
	printf("%s\n", arr);
	return 0;
}

(3)getchar

使用  getchar 逐个字符的读取,也是可以读取一个字符串的。
#include <cstdio>
int main()
{
	char arr[20] = { 0 };
	char ch = 0;
	int i = 0;
	while ((ch = getchar()) != '\n')
	{
		arr[i++] = ch;
	}
	arr[i] = '\0';
	printf("%s\n", arr);
	return 0;
}

三、字符数组的输出

1. C 语言中可以在 printf 函数中使用 %s 占位符的方式,打印字符数组中的字符串。
2. C++ 中使用 cout ,可以直接打印字符数组中的字符串内容。
3. 也可以采用循环的方式逐个字符打印字符串的内容。
以下三个演示中的cout都可以使用scanf来实现相同的效果。
//方法1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	char a[] = "hello world";
	cout << a << endl;
	printf("%s\n", a);
	return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
//方法2
//单个字符的打印,直到\0字符,\0不打印
int main()
{
	char a[] = "hello world";
	int i = 0;
	while (a[i] != '\0')
	{
		cout << a[i];
		i++;
	}
	cout << endl;
	return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
//方法3
//单个字符打印,根据字符串长度来逐个打印,
// strlen可以求出字符串的长度,不包含\0
int main()
{
	char a[] = "hello world";
	int i = 0;
	for (i = 0; i < strlen(a); i++)
	{
		cout << a[i];
	}
	cout << endl;
	return 0;
}

http://www.kler.cn/a/472373.html

相关文章:

  • 微信小程序map组件所有markers展示在视野范围内
  • 【网络安全 | 漏洞挖掘】通过监控调试模式实现价值$15k的RCE
  • Web应用安全-漏洞扫描器设计与实现
  • uniapp vue2版本如何设置i18n
  • 二维数组:求最大元素及其所在的行坐标及列坐标(PTA)C语言
  • 游戏引擎学习第77天
  • SQL—替换字符串—replace函数用法详解
  • ffmpeg7.0 合并2个 aac 文件
  • 使用 MongoDB 构建高效的 NoSQL 数据库
  • ChatGPT如何赋能办公
  • 以太网MAC和PHY层问题的“对症下药”攻略
  • 缓存-Redis-API-Redission-可重入锁-原理
  • IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)
  • Centos7 安装MySQl8.0报错:“MySQL 8.0 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包
  • axios的学习笔记
  • 【SQL】进阶知识 — 各大数据库合并几条数据到一行的方式
  • 2025-01-07 Unity 使用 Tip3 —— 游戏保存数据到 Application.persistentDataPath 不生效解决方案更新
  • 基于Spring Boot的仓库租赁管理系统
  • el-dialog 组件 在<style lang=“scss“ scoped>标签
  • 2025-01-06日SSH钓鱼日志
  • 冬季蜂巢内蜂群运动的自动化监测
  • c++开源协程库libgo介绍及使用,srs协程,boost协程 Boost::fiber
  • Redis奇幻之旅(四)4. Redis Cluster
  • 使用systemd管理MySQL服务器
  • AI 平台 GPU 节点上运行基于 PyTorch 的深度学习任务
  • Mac中配置vscode(第一期:python开发)