C/C++字符数组的输入输出方式详解

字符是C/C++读入数据最主要的类型。本篇将介绍单个字符数组/多个字符串及二维数组的输入输出方式与相关函数。

目录

单个字符串处理

​编辑

输入

逐个元素输入

整体串形式输入

输出

逐个输出

整体串形式输出

任一元素开始串形式输出

多个字符串处理

输入

gets_s(VS)

gets(Dev C++)

fgets(VS / Dev C++)

二维数组的输入输出


单个字符串处理

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZOI6YeM5pavSGVucnk=,size_20,color_FFFFFF,t_70,g_se,x_16

输入

逐个元素输入

在对字符数组进行输入操作时,可以逐个元素进行输入,甚至指定输入某个位置的某个元素。下面将从C和C++两种方式进行介绍:

C语言:scanf ( "%c", &数组元素 )

C++:cin>>数组元素

当然这就是最简单的输入方法,我们可以从下面两段代码理解:

/* C++基本实现 */
char s[20];
cin >> s[3] >> s[6];   //输入 Tj
cout << s[3] << s[6];  //输出 Tj

/* C语言基本实现 */
char v[20];
scanf("%c%c",&v[3],&v[6]);   //输入Sp
printf("%c%c",v[3],v[6]);  //输出Sp

scanf在使用时,需要加上取地址符 &,因为scanf规定后面必须是变量的地址。

那么我们再来讨论一下非正常输入的情况。在上段代码中那,要求输入两个字符,但是输入三个字符会怎么样呢?其实这和 cin 输入的普通处理相同,多余的数据会被存放在缓冲区中,而真正起作用的就是输入的前两个参数。

但是如果输入了呢?这里就有一个需要引起注意的地方。先看一段代码:

/* CASE 1: C++ */
char s[20];
cin >> s[2] >> s[3] >> s[4];
cout << int(s[2]) << ' ' << int(s[3]) << ' ' << int(s[4]) << endl;
//这时如果只输入两个字符,然后按回车(一个或多个),光标会一直跳动等待输入

/* CASE 2: C */
char s[20];
scanf("%c%c%c",&s[2],&s[3],&s[4]);
cout << int(s[2]) << ' ' << int(s[3]) << ' ' << int(s[4]) << endl;
//这时表现就和上面不同了
//如输入 ab ,按回车后不再等待,而第三位输出的是回车的ascii码

可以用一句话总结一下以上规律:多次逐个输入时,C处理回车的方式时当作字符读入,而C++不作为字符读入 ,等待继续输入。

整体串形式输入

看完上面的逐个输入,会觉得这是一种这时一种非常繁琐的方式。如果用逐个读入的方式读入整个字符串,需要使用一个循环才可完成全部输入操作。这里将介绍整体字符串形式输入的方式:

C语言:scanf ( "%s", 数组名 )

C++:cin>>数组名

这里我们可以把C方式和逐个输入比较一下,会发现这里不再需要加取地址符&,这是因为C/C++ 规定,数组名代表数组的首地址。样例代码如下:

/* C方式 */
char s[20]={'\0'};
scanf("%s",s);
cout<<s<<endl;

/* C++方式 */
char s[20]={'\0'};
cin>>s;
cout<<s<<endl;

//这两个程序的结果是一样的
//如输入 hello ,都会输出hello(后面都是尾零不输出)

在逐个输入时,如果多输入,在本次读取也不会产生问题,只是存储在缓冲区中。但是在整体输入时,如果输入字符个数超过数组大小便会导致弹窗报错。

同时,极容易忽视的一点是,输入的字符个数应当严格小于数组大小,因为字符串后面有一个隐式的尾零,也占数据的一位空间。这也导致字符串方式输入的字符数组最后总有一个尾零。

在字符串形式输入时,无论是C还是C++,回车都不会被当作一个字符读入。(回顾:逐个读入时C方式会读取回车当作普通字符存储)。我们可以用下面的代码加以验证:

char s[3];
scanf("%s", s);
for (int i = 0; i < 3; i++) {
    cout << int(s[i]) << ' ';
}
cout << endl;

//这时输入一个字符a ,输出三个数字:97 0 -52

可以看到输出结果没有回车,同时中间的数字0就是尾零的ascii码。最后的-52表示这里字符数组没有被输入,是一个随机值。这里可以在定义数组时简单操作,使数组初始元素都为尾零:

char s[3]={'\0'};  //此处操作
scanf("%s", s);
for (int i = 0; i < 3; i++) {
    cout << int(s[i]) << ' ';
}
cout << endl;

//这时输入一个字符a ,输出三个数字:97 0 0
//可以看到最后一位变成了0,也是尾零

输出

逐个输出

可以逐个输入,当然也可以逐个输出。逐个输出就是普通的字符输出方式:

C语言:printf ( "%c" , 数组元素 )

C++:cout<<数组元素

