字符串与输入输出
C语言中的字符串是一个比较让人头疼的问题。首先,C语言中没有独立的字符串数据类型,所以你需要使用「字符数组」来表示字符串。
这太反人类了!
字符数组
在C语言中,单引号''
包裹起来的将被视作字符,双引号""
包裹起来的将被视作字符串。
字符串需要存储在字符数组中。字符类型即char
,你可以通过如下方式定义单个字符和字符数组:
char i1 = 'Q';
char i2 = 'A';
char i3 = 'Q';
char qaq1[4] = {'Q', 'A', 'Q', '\0'};
char qaq2[4] = "QAQ";
字符数组的长度即字符串的长度。但是,C语言要求字符串的末尾(即最后一个有效字符)的后面需要跟一个\0
,表示字符串结束。因此我们看起来长度为3的QAQ
需要定义在长度为4的字符数组中。
在按照第5行的方式依次给出字符时,需要在最后一位给出\0
;按照第6行的方式使用双引号直接给出字符串,则无需手动给出\0
。字符数组的长度可以更长,对于QAQ
来说,数组的长度只需要大于3即可,是4或是400都是合法的。
一定要有\0
吗?
是的,C语言中字符串或字符数组必须要以\0
作为结尾。
C语言需要通过\0
来判断字符串的结束位置;否则,在程序运行的过程中可能会出现意外错误,并且在不同的环境中可能出现不同的意外错误。
输入输出
输出字符串
标准库函数printf
用于在控制台打印字符串。你不能像其他语言的print
或log
那样随便传各种类型的值,只能传递字符串。
但是你可以通过格式控制符将其他数据(包括其他字符串)嵌入到字符串中:
#include <stdio.h>
int main(void){
int a = 5;
char string[20] = "Are you OK?";
char c = 'A';
double pi = 3.14;
printf("数字是 %d 字符串是 %s 字符是 %c 圆周率是 %lf\n", a, string, c, pi);
return 0;
}
数字是 5 字符串是 Are you OK? 字符是 A 圆周率是 3.140000
以下是C语言中支持的格式控制说明符:
%d
- 有符号十进制整数%u
- 无符号十进制整数%s
- 字符串%c
- 字符%ld
- 浮点数(小数形式)%e
- 科学计数法(小写e
)%E
- 科学计数法(大写E
)%p
- 指针地址
然后,作为格式控制说明符,你还可以控制打印格式。
对于整数,%5d
指定了最小输出宽度,整数在打印时若宽度不够,则会在左边补空格以达到5宽度。如果需要在左边补0而不是空格,则可以使用%05d
。
对于浮点数,%.2lf
指定了保留两位小数,%6.2f
指定了宽度为6且保留两位小数。
对于字符串,同样可以使用%10.6s
来限制其宽度为10,截断输出前6个字符。
#include <stdio.h>
int main(void){
int a = 5;
char string[20] = "Are you OK?";
char c = 'A';
double pi = 3.14;
printf("数字是 %d 字符串是 %s 字符是 %c 圆周率是 %lf\n", a, string, c, pi);
printf("数字不仅是 %5d 还是 %05d\n", a, a);
printf("圆周率是 %.2lf 还是 %6.2lf\n", pi, pi);
printf("字符串是 %10.6s 还是 %.2s\n", string, string);
return 0;
}
数字是 5 字符串是 Are you OK? 字符是 A 圆周率是 3.140000
数字不仅是 5 还是 00005
圆周率是 3.14 还是 3.14
字符串是 Are yo 还是 Ar
另外,你可以使用%-5d
来让数字在宽度为5输出时靠左(空格在右)而不是%5d
一样靠右(空格在左),对于整形和字符串也是一致。
按照顺序,依次传入每个格式控制符对应的变量,程序在运行时会将变量嵌入字符串中并进行输出。
输入
你可以使用标准库函数scanf
从控制台接收用户传入的内容。scanf
的使用与printf
有一定区别需要注意。
#include <stdio.h>
int main(void){
int a;
double pi;
scanf("%d %lf", &a, &pi);
printf("a = %d, pi = %lf\n", a, pi);
}
6 3.14159
a = 6, pi = 3.141590
scanf
的首个参数是字符串,规定了接收控制台传入参数的格式,并且使用格式控制说明符。用户按照格式传入参数之后,scanf
从中提取出想要的参数,赋值到scanf
的第二个即往后的传入地址中。
scanf
接收的第二个即更多参数需要是指针类型,scanf
会把用户从控制台传入的变量分别赋值到地址中。
于是我们得到了如下规范:
- 不可以在
scanf
的首个字符串参数中填写说明。 因为不像Python中的input
可以传入输入说明,C中的scanf
的首个字符串参数是不会在控制台中显示,而仅用作传入参数的匹配提取的。- 这意味着如果你使用
scanf("请输入a的值:%d", &a)
,则用户需要在控制台完整输入请输入a的值:6
,显然程序没有按照期望运行。
- 这意味着如果你使用
- 必须在
scanf
中传入待赋值变量的指针。 且,在前一节数组中我们知道,数组会在被作为参数传入函数时退化成其头指针,因此接收字符数组(字符串)时无需特地求其地址。
#include <stdio.h>
int main(void){
int a;
double pi;
scanf("请输入两个变量的值:%d %lf", &a, &pi);
printf("a = %d, pi = %lf\n", a, pi);
}
请输入两个变量的值:6 3.14159
a = 6, pi = 3.141590
6 3.14159
a = 0, pi = 0.000000
从上面可以看出,在匹配提取参数失败时,scanf
不会出现错误。
下面是合理的传入字符串参数的实现:
#include <stdio.h>
int main(void){
char str[100];
printf("请输入一个字符串:");
scanf("%s", str);
printf("你输入的字符串是:%s\n", str);
}
mangofanfan@LAPTOP-MREQPRK3:~/CTest$ ./02_io
请输入一个字符串:你好?
你输入的字符串是:你好?
在上面,我们使用printf
提供了需要用户输入字符串时的提示文本。字符串你好?
由用户输入,在C语言中,汉字占用的字符长度根据编码决定,例如在目前广为常用的UTF-8编码下一个汉字占用3字符,则你好?
至少需要用长度为10的字符数组存储;而稍久远的GBK编码中则占用2字符,则你好?
至少需要用长度为7的字符数组存储。