<stdio.h>

scanf()函数

概述

  • scanf是 C 语言中的一个标准库函数,主要用于从标准输入流(一般指键盘)读取格式化的输入数据 ,并将其存储到程序中指定的变量中。

  • 关于scanf()在读取的时候,占位符、后方变量地址、以及输入数据时的格式”一一对应”的规则:

  • 占位符格式

    scanf 函数的占位符格式用于指定要读取的数据类型,常见的占位符有:

    • %d:用于读取十进制整数,对应的数据类型是 int
    • %f:用于读取单精度浮点数,对应的数据类型是 float
    • %lf:用于读取双精度浮点数,对应的数据类型是 double
    • %c:用于读取单个字符,对应的数据类型是 char
    • %s:用于读取字符串(以空白字符分隔),对应的数据类型是字符数组。
    • %x%X:用于读取十六进制整数,对应的数据类型是 int
    • %o:用于读取八进制整数,对应的数据类型是 int

传递变量地址的格式

scanf 函数中,需要传递变量的地址,以便将读取的数据存储到相应的变量中。对于基本数据类型的变量,需要使用取地址运算符 & 来获取变量的地址;对于字符数组,由于数组名本身就代表数组首元素的地址,所以不需要使用 &

命令端输入数据格式与占位符格式的对应关系以及规律

  • 一句话总结规律:scanf函数的读取流程由其中的占位符号代表的数据类型来决定,并且在大多数情况下,就是在讨论关于空白字符(空格、制表符、换行符等 )与目标类型数据的关系,并且:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

int main(){
int a;
char c;

printf("请输入一个整数和一个字符");
scanf("%d,%c",&a &c);
/*我想表达的是:
scanf的读取机制只由前面字符串内部的占位符的分布情况决定
和后面传参的分布无关(当然是在后面参数类型个数都和前面相对应的情况下)
*/
printf("整型数字为:%d,字符为:%c",a,b);
}
  • 具体来说如下:
  • 整体原则scanf 按照格式控制字符串中格式说明符(如 %d%c%s 等 )的顺序和要求,从标准输入流中读取数据,并存储到对应变量地址指向的内存空间。
  • 针对不同类型说明符
    • 整数类型说明符(如 %d%i%o%x 等 ):自动跳过输入流开头的空白字符(空格、制表符、换行符 ),从第一个非空白字符开始,依据对应进制规则读取,直到遇到不属于该进制表示的字符(即非数字字符 ),然后把读取的内容转换为整数存入变量,剩余字符留在输入流。
    • 字符类型说明符 %c
      • 单纯的 %c 会直接读取输入流中的下一个字符,不管是不是空白字符。
      • %c 前面有空格(如 %c )时,先跳过输入流开头的空白字符,再读取第一个非空白字符。
    • 字符串类型说明符 %s:自动跳过输入流开头的空白字符,从第一个非空白字符开始读取,遇到下一个空白字符时停止,自动在末尾添加 \0 ,存入字符数组。

getchar()

  • 重点介绍:getchar函数可以即时读取输入流的信息,不管是从输入流的首部,中部还是尾部,都可以即时切入输入流对其字符进行读取

  • 如以下代码

  • #include <stdio.h>
    
    void main()
    {
        char b[3][10], c;
        int i;
        for (i = 0; i < 2; i++) scanf("%s", b[i]);
        i = 0;
        while ((c = getchar()) != '\n') b[2][i++] = c;
        /*这里getchar函数,接着scanf停止的那个空格继续读取数据流,
        scanf最后一次读取在flower后面的空格停止,
        所以getchar逐个把<空格>is<空格>pink读取,存入b[2]中,
        这些数据流读取函数在遇到停止的符号时,会直接停止操作并且不会将这些符号读入。
        */
        b[2][i] = '\0';
        printf("%s%s%s\n", b[0], b[1], b[2]);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    * 执行时若输入以下字符串:
    `Peach flower is pink.<回车>`

    * 输出结果是什么?

    * 是:`Peachflower is pink.`

    ## 文件操作专项

    * 较为详细全面的描述可见[菜鸟教程——c语言文件](https://www.runoob.com/cprogramming/c-file-io.html)

    ### `fopen()`

    * 首先进行实例化:

    * ```c
    #include <stdio.h>

    int main(){
    FILE *fp;
    if(fopen("text.txt","w"))==NULL){
    printf("不能打开文件!");
    }
    else{
    printf"成功打开文件!";

    return 0;
    }
    }
  • **注意:**打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,文件内容会被清空(即文件长度被截断为0)。

  • 所以如果在该代码情景下,该文件不存在的话,程序会输出:成功打开文件!

printf

  • 看例题:
  • 在 C 语言里,printf("%s", 指针) 这种形式,%s 格式说明符要求指针指向字符串(以 '\0' 结尾的字符序列 )。当你使用 pm[i]+i 时:
    • pm[i] 是指向对应字符串首地址的指针 ,pm[i]+i 让这个指针向后移动 i 个字符位置。但当把 pm[i]+i 传给 printf("%s" 时,printf 会从 pm[i]+i 所指向的位置开始,顺着内存往后找,只要没遇到字符串结束符 '\0' ,就会一直输出字符,直到碰到 '\0' 才停止 ,所以不是只输出索引为 i 的单个字符,而是输出从该位置开始到字符串结束的内容。
    • 也就说,%s会让数组s1i这个索引开始一直往后输出字符直到遇到结束符而不是只输出那一位字符

<string.h>

strlen()函数

概述

  • 在c语言中strlen()函数负责计算字符串长度,其适用范围有一定的要求:
  • 适用数据类型:只能用于以空字符'\0'结尾的 C 风格字符串。这里的字符串通常用字符数组或字符指针来表示。例如:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <string.h>

int main() {
char str1[] = "Hello"; // 字符数组表示字符串
char *str2 = "World"; // 字符指针指向字符串
printf("str1的长度: %zu\n", strlen(str1));
printf("str2的长度: %zu\n", strlen(str2));
return 0;
}
  • 不适用数据类型:不能用于其他非字符串类型,如整数、浮点数、结构体等;如果字符串没有以'\0'结尾,使用strlen会导致未定义行为。因为strlen会从给定的内存地址开始,一直向后遍历内存,直到遇到'\0'才停止计数,若没有'\0',它会继续访问不属于该字符串的内存区域,可能引发程序崩溃或得到错误的结果。 例如:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <string.h>

int main() {
char arr[5] = {'a', 'b', 'c', 'd', 'e'}; // 没有'\0'结尾
// 以下行为是未定义的
size_t len = strlen(arr);
printf("长度: %zu\n", len);
return 0;
}
  • 多字节字符集的情况strlen按字节计算长度,在处理单字节字符集(如 ASCII)时能正常返回字符个数;但在处理多字节字符集(如 UTF-8)时,返回的是字节数而非字符数,结果可能不符合预期 。比如一个中文字符在 UTF-8 编码下通常占 3 个字节,strlen会将其计为 3,而不是 1 个字符。

此外,当字符数组作为参数传递给函数时,会退化为指针,此时strlen计算的是指针所指向的字符串的长度,而不是数组的实际大小。