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;
}