第三章 字符串和格式化输入和输出
3.1前导程序
//2022年3月29日20:03:30
//一个能为您提供一些信息的对话程序
#include <stdio.h>
#include <string.h> //提供strlen()函数的原型
#define DENSITY 62.4 //人体的密度
int main( )
{
float weight,volume;
int size,letters;
char name[40]; //name是一个有40个字符的数组
printf("Hi! What's your first name?\n");
scanf("%s",name);
printf("%s,what's your weight in pounds?\n",name);
scanf("%f",&weight);
size = sizeof name;
letters = strlen(name);
volume = weight/DENSITY;
printf("Well,%s,your volume is %2.2f cubic feet.\n",name,volume);
printf("Also, your first name has %d letters,\n",letters);
printf("and we have %d bytes to store it in.\n",size);
return 0;
}
结果
Hi! What's your first name?
CodeMagicianT
CodeMagicianT,what's your weight in pounds?
150
Well,CodeMagicianT,your volume is 2.40 cubic feet.
Also, your first name has 13 letters,
and we have 40 bytes to store it in.
C:\Users\51670\source\repos\Project1\x64\Debug\Project1.exe (进程 19508)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
- 它使用一个数组来存放一个字符串。这里,某人的名字被读进这个数组中。该数组是内存中一串连续的40个字节,其中每个字节都可以存放一个字符值。
- 它使用%s转换说明符来处理字符串的输入和输出。请注意,在scanf()中,weight使用了&前缀,而 name没有(name和&weight都是地址)。
- 它使用C预处理器定义了代表值62.4的符号常量DENSITY。
- 它使用C函数stlen()来获取字符串的长度。
3.2字符串简介
1.char数组类型和空字符
C没有为字符串定义专门的变量类型,而是把它存储在char数组中。字符串中的字符存放在相邻的存储单元中,每个字符占用一个单元;而数组由相邻存储单元组成,所以把字符串存储到数组中是很自然的。
请注意数组最后一个位置显示字符、0这个字符就是空字符,C用它来标记字符串的结束。空字符不是数字0;它是非打印字符,其ASCALL码的值为0。C的字符串存储时通常以这个空字符结束。
数组是同一类型的数据元素的有序序列。
2.使用字符串
//2022年3月29日21:22:15
#include <stdio.h>
#define PRAISE "What a super marvelous name!"
int main(void)
{
char name[40];
printf("What's your name?\n");
scanf("%s",name);
printf("Hello,%s. %s\n",name,PRAISE);
return 0;
}
结果
What's your name?
Code Magician
Hello,Code. What a super marvelous name!
C:\Users\51670\Desktop\C Program\praise1.c\Debug\Project1.exe (进程 12188)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
您无须亲自把空字符插入name数组中。scanf()在读取输入时会替您完成这项任务。编译器负责插入空字符。scanf()遇到第一个空白字符空格(blank)、制表符(tab)或者换行符(newline)处停止读取。一般情况下,使用%s的scanf()只会把一个单词而不是整个语句作为字符串读入。C使用其他读取输入函数(例如gets())来处理一般的字符串。
3.strlen()函数
sizeof运算符以字节为单位给出数据的大小。strlen()函数以字符为单位给出字符串的长度。
//2022年3月29日21:52:50
#include <stdio.h>
#include <string.h> //提供strlen()函数的原型
#define PRAISE "What a super marvelous name!"
int main(void)
{
char name[40];
scanf("%s",name);
printf("Hello,%s.%s\n",name,PRAISE);
printf("Your name of %d letters occupies %d memory cells.\n ",strlen(name),sizeof name);
printf("The phrase of praise has %d letters",strlen(PRAISE));
printf("and occupies %d memory cells.\n",sizeof PRAISE);
return 0;
}
结果
Morgan Buttercup
Hello,Morgan.What a super marvelous name!
Your name of 6 letters occupies 40 memory cells.
The phrase of praise has 28 lettersand occupies 29 memory cells.
C:\Users\51670\Desktop\C Program\Project1\Debug\Project1.exe (进程 11836)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
string.h文件包含许多与字符串相关的函数的原型,包括strlen()。C把C函数库分成多个相关函数的系列,并为每个 系列提供一个头文件。对于PRAISE,您会发现strlen()再一次给出了字符串中字符(包括空格和标点符号)的准确数目。Sizeof运算符提供给您的数目比前者大1,这是因为它把用来标志字符串结束的不可见的空字符也计算在内。前一章
sizeof中使用了圆括号,本例没有。是否使用圆括号取决于您是想获取一个类型的大小还是想获取某个具体量的大小。圆括号对于类型是必需的而对于具体量是可选的。不过,在所有情况下都是用圆括号会更好,例如sizeof(6.28)。
3.3常量和C预处理器
为什么使用符号常量比较好呢?首先,一个名字比一个数字告诉您更多信息。如果您多个地方使用了同一个常量,并且必须改变它的值。那么您只需要改变这个符号常量的定义,而不用在程序中查找出现这个常量的每个地方并做修改。
例如
#define NAME value
没有使用分号是因为这是一种替代机制,而不是C的语句。符号常量所用的名字必须满足变量命名规则。可以是字母、数字、下划线的组合。第一个字符不能是数字。也可以定义字符和字符串常量。
1.const修饰符
可以使用const关键字把一个变量声明转换成常量声明:
const int MONTHS = 12;//MONTHS是一个代表12符号常量
2.系统定义的明显常量
C头文件limits.h和float.h分别提供有关整数类型和浮点类型的大小限制的详细信息。每个文件都定义了一系列应用于您的实现的明显常量。
3.4.研究和利用printf()和scanf()
1.printf()函数
请求printf()打印变量的指令取决于变量的类型。
2.使用printf()
请注意在第二个语句中,打印表列的第一项是一个字符常量而非变量,而第二项则是一个乘法表达式。这就说明了printf()使用的是值,无论该值是变量、常量还是表达式。
3.转换说明的意义
Ⅰ.在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。
Ⅱ.printf( )的返回值
C函数一般都有一个返回值。这就是由函数计算并返回给调用程序的值。printf( )会返回所打印字符的个数。如果有输出错误,那么printf( )会返回一个负数。
Ⅲ.打印较长的字符串
C将抱怨您在字符串常量中使用了一个非法字符。您可以在字符串中使用\n符号来表示换行字符,但是在字符串中不能通过回车键产生实际的换行字符。
您必须分割一个字符串,有三个选项可提供选择。
#define _CRT_SECURE_NO_WARNINGS 1
//2022年4月19日10:53:07
//longstrg.c -- 打印较长的字符串
#include <stdio.h>
int main(void)
{
printf("Here's one way to print a ");
printf("long string.\n");
printf("Here's another way to print a \
long string.\n");
printf("Here's the newest way to print a "
"long string.\n");//ANSI C
return 0;
}
结果
Here's one way to print a long string.
Here's another way to print a long string.
Here's the newest way to print a long string.
C:\Users\51670\Desktop\C Program\longstrg\Debug\longstrg.exe (进程 5424)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
方法1是使用多个printf( )语句。因为打印的第一个字符串没有以\n字符结束,所以第二个字符串紧跟第一个字符串输出。
方法2是用反斜线符号(/)和回车键的组合来结束第一行。这使得屏幕上的文本另起一行,并且字符串中不会包含换行字符。其效果就是在下一行继续该字符串。不过,下一行必须像代码中那样从行的最左边开始。如果缩进了该行,比如说缩进了5个空格,那么这5个空格会变成字符串的一部分。
方法3采用字符串连接的方法,它是ANSI C的新方法。如果在一个用双引号引起来的字符串后面跟有另一个用双引号引起来的字符串,而且二者之间仅用空白字符分割,那么C会把该组合当做一个字符串来处理,所以以下三种形式是等同的:
printf("Hello,young lovers,where you are.");
printf("Hello,young" "lovers" ",where you are.");
printf("Hello,young lovers"
",where you are.");
printf("Here's another way to print a
long string.\n");//这个语句是错误的
所有这些方法中,您应该在字符串内部包含所有必需的空格:"young" "lovers" 变成"young lovers",但是"young""lovers"变成"younglovers"
4.使用scanf( )
scanf( )函数开始每次读取一个输入字符,它跳过空白字符(空格、制表符和换行符)直到遇到一个非空白字符。因为它试图读取一个整数,所以scanf( )期望发现一个数字字符或者一个符号(+或-)。如果它发现了一个数字或一个符号,那么它就保存之并读取下一个字符;如果接下来的字符是一个数字,它保存这个数字,并读取下一个字符。就这样,scanf( )持续读取和保存字符直到它遇到一个非数字的字符。如果遇到了一个非数字的字符它就得出结论:已读到了整数的尾部。scanf( )把这个非数字字符放回输入。这就意味着当程序下一次开始时读取输入时,它将从前面被放弃的那个非数字字符开始。如果使用了字段宽度,那么scanf( )在字段结尾或者在第一个空白字符处(二者最先达到的一个)终止。