这个输出方式操作比较简单,看一段代码简单加深下印象:

char s[]="Henry";
cout<<s[3]<<'*';
printf("%c",s[4])<<endl;
//输出结果是 r*y

整体串形式输出

整体串形式输入输出大同小异:

C语言:printf ( "%s", 数组名 )

C++:cout<<数组名

当然尾零虽然在数组中,但是其存在意义是标志字符串的结束,所以不会被输出。

此外需要注意的是,在整体输出时,如果字符串中间某位置存在显式尾零,则输出时只会输出到第一个尾零的前一个字符为止:

char s[]="Henry\0 is so handsome!";
cout<<s<<endl;
printf("%s",s);

//输出的内容是两行的 Henry
//太可惜了,区区一个尾零让读者不知道博主有多帅!所以一定要注意尾零哦!

尾零虽然不输出,但是也是必不可少的。如果手动取出末尾的尾零(换成其他字符),则在正常字符后会出现一堆乱字符:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZOI6YeM5pavSGVucnk=,size_20,color_FFFFFF,t_70,g_se,x_16

乱字符表示数组已经越界读取。此时无论乱字符出现多少都是正常的,这是因为会一直读到遇到第一个尾零为止。所以乱字符的多少完全取决于外部尾零的尾零。所以以字符串形式输出不含尾零的字符数组是不可取的方法。

任一元素开始串形式输出

在了解了逐个输出和串形式整体输出后,问题出现了:如果想从串中间某位置开始输出后面所有内容,用逐个输出显得过于繁杂,而串整体输出又达不到预期目的(起点固定)。这时便可以引入任一元素开始串形式输出的方法:

char s[]="hello world";
printf("%s\n",&s[6]);
cout<<&s[6]<<endl;
//输出是两行world

所以可以归纳为:

C语言:printf ( "%s", &数组元素名 )

C++:cout<<&数组元素名 

这里发现在开始字符处都要加上取地址符。其实可以和串整体输出联系起来:串整体输出时,直接用数组名,其实是因为数组名表示了数组的首地址,所以换言之也是读取了地址,再从地址开始一直读取到尾零为止。

同样输入也可以用相同的方式进行起始点控制:

C语言:scanf ( "%s", &数组元素名 )

C++:cin>>&数组元素名 


多个字符串处理

输入

多个字符串的输入方式和单个字符串没有太大的区别,只是输入时参数变为两个:

C语言:scanf ( "%s%s" ,a,b )

C++:cin>>a>>b

看似没有什么特别的地方。但是这里有一个需要考虑的问题:编译器怎么区分输入的是两个字符串。换言之输入时什么符号作为这两个字符串的间隔?

将这个代码稍加改进,可以做以下的探究:

char a[20],b[20],c[20],d[20];

/* C++方式 */
cin>>a>>b;             //输入 ab cd(中间有空格)
cout<<a<<'#'<<b<<endl; //输出 ab#cd

/* C方式 */
scanf("%s%s",c,d);     //输入 mn pq(中间有空格)
printf("%s#%s",c,d);   //输出 mn#pq

通过这一段代码我们可以清晰地看到作为分隔符的这个字符就是空格(当然回车也可以,但在这里不做讨论),也就是说使用cin和scanf(一般情况下)从键盘上输入的字符串不会读入空格,空格在此处是一个分隔符而不是输入串中的合法字符。

为了读入空格,除了对cin和scanf进行高级设置之外,还可以使用这几个可以读入空格的函数:

gets_svs2019/22中可使用
getsDev C++中可以使用
fgetsvs和Dev中都可以使用

下面就是对这几个函数使用方法的详细介绍:

gets_s(VS)

在gets_s函数中,字符串输入结束的标志只有回车。可以操作下面的示例代码:

/* 注意:只能在VS编译器中编译 */
char m[20],n[20];
gets_s(m);
gets_s(n);
cout<<m<<endl<<n<<endl;

//输入两个中间含空格的字符串,并用回车间隔,输出一样的字符串(含空格)

可以读取空格就是 gets_s 函数神奇的地方。同时输入时也要注意,输入的字符个数应当严格小于数组长度。因为串方式输入后面会附带一个隐式尾零,所以需要留下部分空间。

gets(Dev C++)

使用方法和 gets_s 完全相同,同时也要注意输入个数的问题,在dev中运行。

fgets(VS / Dev C++)

标准函数语句:fgets ( 字符数组名,最大长度,stdin )

fgets 与 gets 和 gets_s 的最大区别就是回车的读取。当连续利用两个 fgets 读入字符串时,输出会多两个换行,因为此处换行虽然具有结束字符串输入的作用,但是也会被 fgets 读入。


二维数组的输入输出

二维数组的输入输出使用和一维数组完全相同的方式。需要注意的是,二维数组双下标表示元素(实现逐个输入输出),单下标表示一维数组(实现串方式输入输出)。


版权声明:本文为m0_65305142原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。