《C Primer Plus》学习笔记—第4章

《C Primer Plus》学习笔记

第4章 字符串和格式化输入/输出

1.前导程序talkback.c

//talkback.c  演示与用户交互 
#include<stdio.h>
#include<string.h>  //提供strlen()函数的原型 
#define DENSITY 62.4 //预处理器指令创建符号常量,人体密度(单位:磅/英尺) 
int main(void)
{
   
	float weight,volume;
	int size,letters;
	char 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 in.\n",size);
	
	return 0;
}

输入maoyuankang(enter键),再输入154(enter键),输出如下:

Hi,What's your first name?
maoyuankang
maoyuankang,what's your weight in pounds?
154
Well,maoyuankang,your volume is 2.47 cubic feet.
Also,your first name has 11 letters,
and we have 40 bytes to store in.

用数组(array)储存字符串(character string)。在该程序中,用户输入的名被储存在数组中,该数组占用内存中40个连续的字节,每个字节储存一个字符值。
使用%s转换说明来处理字符串的输入和输出。注意,在scanf()中,name没有&前缀,而weight有(稍后解释,&weight和name都是地址)。
用C预处理器把字符常量DENSITY定义为62.4。用C函数strlen()获取字符串的长度。

2.字符串简介

字符串(character string)是一个或多个字符的序列,双引号不是字符串的一部分。双引号仅告知编译器它括起来的是字符串,正如单引号用于标识单个字符一样。

1.char类型数组和null字符

C语言没有专门用于储存字符串的变量类型,字符串都被储存在char类型的数组中。数组由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元中,每个单元储存一个字符(见图4.1)。

数组中的字符串

注意图4.1中数组末尾位置的字符\0。这是空字符(mull character), C语言用它标记字符串的结束。空字符不是数字0,它是非打印字符,其ASCII码值是(或等价于)0。C中的字符串一定以空字符结束,这意味着数组的容量必须至少比待存储字符串中的字符数多1。因此,程序talkback.c中有40个存储单元的字符串,只能储存39个字符,剩下一个字节留给空字符

可以把数组看作是一行连续的多个存储单元。用更正式的说法是,数组是同类型数据元素的有序序列。程序清单talkback.c通过以下声明创建了一个包含40个存储单元(或元素)的数组,每个单元储存一个char类型的值:char name[40];name后面的方括号表明这是一个数组,方括号中的40表明该数组中的元素数量。char表明每个元素的类型。

2.使用字符串:程序praise1.c
#include<stdio.h>
#define PRAISE "You are an extraordinary being."
int main(void)
{
   
	char name[40];
	
	printf("What's your name?\n");
	scanf("%s",name);
	
	printf("Hello,%s. %s\n",name,PRAISE); 
	
	return 0;
}

输入Angela Plains,输出如下:

What's your name?
Angela Plains
Hello,Angela. You are an extraordinary being.

%s告诉printf()打印一个字符串。不用亲自把空字符放入字符串末尾,scanf()在读取输入时就已完成这项工作。也不用在字符串常量PRAISE末尾添加空字符。先理解PRAISE后面用双引号括起来的文本是一个字符串。编译器会在末尾加上空字符

注意,scanf()只读取了Angela Plains中的Angela,它在遇到第1个空白(空格、制表符或换行符)时就不再读取输入。因此,scanf()在读到Angela和Plains之间的空格时就停止了。一般而言,根据%s转换说明,scanf()只会读取字符串中的一个单词,而不是一整句。C语言还有其他的输入函数(如,fgets()),用于读取一般字符串。

字符串常量"x"和字符常量’x’不同。区别之一在于’x’是基本类型(char),而"x"是派生类型(char数组);区别之二是"x"实际上由两个字符组成: 'x’和空字符\0(见图4.3)。

字符和字符串的区别(空字符)

字符和字符串

3.strlen()函数:程序praise2.c
strlen()和sizeof
#include<stdio.h>
#include<string.h>   //提供strlen()函数的原型,可以不用 
#define PRAISE "You are an extraordinary being."
int main(void)
{
   
	char name[40];
	
	printf("What's your name?");
	scanf("%s",name);
	
	printf("Hello,%s. %s\n",name,PRAISE); 
	printf("Your name of %zd letters occupies %zd memory cells.\n",
			strlen(name),sizeof name);
	printf("The phrase of praise has %zd letters ",strlen(PRAISE));
	printf("and occupies %zd memory cells.\n",sizeof(PRAISE));
	
	return 0;
}

输入Serendipity Chance,输出如下:

What's your name?Serendipity Chance
Hello,Serendipity. You are an extraordinary being.
Your name of 11 letters occupies 40 memory cells.
The phrase of praise has 31 letters and occupies 32 memory cells.

如果使用ANSI C之前的编译器,必须移除这一行:#include<string.h>。string.h头文件包含多个与字符串相关的函数原型,包括strlen()。
一般而言,C把函数库中相关的函数归为一类,并为每类函数提供一个头文件。例如,printf()和scanf()都隶属标准输入和输出函数,使用stdio.h头文件。string.h头文件中包含了strlen()函数和其他一些与字符串相关的函数(如拷贝字符串的函数和字符串查找函数)。

注意,程序使用了两种方法处理很长的printf()语句。第1种方法是将printf()语句分为两行(可以在参数之间断为两行,但是不要在双引号中的字符串中间断开);第2种方法是使用两个printf()语句打印一行内容,只在第2条printf()语句中使用换行符(\n)。

sizeof运算符报告,name数组有40个存储单元。但是,只有前11个单元用来储存Serendipity,所以strlen()得出的结果是11. name数组的第12个单元储存空字符, strlen()并未将其计入。图4.4演示了这个概念。

strlen()计算长度

对于PRAISE,用strlen()得出的也是字符串中的字符数(包括空格和标点符号)。然而,sizeof运算符给出的数更大,因为它把字符串末尾不可见的空字符也计算在内。该程序并未明确告诉计算机要给字符串预留多少空间,所以它必须计算双引号内的字符数。
C99和C11标准专门为sizeof运算符的返回类型添加了**%zd转换说明,这对于strlen()同样适用。
对于类型,应写成sizeof(char)或sizeof(float);对于特定量,可写成sizeof name或sizeof 6.28。建议所有情况下都使用
圆括号**,如sizeof(6.28)。

3.常量和预处理器

符号常量的命名规则与变量相同。可以使用大小写字母、数字和下划线字符,首字符不能为数字。为什么使用符号常量更好?首先,常量名比数字表达的信息更多。另外,假设程序中的多处使用一个常量,有时需要改变它的值。如果程序使用符号常量,则只需更改符号常量的定义,不用在程序中查找使用常量的地方,然后逐一修改。

那么,如何创建符号常量?方法之一是声明一个变量,然后将该变量设置为所需的常量。可以这样写:
float taxrate;
taxrate = 0.015;
预处理器也可用来定义常量。只需在程序顶部添加下面一行:
#define TAXRATE 0.015
编译程序时,程序中所有的TAXRATE都会被替换成0.015。这一过程被称为编译时替换(compile-timesubstitution)。在运行程序时,程序中所有的替换均已完成)。通常,这样定义的常量也称为明示常量(manifest constant)。
请注意格式,首先是#define,接着是符号常量名(TAXRATE),然后是符号常量的值(0.015)注意,其中并没有=符号)。所以,其通用格式如下:
#define NAME value
实际应用时,用选定的符号常量名和合适的值来替换NAME和value。注意,末尾不用加分号,因为这是一种由预处理器处理的替换机制。用大写表示符号常量是C语言一贯的传统。这样,在程序中看到全大写的名称就立刻明白这是一个符号常量,而非变量。大写常量只是为了提高程序的可读性。另外,还有一个不常用的命名约定,即在名称前带c或k_前缀来表示常量(如,c _level或k_line)。

1.程序pizza.c
#include<stdio.h>
#define PI 3.14159
int main(void)
{
   
	float area,circum,radius;
	
	printf("What is the radius of your pizza?\n");
	scanf("%f",&radius);
	
	area=PI*radius*radius;
	circum=2.0*PI*radius;
	printf("Your basic pizza parameters are as follows:\n");
	printf("circumference=%1.2f,area=%1.2f\n",circum,area);
	
	return 0;
	//const限定符,限定一个变量为只读const float PI=3.14159; 
}

输入6.0,输出如下:

What is the radius of your pizza?
6.0
Your basic pizza parameters are as follows:
circumference=37.70,area=113.10

printf()语句中的1.2f表明,结果被四舍五入为两位小数输出。

#define指令还可定义字符和字符串常量。前者使用单引号,后者使用双引号。如下所示:
#define BEEP ‘\a’
#define OOPS “Now you have done it!”
记住,符号常量名后面的内容被用来替换符号常量。

2.const限定符

C90标准新增了const关键字,用于限定一个变量为只读。其声明如下:
const int MONTHS=12;//MONTHS在程序中不可更改,值为12
这使得MONTHS成为一个只读值。也就是说,可以在计算中使用MONTHS,可以打印MONTHS,但是不能更改MONTHS的值。const用起来比#define更灵活。

3.明示常量:程序defines.c

C头文件limits.h和float.h分别提供了与整数类型和浮点类型大小限制相关的详细信息。每个头文件都定义了一系列供实现使用的明示常量。例如,limits.h头文件包含以下类似的代码:
#define INT_MAX +32767
#define INT_MIN -32768
这些明示常量代表int类型可表示的最大值和最小值。如果系统使用32位的int,该头文件会为这些明示常量提供不同的值。

//limits.h和float.hz中的一些明示常量 
#include<stdio.h>
#include<limits.h>
#include<float.h>
int main(void)
{
   
	printf("Some number limits for this system:\n")
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值