0
点赞
收藏
分享

微信扫一扫

【C语言初阶】掌握C语言调试技巧,迈向高效编程的阶梯

后来的六六 2024-08-18 阅读 8

目录

一.getchar()函数

1.基本功能

2.使用方法

(1).读取单个字符

(2).读取多个字符(直到遇到换行符)

(3).处理输入中的空白字符

3.返回值

4.应用场景

5.注意事项

二.fgets()函数

1.函数原型

2.工作原理

3.使用示例

(1).从标准输入读取一行字符串

(2).从文件中读取内容

4.处理换行符

5.与其他输入函数的比较

(1). fgets vs gets

(2). fgets vs scanf

(3). fgets vs fgetc

6、常见错误和注意事项

(1). 忘记检查返回值

(2). 未正确处理换行符

(3). 缓冲区大小不足

(4). 多次读取时的缓冲区残留

7.综合示例

三.sscanf函数

1.函数原型

2.工作原理

(1).从字符串中解析数据

3.常见用法和注意事项

(1). 解析特定格式的字符串

(2). 处理多余的输入

(3). 不匹配的格式

(4). 忽略特定数据

(5). 返回值处理

4.常见错误和陷阱

(1). 未匹配到预期的数据

(2). 忘记检查返回值

(3). 缓冲区溢出

(4). 处理多余输入

5.sscanf 与其他输入函数的比较

(1). sscanf vs scanf

(2). sscanf vs fscanf

(3). sscanf vs strtok

6.综合示例

四.fscanf()函数

1.函数原型

2.工作原理

3.常用用法和注意事项

(1). 读取一行数据

(2). 文件指针位置

(3). 遇到EOF

(4). 忽略特定数据

(5). 返回值处理

(6). 处理多余输入

4.常见错误和陷阱

(1). 格式不匹配

(2). 忘记检查返回值

(3). 文件结束符

5.fscanf 与其他输入函数的比较

(1). fscanf vs scanf

(2). fscanf vs sscanf

(3). fscanf vs fgets

6.综合示例


一.getchar()函数

1.基本功能

2.使用方法

int ch = getchar();

示例:

(1).读取单个字符

#include <stdio.h>

int main() {
    int ch;
    
    printf("请输入一个字符: ");
    ch = getchar();
    
    printf("你输入的字符是: %c\n", ch);
    
    return 0;
}

解释:

  • 程序等待用户输入一个字符。用户输入的字符被getchar()读取并存储在ch中。
  • printf函数随后输出用户输入的字符。

(2).读取多个字符(直到遇到换行符)

#include <stdio.h>

int main() {
    int ch;
    
    printf("请输入一行文字,按回车结束: ");
    
    while ((ch = getchar()) != '\n' && ch != EOF) {
        printf("读取字符: %c\n", ch);
    }
    
    printf("输入结束。\n");
    
    return 0;
}

解释:

  • 程序使用while循环来读取字符,直到遇到换行符('\n')或文件结束符(EOF)。
  • 每次读取的字符都会被输出。

(3).处理输入中的空白字符

#include <stdio.h>

int main() {
    int ch;

    printf("请输入字符,输入结束请按 Ctrl+D (Linux) 或 Ctrl+Z (Windows):\n");

    while ((ch = getchar()) != EOF) {
        if (ch == ' ' || ch == '\n' || ch == '\t') {
            printf("[空白字符]\n");
        } else {
            printf("读取字符: %c\n", ch);
        }
    }

    printf("输入结束。\n");
    
    return 0;
}

解释:

  • 这个程序读取用户输入的每个字符,并检查它是否是空白字符(空格、换行符、制表符)。
  • 如果是空白字符,程序会输出[空白字符],否则输出字符本身。
  • 当用户按下Ctrl+DCtrl+Z时,输入结束。

3.返回值

  • 读取的字符: 如果读取成功,getchar()返回读取的字符的ASCII值。例如,如果用户输入字符'A'getchar()将返回值65(即'A'的ASCII码)。

  • EOF (End of File): 如果在读取时遇到文件结束符(通常是在控制台输入时按下Ctrl+DCtrl+Z),getchar()将返回常量EOF,其值通常为-1EOF用于指示输入的结束或错误情况。

4.应用场景

5.注意事项

二.fgets()函数

1.函数原型

返回值

  • 成功: 返回指向读取字符串的指针,即参数 str
  • 失败或到达文件末尾: 返回 NULL

2.工作原理

3.使用示例

(1).从标准输入读取一行字符串

#include <stdio.h>

int main() {
    char buffer[100];

    printf("请输入一行文本:");
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        printf("您输入的是:%s", buffer);
    } else {
        printf("读取输入时发生错误。\n");
    }

    return 0;
}

