关于C++,基础的概念便可不在叙述,这篇文章主要围绕于 C++中字符串相关内容 和 格式化输入\输出 ,那么,将离不开包含在头文件 stdio.h 中的 printf() 函数和 scanf() 函数。如果能够利用好这两个函数,那么不仅能与用户交互,还可根据个人喜好和任务要求格式化输出。
首先,我们先来了解字符串。
1.1 字符串
字符串(character string)是一或多个字符的序列,例如 "Welcome to Shaanxi!" ,它用双引号括起来,双引号的作用则是告知编译器它括起来的是字符串。关于字符串的储存,我将用一幅图来表示:
W | e | l | c | o | m | e | t | o | S | h | a | a | n | x | i | ! | \0 |
C语言中字符串都是被储存在char类型的数组中,如上图所示,字符串中的每一个字符被储存在相邻的储存单元中,包括空字符 '\0' ,它用来标记字符串的结束。接下来,我们将通过一个简单的例子(程序1.1)来使用字符串,我使用的编译器是MSVS2022。
#include<stdio.h>
#include<string.h>
int main(void)
{
char name[40];
printf("你的名字是:");
scanf("%s", name);
printf("你好,%s.今天的你又比昨天更加努力了噢!\n", name);
printf("你的名字占用%zd个字节", strlen(name));
return 0;
}
输入zhangsan,打印出来结果是:
这段代码中,输入的名字zhangsan以 %s 的形式打印出来,它在储存中占用9个字节,因为空字符'\0'的存在。
1.2 strlen()函数与sizeof运算符的区别
在程序1.1中,我们使用了包含在头文件string.h中的strlen()函数。由于sizeof以字节为单位给出对象的大小,而strlen()函数给出字符串中的字符长度(一个字符储存在一个字节中),那么,将这两种方法同时应用于字符串能否得到相同结果呢?答案显然是否定的。我将通过下面一个例子(程序1.2)来说明:
#include<stdio.h>
#include<string.h>
#define SENTENCE "Welcome to Shaanxi!"
int main(void)
{
char name[40];
printf("尊敬的旅客,请输入您的名字:");
scanf("%s", name);
printf("请稍等,正在查询信息中……\n");
Sleep(5000);//Sleep()函数,程序将延时5s打印下一项
printf("%s,欢迎来到陕西!(%s)\n", name, SENTENCE);
printf("\n\"用sizeof运算符得出名字占用 %zd 个字节,", sizeof(name));
printf("而strlen()函数得出名字占用 %zd 个字节。\"\n", strlen(name));
printf("\"用sizeof运算符得出SENTENCE占用 %zd 个字节,", sizeof(SENTENCE));
printf("而strlen()函数得出SENTENCE占用 %zd 个字节。\"\n", strlen(SENTENCE));
return 0;
}
代码中 Sleep() 函数用于延时打印下一项printf,其中5000单位为毫秒。运行代码,根据提示输入名字:Zhangsan,得到如下结果:
其中,sizeof运算符得出名字占用40个字节,其实是name数组中有40个储存单元,但是只有前8个存储Zhangsan,因此strlen()函数得出名字占用8个字节是正确的;下面关于SENTENCE所占字节数,由于sizeof也将空字符 '\0' 包括在内,所以比strlen(SENTENCE)多一个字节。通过这个例子,我们可以直观地看出 sizeof运算符 和 strlen()函数 的区别。
1.3 #define 指令
程序1.2中运用 #define 指令将字符串" Welcome to Shaanxi! "用 SENTENCE 代替。其中 SENTENCE 叫做符号常量。那么,常量与符号常量在应用上的区别主要体现在哪里呢?我们在敲代码时,离不开常量的应用,但是如果涉及那种会经常改变的常量,例如税率,使用常量表示税率,当税率发生变化时,则应该把程序中所有的税率常量都改变,但是如果对于这种经常变化的常量使用符号常量的话,使用符号常量,当发生变化时,我们只需要改变符号常量的定义即可。
那么,如何创建符号常量?其通用格式如下:
#define NAME value
其中NAME表示符号常量名,value表示符号常量的值,并且末尾不用加分号。
1.4 printf()函数 和 scanf()函数
1.4.1 printf()函数
我们在使用 printf() 函数时,打印的数据的指令要与待打印数据类型相匹配。例如,打印整数时使用%d,打印字符使用%c,打印字符串使用%s。这些符号被称为转换说明。接下来我将通过一个表格(表1.1)将部分转换说明陈列在其中:
转换说明 | 输出 |
---|---|
%% | 打印一个百分号 |
%c | 单个字符 |
%d | 有符号十进制整数 |
%e | 浮点数,e计数法 |
%E | 浮点数,e计数法 |
%f | 浮点数,十进制计数法 |
%i | 有符号十进制整数(与%d相同) |
%o | 无符号八进制整数 |
%p | 指针 |
%s | 字符串 |
%u | 无符号十进制整数 |
%x | 无符号十六进制整数 |
%X | 无符号十六进制整数 |
%a | 浮点数,十六进制数和p计数法 |
%A | 浮点数,十六进制数和p计数法 |
程序1.3使用了一些转换说明:
#include<stdio.h>
#define PI 3.1415926
int main(void)
{
int radius = 0;//定义变量半径,并初始化为零
double area;//定义变量圆面积
double circum;//定义变量圆周长
printf("请输入想要求的圆面积的半径:");
scanf("%d", &radius);
area = PI * radius * radius;
circum = 2.0 * PI * radius;
printf("半径为%d的圆面积为%4.5f.\n", radius, area);
printf("该圆周长为%4.5f.\n", circum);
return 0;
}
输入圆半径为 5 .得到输出结果如下:
其中面积(area)与周长(circum)为双精度型浮点数,用%f打印,其中 %4.5f 中的4表示打印项输出结果为4个字段宽度,由于待打印的数宽度超过了4,所以字段宽度自动扩大为带打印项字段宽度,其中 .5 表示精确到小数点后五位。
程序1.3中使用了%4.5f转换说明,其也可以理解为转换说明修饰符,接下来,我将用表格(表1.2)列出一些printf()的修饰符。
修饰符 | 含义 |
---|---|
标记 | 表1.3描述了5中常见的标记 |
数字 | 最小字段宽度 |
. 数字 | 精度 |
h | 和整型转换说明一起使用,表示 short int 或 unsigned short int 类型的值。如 "%hu","%hx" |
hh | 和整型转换说明一起使用,表示 signed char 或 unsigned char 类型的值。如 "%hhu","%hhx" |
l | 和整型转换说明一起使用,表示 long int 或 unsigned long int 类型的值。如 "%lu","%ld" |
ll | 和整型转换说明一起使用,表示 long long int 或 unsigned long long int 类型的值。如 "%llu","%lld" |
L | 和浮点转换说明一起使用,表示 long double 类型的值。如 "%Lf" |
z | 和整型转换说明一起使用,表示 size_t 类型的值,该类型是 sizeof 返回的类型 |
下面的 表1.3 列出printf()函数中常用的标记
标记 | 含义 |
---|---|
- | 从字段的左侧开始打印该项 |
+ | 有符号值若为正,则在值前面显示加号,若为负,在值前面显示减号 |
空格 | 有符号值若为正,则在值前面显示前导空格(不显示任何符号),若为负,在值前面显示减号标记并覆盖空格 |
# | 把结果转换为另一种形式 |
0 | 对于数值格式,用前导0代替空格填充字段宽度。 对于整数格式,如果出现-标记或指定精度,则忽略 |
接下来,我们通过程序1.4来了解修饰符和标记
#include<stdio.h>
#define PAGES 959
int main(void)
{
printf("*%d*\n", PAGES);
printf("*%2d*\n", PAGES);
printf("*%10d*\n", PAGES);
printf("*%-10d*\n", PAGES);
return 0;
}
该程序中使用*标记字段的开始与结束,让我们更加直观的看出标记和修饰符的作用。打印结果如下:
该程序中,"%2d"由于959字段宽度为三,它将自动扩充;"%-10d"打印字段宽度为10并且从左端开始打印。
程序1.5展示出字符串格式的示例
#include<stdio.h>
#define BLURB "Welcome to Shaanxi!"
int main(void)
{
printf("[%2s]\n", BLURB);
printf("[%24s]\n", BLURB);
printf("[%20s]\n", BLURB);
printf("[%24.2s]\n", BLURB);
printf("[%24.3s]\n", BLURB);
printf("[%24.4s]\n", BLURB);
printf("[%24.5s]\n", BLURB);
printf("[%-24.5s]\n", BLURB);
return 0;
}
该程序与程序1.4有同样的表达,展示了修饰符和标记的示例。
1.4.2 转换说明的意义
转换说明把以二进制格式储存在计算机中的值转换为一系列字符(字符串)以便于显示,它很容易被我们误解为原始值被替换成转换后的值。实际上,转换说明是翻译说明。例如,%d的意思是“把给定的值翻译成十进制文本并打印出来”。
1.4.3 scanf() 函数
C库中包含多个输入函数,scanf() 函数是最通用的一个,因为它可以读取不同格式的数据。它与 printf() 函数类似,也使用格式字符串和参数列表,scanf() 函数中的格式字符串字符输入流的目标数据类型。scanf() 和 printf()的区别主要在于参数列表中,printf() 函数使用变量,常量和表达式,而 scanf() 函数使用指针变量的指针。这里有两条简单的规则:
·1. 如果用scanf()读取基本变量类型的值,在变量名前加一个 &
·2. 如果用scanf()把字符串读入字符数组中,不要使用 &
程序1.6展示了这两条规则:
#include<stdio.h>
int main(void)
{
int age; //变量
char pet[20]; //字符数组,用于储存字符串
printf("请输入你的年龄:");
scanf("%d", &age);//基本变量使用&
printf("你好呀,%d岁的小朋友,你最喜欢的宠物是什么?\n",age);
scanf("%s", pet);//字符数组不使用&
printf("有这么可爱的你,那么%s一定也非常可爱吧!", pet);
return 0;
}
其输入年龄:8,最喜欢的宠物:小狗。打印结果如下:
scanf()函数所用的转换说明与printf()函数基本相同,我将用一个表格(表1.4)列出常见的转换说明
转换说明 | 含义 |
---|---|
%c | 把输入解释成字符 |
%d | 把输入解释成有符号的十进制整数 |
%e,%f,%g,%a | 把输入解释成浮点数 |
%E,%F,%G,%A | 把输入解释成浮点数 |
%i | 把输入解释成有符号的十进制整数 |
%o | 把输入解释成有符号的八进制整数 |
%p | 把输入解释成指针(地址) |
%s | 把输入解释成字符串,第一个空白开始,下一个空白结束 |
%u | 把输入解释成无符号十进制整数 |
%x,%X | 把输入解释成有符号的十六进制整数 |
下面这个表格(表1.5)我将列出scanf()函数转换说明中的修饰符
修饰符 | 含义 |
---|---|
* | 抑制赋值 |
数字 | 最大字段宽度 |
hh | 把整数作为 signed char 或 unsigned char 类型读取,如:"%hhd" |
ll | 把整数作为 long long或 unsigned long long 类型读取,如:"%lld" |
j | 在类型转换说明后面时,表明使用 intmax_t 或 uintmax_t 类型,如:"%jd" |
z | 在类型转换说明后面时,表明使用sizeof的返回值类型,如:"%zd" |
t | 在类型转换说明后面时,表明使用两个指针差值的类型,如:"%td" |
实际上,scanf() 函数并不是最常用的输入函数,它只是能读取不同类型的数据。C语言中还有其他的输入函数,如 getchar() 和 fgets() 。
如果本篇文章有任何错误希望兄弟们指正,谢谢啦!