1. 字符串
字符串是一个或多个字符的序列。双引号不是字符串的一部分,它的作用仅是告诉编译器它括起来的内容是字符串。
1.1 char类型数组和null字符
字符串末尾的\0是空字符,C语言用它标记字符串的结束,其ASCII码值是0。C语言中字符串一定以空字符结尾,因此char数组一定要比带存储字符串的字符数多1。
数组是同类型数据元素的有序序列。
1.2 使用字符串
sizeof以字节为单位给出对象的大小,strlen给出字符串中的字符长度。虽然1字节存储1字符,但是并不能将两者混用。
假设char[40] name存储字符串“Caldm”,sizeof返回的值是40,而strlen返回的值是5。即使直接传递字符串字面量,sizeof的结果也会比strlen的值大,因为sizeof把字符串末尾不可见的空字符\0也计算在内了。
2. 常量和C预处理器
为什么符号常量更好?
- 常量名比数字表达的信息更多
- 当程序中多处使用常量,且需要更改常量时,使用符号常量只需要修改符号常量的定义,不用再程序中逐一修改
如何创建符号常量?
方法一:声明一个变量,然后将变量修改为所需的常量。
这样做依然可能在程序运行过程中修改它的值,更好的做法是使用C预处理器
方法二:使用C预处理器 #define 常量名 常量值
命名规则:
- 常量名应当采用全大写字母+下划线连接
- 也可在名称前带
c_或k_前缀来表示常量(比较少见)
2.1 const限定符
const关键字(C90新增)用于限定一个变量为只读(在C语言中,使用const类型限定符声明的是变量,不是常量)。
2.2 符号常量
C头文件limits.h和float.h分别提供了整数类型和浮点数类型大小限制相关的详细信息。每个头文件都提供了一系列供实现使用的符号常量。
3. printf()和scanf()
printf()和scanf()是输入/输出函数,简称I/O函数。C最开始吧输入/输出留给编译器的实现者,但C90和C99标准规定了这些函数的标准版本。
3.1 printf()函数
printf()函数打印数据的指令要与待打印数据的类型相匹配,例如%d打印整数,%f打印单精度浮点数(float),这些符号被称为转换说明(conversion specification),它们指定了如何把数据转换成可显示的形式。
printf()的标记
| 标记 | 意义 |
|---|---|
- | 待打印项左对齐 |
+ | 显示符号,正数显示+,负数显示- |
| 空格 | 前导填充空格 |
# | 把结果转换为另一种格式。如果是%o格式,则以0开始,%x或%X格式,则以0x或0X开始;对于所有浮点格式,#保证即使没有小数部分,也将打印一个小数点字符;对于%g或%G,防止结果后面的0倍删除 |
0 | 对于数值格式,用前导0填充字段宽度;对于整数格式,如果出现-标记或指定精度,则虎落该标记 |
printf()的修饰符
| 修饰符 | 意义 |
|---|---|
| 标记 | 可以不使用标记或使用多个标记 |
| 数字 | 最小字段宽度。 如果字段小于指定宽度,则会进行填充,填充内容受标记影响,默认为空格; 如果字段大于指定宽度,则使用能完整显示的最小宽度 |
.数字 | 精度。 对于 %e、%E和%f,表示小数点右边数字的位数对于 %g和%G转换,表示有效数字的最大位数对于 %s转换,表示待打印字符的最大数量对于整型转换,表示待打印数字的最小位数 如有必要,使用前导0来达到这个位数 .和.0相同 |
h | 和整型转换说明一起使用,表示short int或unsigned short int类型的值 |
hh | 和整型转换说明一起使用,表示signed char或unsigned char类型的值 |
j | 和整型转换说明一起使用,表示intmax_t或uintmax_t类型的值,这些类型定义在stdint.h中 |
l | 和整型转换说明一起使用,表示long int或unsigned long int类型的值和浮点转换说明一起使用,表示 double long类型的值 |
ll | 和整型转换说明一起使用,表示long long int或unsigned long long int类型的值(C99) |
t | 和整型转换说明一起使用,表示ptrdiff_t类型的值,ptrdiff_t是两个指针差值的类型(C99) |
z | 和整型转换说明一起使用,表示size_t类型的值。size_t是sizeof返回的类型(C99) |
3.2 使用scanf()
scanf()函数使用指向变量的指针,不过这里先不写指针方面的内容。只需要记住:
- 如果用
scanf()读取基本变量类型的值,需要在变量名前加一个& - 如果用
scanf()吧字符串读入字符数组中,不要使用&
ANSI C中的scanf()的转换说明
| 转换说明 | 含义 |
|---|---|
%c | 把输入解释成字符 |
%d | 把输入解释成有符号的十进制整数 |
%e、%f、%g、%a%E、%F、%G、%A | 把输入解释成浮点数(C99标准新增了%a和%A) |
%i | 把输入解释成有符号十进制整数 |
%o | 把输入解释成有符号八进制整数 |
%p | 把输入解释成指针(地址) |
%s | 把输入解释成字符串,从第1个非空白字符开始,到下一个非空白之前的所有字符都是输入 |
%u | 把输入解释成无符号十进制整数 |
%x、%X | 把输入解释成有符号十六进制整数 |
可以在转换说明中使用修饰符。若要使用多个修饰符,则必须按表中顺序书写
| 转换说明 | 含义 |
|---|---|
* | 抑制赋值 |
| 数字 | 最大字段宽度。输入达到最大字段宽度处,或第1次遇到空白字符时停止 |
hh | 把整数作为signed char或unsigned char类型读取 |
ll | 把整数作为long long或unsigned long long类型读取(C99新增) |
h、l或L | %hd和%hi表明把对应的值储存为short int类型%ho、%hx和%hu表明把对应的值储存为unsigned short int类型%ld和%li表明把对应的值储存为long类型%lo、%lx和%lu表明把对应的值储存为unsigned long类型%le、%lf和%lg表明把对应的值储存为double类型在 e、f和g前面使用L,表明把对应的值储存为long double类型,如果没有修饰符,d、i、o和x表明把对应的值储存为int类型,f和g表明把对应的值储存为float类型 |
j | 在整型转换说明后面时,表明使用intmax_t或uintmax_t类型(C99新增) |
z | 在整型转换说明后面时,表明使用sizeof的返回类型(C99新增) |
t | 在整型转换说明后面时,表明使用两个指针差值的类型(C99新增) |
3.2.1 从scanf()角度看输入
假设scanf()根据一个%d转换说明读取一个整数,那它会先读取第一个非空白字符,如果该字符是数字或符号,便存下该字符,继续读取下一个字符,直到遇到非数字字符,此时scanf()会将非数字字符放回输入,这样程序下一次读取输入时,会从被放回的这个字符开始读取。
如果使用字段宽度,那么则在字段结尾或第1个空白字符处停止读取。
如果遇到的第一个非空白字符不是数字,比如'A',那么会不赋值给变量,如果scanf()中全部是%d,那么读取就会一直卡在字符'A'上,无法越过。
3.2.2 格式字符串中的普通字符
scanf()函数允许吧普通字符放在格式字符串中。除空格字符外的普通字符必须与输入字符串严格匹配。
scanf("%d,%d", &n, &m);
scanf()函数将其解释为用户将输入一个数字、一个逗号和一个数字。也就是说用户必须用逗号分隔输入的两个数字。
格式字符串中的空格意味着跳过下一个输入项前面的所有空白,这包括“没有空白”的情况。
3.2.3 scanf()返回值
scanf()返回成功读取的项数
3.3 printf()和scanf()的*修饰符
printf()中使用*修饰符来代替字段宽度,可以通过它让程序来指定字段宽度,而不需要你事先预设。这点同样可以应用于浮点值指定精度和字段宽度。
#include <stdio.h>
int main(void) {
unsigned width, precision;
int number = 256;
double weight = 242.5;
printf("Enter a field width:\n");
scanf("%d", &width);
printf("The number is : %*d\n", width, number);
printf("Now there a width and a precision:\n");
scanf("%d %d", &width, &precision);
printf("Weight = %*.*f\n", width, precision, weight);
printf("Done!\n");
return 0;
}
scanf()中,把*放在%和转换字符之间时,会使得scanf()跳过相应的输出项。
#include <stdio.h>
int main(void) {
int n;
printf("Please enter three integers:\n");
scanf("%*d %*d %d", &n);
printf("The last integer was %d\n", n);
return 0;
}