解释:

  • fgets(buffer, sizeof(buffer), stdin) 从标准输入读取最多 99 个字符(保留1个字符给 \0),并存储在 buffer 中。
  • 如果读取成功,程序会输出用户输入的内容。

注意: 由于 fgets 会将换行符 \n 一并读取并存储,如果不想要这个换行符,需要手动去除。

(2).从文件中读取内容

#include <stdio.h>

int main() {
    FILE *fp = fopen("example.txt", "r");
    if (fp == NULL) {
        perror("无法打开文件");
        return 1;
    }

    char line[256];
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("%s", line);
    }

    fclose(fp);
    return 0;
}

解释:

  • 打开名为 example.txt 的文件,读取其中的内容并逐行打印到标准输出。
  • fgets 在每次循环中读取一行内容,直到文件结束。

4.处理换行符

正如前面提到的,fgets 会将输入中的换行符 \n 一并读取并存储在目标字符串中。如果在处理时不需要这个换行符,可以使用以下方法去除:

方法1:手动检查并替换

size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
    buffer[len - 1] = '\0';
}

解释:

  • 首先获取字符串的长度 len
  • 如果最后一个字符是 \n,将其替换为 \0

方法2:使用 strcspn 函数

buffer[strcspn(buffer, "\n")] = '\0';

解释:

  • strcspn 函数返回 buffer 中第一个匹配 \n 的位置索引,然后将该位置的字符替换为 \0

5.与其他输入函数的比较

(1). fgets vs gets

  • gets: 从标准输入读取一行,直到遇到换行符或文件结束符。不安全,因为无法指定读取的最大长度,容易导致缓冲区溢出。

  • fgets: 可以指定最大读取长度,安全性更高。建议始终使用 fgets 代替 gets

(2). fgets vs scanf

  • scanf: 按照指定的格式从输入中读取数据,默认会忽略空白字符,读取字符串时会在遇到空白字符时停止。

  • fgets: 读取整行输入,包括空白字符和换行符,更适合读取包含空格的字符串

示例:

char str1[100], str2[100];

// 使用 scanf
scanf("%s", str1);
// 输入:Hello World
// str1 的值为:"Hello"

// 使用 fgets
fgets(str2, sizeof(str2), stdin);
// 输入:Hello World
// str2 的值为:"Hello World\n"

(3). fgets vs fgetc

  • fgetc: 每次从指定流中读取一个字符,适合逐字符处理输入。

  • fgets: 一次读取一行或指定长度的字符串,效率更高。

6、常见错误和注意事项

(1). 忘记检查返回值

错误示例:

fgets(buffer, sizeof(buffer), stdin);
// 未检查返回值,可能导致程序处理空指针

正确示例:

if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
    // 处理读取的数据
} else {
    // 错误处理
}

(2). 未正确处理换行符

(3). 缓冲区大小不足

错误示例:

char buffer[10];
fgets(buffer, 100, stdin); // 错误:缓冲区只有10个字节,却试图读取100个字符

正确示例:

char buffer[100];
fgets(buffer, sizeof(buffer), stdin); // 正确:缓冲区大小与读取长度匹配

(4). 多次读取时的缓冲区残留

char buffer1[50], buffer2[50];

printf("输入第一行:");
fgets(buffer1, sizeof(buffer1), stdin);

printf("输入第二行:");
fgets(buffer2, sizeof(buffer2), stdin);

如果在第一次输入时输入的字符超过了 buffer1 的大小,剩余的字符会留在输入缓冲区中,影响第二次读取。为避免这种情况,可以在每次读取后清空缓冲区。

清空缓冲区的方法:

int c;
while ((c = getchar()) != '\n' && c != EOF);

7.综合示例

示例:读取用户输入并处理

#include <stdio.h>
#include <string.h>

int main() {
    char name[50];
    int age;
    char input[100];

    // 读取姓名
    printf("请输入您的姓名:");
    if (fgets(name, sizeof(name), stdin) != NULL) {
        // 去除换行符
        name[strcspn(name, "\n")] = '\0';
    } else {
        printf("读取姓名失败。\n");
        return 1;
    }

    // 读取年龄
    printf("请输入您的年龄:");
    if (fgets(input, sizeof(input), stdin) != NULL) {
        // 将字符串转换为整数
        age = atoi(input);
    } else {
        printf("读取年龄失败。\n");
        return 1;
    }

    printf("姓名:%s,年龄:%d\n", name, age);

    return 0;
}

解释:

  • 首先使用 fgets 读取用户的姓名,并去除结尾的换行符。
  • 然后再次使用 fgets 读取用户的年龄输入,并使用 atoi 将其转换为整数。
  • 最后输出用户输入的信息。

三.sscanf函数

1.函数原型

返回值

  • 成功: 返回成功读取并匹配的项数
  • 失败: 返回 EOF,如果在解析过程中遇到错误或在尝试读取时到达字符串末尾

2.工作原理

示例:

(1).从字符串中解析数据

#include <stdio.h>

int main() {
    const char *str = "100 3.14 hello";
    int num;
    float pi;
    char word[20];

    int count = sscanf(str, "%d %f %s", &num, &pi, word);

    printf("读取到 %d 项数据:\n", count);
    printf("整数: %d\n", num);
    printf("浮点数: %.2f\n", pi);
    printf("字符串: %s\n", word);

    return 0;
}

输出:

读取到 3 项数据:
整数: 100
浮点数: 3.14
字符串: hello

解释:

  • sscanf 解析字符串 "100 3.14 hello",并将数据分别存储在 num, pi, word 中。
  • 返回值 count 表示成功读取了3项数据。

3.常见用法和注意事项

(1). 解析特定格式的字符串

示例:解析日期

#include <stdio.h>

int main() {
    const char *date = "2024-08-17";
    int year, month, day;

    sscanf(date, "%d-%d-%d", &year, &month, &day);

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

    return 0;
}

输出:

年: 2024, 月: 8, 日: 17

解释:

  • 解析字符串 "2024-08-17" 中的年份、月份和日期,并分别存储在 year, month, day 中。

(2). 处理多余的输入

示例:部分解析字符串

#include <stdio.h>

int main() {
    const char *str = "42 3.14 some extra text";
    int num;
    float pi;

    int count = sscanf(str, "%d %f", &num, &pi);

    printf("读取到 %d 项数据:\n", count);
    printf("整数: %d\n", num);
    printf("浮点数: %.2f\n", pi);

    return 0;
}

输出:

读取到 2 项数据:
整数: 42
浮点数: 3.14

解释:

  • sscanf 只解析了前两个数据项(整数和浮点数),忽略了字符串末尾的额外内容。

(3). 不匹配的格式

示例:格式不匹配

#include <stdio.h>

int main() {
    const char *str = "hello 3.14";
    int num;
    float pi;

    int count = sscanf(str, "%d %f", &num, &pi);

    printf("读取到 %d 项数据:\n", count);
    return 0;
}

输出:

读取到 0 项数据:

(4). 忽略特定数据

示例:忽略数据

#include <stdio.h>

int main() {
    const char *str = "42 skip this 3.14";
    int num;
    float pi;

    sscanf(str, "%d %*s %f", &num, &pi);

    printf("整数: %d\n", num);
    printf("浮点数: %.2f\n", pi);

    return 0;
}

输出:

整数: 42
浮点数: 3.14

解释:

  • sscanf 使用 %*s 忽略了 "skip this" 字符串部分,只提取了整数和浮点数。

(5). 返回值处理

示例:检查返回值

#include <stdio.h>

int main() {
    const char *str = "100 3.14";
    int num;
    float pi;

    int result = sscanf(str, "%d %f", &num, &pi);

    if (result == 2) {
        printf("成功读取两个数值:%d 和 %.2f\n", num, pi);
    } else {
        printf("解析失败,已成功读取 %d 项数据。\n", result);
    }

    return 0;
}

输出:

成功读取两个数值:100 和 3.14

解释:

  • 如果 sscanf 成功解析了两个值,程序输出成功消息。否则,输出失败消息。

4.常见错误和陷阱

5.sscanf 与其他输入函数的比较

(1). sscanf vs scanf

  • scanf: 从标准输入中读取数据,适用于直接的用户输入操作。

  • sscanf: 从字符串中读取数据,适用于解析已经存在的字符串内容。

(2). sscanf vs fscanf

  • fscanf: 从文件流中读取数据,适用于从文件中解析数据。

  • sscanf: 从字符串中读取数据,适用于解析内存中的字符串。

(3). sscanf vs strtok

  • strtok: 用于分割字符串,可以按指定的分隔符逐一提取子字符串。

  • sscanf: 直接解析字符串中的数据,并将其转换为相应的数据类型。

6.综合示例

示例:解析复杂字符串

#include <stdio.h>

int main() {
    const char *str = "Name: John Doe, Age: 30, Score: 85.5";
    char name[50];
    int age;
    float score;

    int count = sscanf(str, "Name: %[^,], Age: %d, Score: %f", name, &age, &score);

    if (count == 3) {
        printf("姓名: %s\n", name);
        printf("年龄: %d\n", age);
        printf("分数: %.1f\n", score);
    } else {
        printf("解析字符串失败。\n");
    }

    return 0;
}

输出:

姓名: John Doe
年龄: 30
分数: 85.5

解释:

  • 使用 sscanf 从格式化字符串中提取姓名、年龄和分数。%[^,] 格式说明符用于读取直到遇到逗号 , 的所有字符,这样可以处理包含空格的姓名。

四.fscanf()函数

1.函数原型

