【《C Primer Plus》读书笔记】第4章:字符串和格式化输入/输出
4.1 字符串
字符串是一个或多个字符的序列,储存在char类型的数组中。
4.1.1 ‘\0’
‘\0’就是8位的00000000,因为字符类型中并没有对应的这个字符,所以这么写。’\0’就是 字符串结束标志。
空字符(Null character)又称结束符,缩写 NUL,是一个数值为 0 的控制字符,\0 是转义字符,意思是告诉编译器,这不是字符 0,而是空字符。
C语言用’\0’标记字符串的结束,'\0’占据一个存储单元。
4.1.2 字符串与字符的区别
字符’a’占一个存储空间。
字符串"a"占两个存储空间,因为末尾自带’\0’。
4.2 strlen()
size_t strlen(const char *str)
C 标准库 - <string.h> 中,计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
参数:str – 要计算长度的字符串。
返回值:该函数返回字符串的长度。
下面的实例演示了 strlen() 函数的用法。
#include <stdio.h>
#include <string.h>
int main ()
{
char str[50];
int len;
strcpy(str, "This is runoob.com");
len = strlen(str);
printf("|%s| 的长度是 |%d|\n", str, len);
return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:
|This is runoob.com| 的长度是 |18|
菜鸟教程:C 标准库 - <string.h>
4.3 sizeof
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。
sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。
使用 sizeof 的语法如下:
sizeof (data type)
其中,data type 是要计算大小的数据类型,包括类、结构、共用体和其他用户自定义数据类型。
size_t 是 sizeof 返回的类型(C99),打印用 %zd。
请尝试下面的实例,理解 C++ 中 sizeof 的用法。复制并黏贴下面的 C++ 程序到 test.cpp 文件中,编译并运行程序。
#include <iostream>
using namespace std;
int main()
{
cout << "Size of char : " << sizeof(char) << endl;
cout << "Size of int : " << sizeof(int) << endl;
cout << "Size of short int : " << sizeof(short int) << endl;
cout << "Size of long int : " << sizeof(long int) << endl;
cout << "Size of float : " << sizeof(float) << endl;
cout << "Size of double : " << sizeof(double) << endl;
cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果,结果会根据使用的机器而不同:
Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4
4.4 #define
#define 是预处理器的一种。
#define 预处理指令用于创建符号常量。该符号常量通常称为宏,指令的一般形式是:
#define macro-name replacement-text
例如:
#define MAX_ARRAY_LENGTH 20
编译程序时,这个指令告诉 CPP 把所有的 MAX_ARRAY_LENGTH 替换为 20,称为编译时替换,这样定义的常量称为明示常量。使用 #define 定义常量来增强可读性。
菜鸟教程:C 预处理器
4.5 const
C90 标准新增了 const 关键字,用于限定一个变量为只读。
例如:
const int MONTHS = 12;// MONTHS 在程序中不可修改,值为12
const 用起来比 #define 更灵活。
4.6 明示常量
C头文件 limits.h 头文件决定了各种变量类型的各种属性。定义在该头文件中的宏限制了整数类型(比如 char、int 和 long)的值。
这些限制指定了变量不能存储任何超出这些限制的值,例如一个无符号可以存储的最大值是 255。
宏 | 值 | 描述 |
---|---|---|
CHAR_BIT | 8 | 定义一个字节的比特数。 |
SCHAR_MIN | -128 | 定义一个有符号字符的最小值。 |
SCHAR_MAX | 127 | 定义一个有符号字符的最大值。 |
UCHAR_MAX | 255 | 定义一个无符号字符的最大值。 |
CHAR_MIN | 0 | 定义类型 char 的最小值,如果 char 表示负值,则它的值等于 SCHAR_MIN,否则等于 0。 |
CHAR_MAX | 127 | 定义类型 char 的最大值,如果 char 表示负值,则它的值等于 SCHAR_MAX,否则等于 UCHAR_MAX。 |
MB_LEN_MAX | 1 | 定义多字节字符中的最大字节数。 |
SHRT_MIN | -32768 | 定义一个短整型的最小值。 |
SHRT_MAX | +32767 | 定义一个短整型的最大值。 |
USHRT_MAX | 65535 | 定义一个无符号短整型的最大值。 |
INT_MIN | -2147483648 | 定义一个整型的最小值。 |
INT_MAX | 2147483647 | 定义一个整型的最大值。 |
UINT_MAX | 4294967296 | 定义一个无符号整型的最大值。 |
LONG_MIN | -9223372036854775808 | 定义一个长整型的最小值。 |
LONG_MAX | 9223372036854775807 | 定义一个长整型的最大值。 |
ULONG_MAX | 1.8446744e+19 | 定义一个无符号长整型的最大值。 |
菜鸟教程:C 标准库 - <limits.h>
C 标准库的 float.h 头文件包含了一组与浮点值相关的依赖于平台的常量。
下面的值是特定实现的,且是通过 #define 指令来定义的,这些值都不得低于下边所给出的值。
宏 | 描述 |
---|---|
FLT_MANT_DIG | float类型的尾数位数 |
FLT_DIG | float类型的最少有效数字位数(十进制) |
FLT_MIN_10_EXP | 基数为 10 时的指数的float类型的最小负整数值 |
FLT_MAX_EXP | 基数为 10 时的指数的float类型的最大正整数值 |
FLT_MAX | 最大的float类型浮点值 |
FLT_MIN | 保留全部精度的float类型最小正数 |
FLT_EPSILON | float类型可表示的最小有效数字 |
示例:
#include <stdio.h>
#include <float.h>
int main()
{
printf("The maximum value of float = %.10e\n", FLT_MAX);
printf("The minimum value of float = %.10e\n", FLT_MIN);
printf("The number of digits in the number = %.10e\n", FLT_MANT_DIG);
}
让我们编译和运行上面的程序,这将产生下列结果:
The maximum value of float = 3.4028234664e+38
The minimum value of float = 1.1754943508e-38
The number of digits in the number = 7.2996655210e-312
菜鸟教程:C 标准库 - <float.h>
4.7 printf()
C 库函数 int printf(const char *format, …) 发送格式化输出到标准输出 stdout。
printf()函数的调用格式为:
printf("<格式化字符串>", <参量表>);
菜鸟教程:C 库函数 - printf()
4.7.1 printf()中的标记
标记 | 含义 |
---|---|
– | 待打印项左对齐 |
+ | 有符号值若为正,则在值的前面显示加号;若为负,则在值前面显示减号 |
空格 | 有符号值若为正,则在值的前面显示前导空格(不显示任何符号);若为负,则在值前面显示减号 |
# | 把结果转换为另一种格式,#保证对任何浮点数打印一个小数点字符 |
0 | 对于数值格式,用前导0代替空格填充字段宽度 |
4.7.2 printf()中的参数传递
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main(void)
{
float n1 = 3.0;
double n2 = 3.0;
long n3 = 2000000000;
long n4 = 1234567890;
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
system("pause");
return 0;
}
假设我们在32位系统中执行上述程序,程序把传入的值放入栈中。
32位系统中,float占4字节,double占8字节,long占4字节。
参数传递的过程中,float自动转换成double,所以n1占8字节,n2占8字节,n3和n4各占4字节。而在32位系统中,long占4字节, 所以%ld表明printf()一次读取4字节。因此,四次读取的分别是:n1的前半部分,n1的后半部分,n2的前半部分,n2的后半部分。虽然n3和n4用对了转换说明,但是printf()没有读取到n3和n4。
4.7.3 printf()的返回值
一般而言,prinf()返回打印字符的个数。
如果有输出错误,printf()则返回一个负值。
4.8 scanf()
C 库函数 int scanf(const char *format, …) 从标准输入 stdin 读取格式化输入。
下面是 scanf() 函数的声明。
int scanf(const char *format, ...)
菜鸟教程:C 库函数 - scanf()
除了%c,其他转换说明都会自动跳过待输入值前面的所有空白。
scanf()的实质是字符串匹配。
4.8.1 转换说明
假设有如下输入行: -13.45e12# 0。(注意-前有个空格)
- 如果转换说明是%d,则读取-13,.作为下一次输入的首字符
- 如果转换说明是%f,则读取-13.45e12,并存储在float类型的目标变量中
- 如果转换说明是%s,则读取-13.45e12#,并存储在目标字符数组中,末尾加上’\0’
- 如果转换说明是%c,则读取空格
4.8.2 scanf()的返回值
scanf()返回成功读取的项数。
如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,scanf()便返回0。
当 scanf() 检测到“文件结尾”时,会返回EOF(一般用#define指令设为-1)。
4.9 printf()和scanf()的*修饰符
printf()和scanf()都可以使用*修饰符来修改转换说明的含义。
在printf()中,可以用*修饰符代替字段宽度,这需要用一个参数告诉函数字段宽度应该是多少。
示例:
/*varwid.c -- 使用变宽输出字段*/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main(void)
{
unsigned width, precision;
int number = 256;
double weight = 242.5;
printf("Enter a field width:\n");
cin >> width;
printf("The number is :%*d:\n", width, number);
printf("Now enter a width and a precision:\n");
cin >> width >> precision;
printf("Weight = %*.*f\n", width, precision, weight);
system("pause");
return 0;
}
测试:
在scanf()中,把*放在%和d之间,会使得scanf()跳过相应的输出项。
示例:
/*skiptwo.c -- 跳过输入中的前两个整数*/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main(void)
{
int n;
cout<<"Please enter three integers:"<<endl;
scanf("%*d %*d %d",&n);
cout<<"The last integer was "<<n<<endl;
system("pause");
return 0;
}
测试: