C语言学习笔记(二):字符串和格式化输入/输出

本章的主题是C语言的字符串和格式化输入/输出。


  1. C语言没有专门用于存储字符串的变量类型,字符串都被存储在char类型的数组中。

  2. 数组是同类型数据元素的有序序列。

    • char name[40]为例,name后面的方括号表明这是一个数组,方括号中的40表明该数组中的元素数量,char表明每个元素的类型。
    • 字符串可以理解为字符数组,每个单元存储一个字符,数组末尾用一个空字符(null character)标识结束。
  3. 空字符\0是非打印字符,其ASCII码值为0。由于空字符的存在,因此字符串实际能存储的字符数要减1,剩下一个字节留给空字符。上例中字符串name实际能存储的字符数为39

  4. 转换字符%s用于读写字符串,%zd用于处理sizeof()strlen()的返回值。

  5. scanf()在遇到第一个空白(空格、制表符或换行符)时就不再读取输入。C语言还有其他的输入函数(如,fgets()),用于读取一般字符串,后面会详谈。

  6. 使用符号常量(symbolic constant)明示常量(manifest constant)的好处:

    • 常量名比数字表达的信息更多;
    • 复用性更好。
  7. 使用C预处理器来定义符号常量:#define NAME value

    • 例如,#define PI 3.14159。编译程序时,程序中所有的PI都会被替换成3.14159。这一过程被称为编译时替换(compile-time substitution)
    • 为什么PI要大写?因为用大写表示符号常量是C语言一贯的传统,这样做是为了提高程序的可读性,在程序中看到全大写的名称就立刻明白这是一个符号常量,而非变量。
  8. C90标准新增了const关键字,用于限定一个变量为只读。

    const int MONTHS = 12;    // MONTHS在程序中不可更改,值为12
    

    const用起来比#define更灵活,后续会详谈。

  9. printf()scanf()是标准输入/输出函数,简称为I/O函数。printf()把整数、浮点数、字符和字符串转换成显示在屏幕上的文本,而scanf()正好与它相反,把输入的字符串转换成整数、浮点数、字符和字符串存储在内存中。

  10. printf()的格式为:printf(格式字符串, 待打印项1, 待打印项2, ...)
    其中,格式字符串是双引号括起来的内容,包含两种形式不同的信息:(1)实际要打印的字符;(2)转换说明。待打印项1、待打印项2等都是要打印的项,可以是变量、常量或表达式。

  11. printf()的转换说明

转换说明 含义
%a 浮点数、十六进制数和p记数法(C99/C11)
%A 浮点数、十六进制数和p记数法(C99/C11)
%c 单个字符
%d 有符号十进制整数
%e 浮点数,e记数法
%E 浮点数,e记数法
%f 浮点数,十进制记数法
%g 根据值的不同,自动选择%f%e
%G 根据值的不同,自动选择%f%E
%i 有符号十进制整数(和%d相同)
%o 无符号八进制整数
%p 指针
%s 字符串
%u 无符号十进制整数
%x 无符号十六进制整数,使用十六进制数0f
%X 无符号十六进制整数,使用十六进制数0F
%% 打印一个百分号
  1. printf()的转换说明修饰符:在%转换字符之间插入修饰符可修饰基本的转换说明。
修饰符 含义
标记           有6种标记(-+空格#*0),可以不使用标记或使用多个标记

-:待打印项左对齐

+:有符号值若为正,则在值前面显示加号;若为负,则在值前面显示减号

空格:有符号值若为正,则在值前面显示前导空格;若为负,则在值前面显示减号

#:把结果转换为另一种类型。如果是%o格式,则以0开始;如果是%x%X格式,则以0x0X开始;对于所有的浮点格式,#保证了即使后面没有任何小数,也打印一个小数点字符;对于%g%G格式,#防止结果后面的0被删除

*:抑制赋值(详见后面解释)

0:对于数值格式,用前导0代替空格填充字段宽度。对于整型格式,如果出现-标记或指定精度,则忽略该标记  
数字 最小字段宽度
如果该字段不能容纳待打印的数字或字符串,系统会使用更宽的字段
.数字 精度
对于%e%E%f转换,表示小数点右边数字的位数
对于%s转换,表示待打印字符的最大数量
对于整型转换,表示待打印数字的最小位数
如有必要,使用前导0来达到这个位数
只使用.表示其后跟随一个0,所以%.f%.0f相同
h 和整型转换说明一起使用,表示short intunsigned short int类型的值
hh 和整型转换说明一起使用,表示signed charunsigned char类型的值
j 和整型转换说明一起使用,表示intmax_tuintmax_t类型的值。这些类型定义在stdint.h
l 和整型转换说明一起使用,表示long intunsigned long int类型的值
ll 和整型转换说明一起使用,表示long long intunsigned long long int类型的值
L 和浮点转换说明一起使用,表示long double类型的值
t 和整型转换说明一起使用,表示ptrdiff_t类型的值。ptrdiff_t是两个指针差值的类型
z 和整型转换说明一起使用,表示size_t类型的值。size_tsizeof()返回的类型
  1. printf()有一个返回值,它返回打印字符的个数。如果有输出错误,则返回一个负值。

  2. 给字符串断行有3种方法。

// longstrg.c --打印较长的字符串
#include 

int main(void)
{
    // 方法1:使用多个printf()语句
    printf("Here's one way to print a ");
    printf("long string.\n");

    // 方法2:使用反斜杠和Enter键组合
    printf("Here's another way to print a \
long string.\n");

    // 方法3:字符串连接
    printf("Here's the newest way to print a "
            "long string.\n");

    return 0;
 }
  1. scanf()函数的格式为:scanf(格式字符串, 地址列表)
    其中,地址列表是指向变量的指针,此处不必了解如何使用指针,只需记住以下两条简单的规则:

    • 如果用scanf()读取基本变量类型的值,则在变量名前加上一个&
    • 如果用scanf()把字符串读入字符数组中,不要使用&
  2. scanf()函数所用的转换说明与printf()函数几乎相同。主要的区别是,对于float类型和double类型,printf()都使用%f%e%E%g%G转换说明,而scanf()只把它们用于float类型,对于double类型要用l修饰符。

  3. scanf()中,除了%c,其他转换说明都会自动跳过待输入值前面的所有空白。

  4. scanf()函数允许把普通字符放在格式字符串中。除空格字符外的普通字符必须与输入字符串严格匹配

  5. scanf()函数返回成功读取的项数。如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,scanf()便返回0

  6. printf()scanf()都可以使用*修饰符来修改转换说明的含义,但用法不一样。

    • printf():如果不想预先指定字段宽度或精度,希望通过程序来指定,可以用*修饰符代替字段宽度或精度,但需要参数告诉函数,字段宽度或精度应该是多少。
    • scanf():把*放在%和转换字符之间时,会使得scanf()跳过相应的输入项。在程序需要读取文件中特定列的内容时,这项跳过功能很有用。
  7. 使用scanf()输入分数时,不能直接使用以下语句

/* 这是错误的分数输入 */
scanf("%f", &x);    // 在实际输入的时候不能输入类似"3/7"的数值,因为scanf()并不能识别"/"

/* 这是正确的分数输入 */
scanf("%d/%d", &x, &y);
  1. 使用scanf()可以实现长数据的截取与跳过
/* 截取身份证号的出生年月日 */
#include 

int main(void)
{
    int year, month, day;
    
    printf("请输入您的身份证号:");
    scanf("%*6d%4d%2d%2d%*4d", &year, &month, &day);

    printf("您的生日是:%d年%d月%d日\n", year, month, day);

    return 0;
 }

下一章的主题是C语言的运算符、表达式和语句。

你可能感兴趣的:(C语言学习笔记(二):字符串和格式化输入/输出)