返回值

  • 成功: 返回成功读取并匹配的项数
  • 失败: 如果遇到文件结束符 EOF,则返回 EOF。如果遇到错误,返回负数。

2.工作原理

fscanf 函数根据 format 字符串中的格式说明符,从文件流 stream 中逐一读取和解析数据。每个格式说明符都对应于一个传入的变量地址,fscanf 将解析后的数据存储在这些变量中。

格式说明符示例

  • %d: 读取一个整数。
  • %f: 读取一个浮点数。
  • %s: 读取一个字符串,遇到空白字符(如空格、换行)时停止。
  • %c: 读取单个字符。

示例:从文件中解析数据

假设有一个文本文件 data.txt,内容如下:

42 3.14 hello
#include <stdio.h>

int main() {
    FILE *file = fopen("data.txt", "r"); // 打开文件进行读取
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int num;
    float pi;
    char word[20];

    int count = fscanf(file, "%d %f %s", &num, &pi, word);

    printf("读取到 %d 项数据:\n", count);
    printf("整数: %d\n", num);
    printf("浮点数: %.2f\n", pi);
    printf("字符串: %s\n", word);

    fclose(file); // 关闭文件
    return 0;
}

输出:

读取到 3 项数据:
整数: 42
浮点数: 3.14
字符串: hello

解释:

  • fscanf 从文件 data.txt 中解析数据,并将数据分别存储在 num, pi, word 中。
  • 返回值 count 表示成功读取了3项数据。

3.常用用法和注意事项

(1). 读取一行数据

示例:逐行读取数据

假设文件 data.txt 内容如下:

42 3.14 hello
43 2.71 world
#include <stdio.h>

int main() {
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int num;
    float pi;
    char word[20];

    while (fscanf(file, "%d %f %s", &num, &pi, word) != EOF) {
        printf("整数: %d, 浮点数: %.2f, 字符串: %s\n", num, pi, word);
    }

    fclose(file);
    return 0;
}

输出:

整数: 42, 浮点数: 3.14, 字符串: hello
整数: 43, 浮点数: 2.71, 字符串: world

(2). 文件指针位置

(3). 遇到EOF

(4). 忽略特定数据

示例:忽略数据

#include <stdio.h>

int main() {
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int num;
    float pi;

    while (fscanf(file, "%d %*s %f", &num, &pi) != EOF) {
        printf("整数: %d, 浮点数: %.2f\n", num, pi);
    }

    fclose(file);
    return 0;
}

解释:

  • fscanf 使用 %*s 忽略了字符串部分,只提取了整数和浮点数。

(5). 返回值处理

示例:检查返回值

#include <stdio.h>

int main() {
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int num;
    float pi;

    while (fscanf(file, "%d %f", &num, &pi) == 2) { // 期望成功读取2项数据
        printf("整数: %d, 浮点数: %.2f\n", num, pi);
    }

    fclose(file);
    return 0;
}

解释:

  • 只有在成功解析了两个值时才输出结果。如果 fscanf 未能成功读取两个值,将停止读取。

(6). 处理多余输入

4.常见错误和陷阱

(1). 格式不匹配

(2). 忘记检查返回值

(3). 文件结束符

5.fscanf 与其他输入函数的比较

(1). fscanf vs scanf

  • scanf: 从标准输入中读取数据,适用于直接的用户输入操作。

  • fscanf: 从文件流中读取数据,适用于从文件中解析数据。

(2). fscanf vs sscanf

  • sscanf: 从字符串中读取数据,适用于解析内存中的字符串。

  • fscanf: 从文件流中读取数据,适用于从文件中解析数据。

(3). fscanf vs fgets

  • fgets: 从文件中读取一整行字符串,适用于逐行读取文件内容,通常结合 sscanf 使用以进一步解析数据。

  • fscanf: 按照格式说明符从文件中读取数据,适用于逐项解析数据。

6.综合示例

示例:从文件中读取并解析数据

假设有一个文本文件 students.txt,内容如下:

John 20 85.5
Alice 22 90.0
Bob 21 78.5
#include <stdio.h>

int main() {
    FILE *file = fopen("students.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    char name[50];
    int age;
    float score;

    while (fscanf(file, "%s %d %f", name, &age, &score) == 3) {
        printf("姓名: %s, 年龄: %d, 分数: %.1f\n", name, age, score);
    }

    fclose(file);
    return 0;
}

输出

姓名: John, 年龄: 20, 分数: 85.5
姓名: Alice, 年龄: 22, 分数: 90.0
姓名: Bob, 年龄: 21, 分数: 78.5

解释:

  • fscanf 从文件 students.txt 中解析每一行数据,并输出到屏幕上。它通过格式说明符 %s %d %f 解析每行中的姓名、年龄和分数。

完!

一键三连支持一下吧,非常感谢!

举报

相关推荐

0 条评论