收集飞花令碎片——C语言字符函数与字符串函数

目录

一)字符函数

字符函数大部分都定义在<ctype.h>头文件中
在C语言中,字符是以其对应的ASCII码(整数)存储的。例如,字符 A 的ASCII码是65,a 是97,0 是48。字符函数本质上就是对传入的整数值(字符)进行判断或运算

字符分类函数

这些函数用于检查一个字符是否属于特定的类型。它们接收一个int类型的参数(字符的ASCII码),返回一个int类型的值:非零(真)或 零(假)

函数名 功能描述 包含范围 示例
iscntrl 检查字符是否为控制字符 ASCII码 0~31 和 127 (DEL) iscntrl('\n') → 真 iscntrl('a') → 假
isspace 检查字符是否为空白字符 空格' '、换页\f、换行\n、回车\r、水平制表符\t、垂直制表符\v isspace(' ') → 真 isspace('A') → 假
isdigit 检查字符是否为十进制数字 '0' ~ '9' isdigit('5') → 真 isdigit('a') → 假
isxdigit 检查字符是否为十六进制数字 '0'`'9'`、`'a'`'f''A'~'F' isxdigit('a') → 真 isxdigit('G') → 假
islower 检查字符是否为小写字母 'a' ~ 'z' islower('g') → 真 islower('G') → 假
isupper 检查字符是否为大写字母 'A' ~ 'Z' isupper('X') → 真 isupper('x') → 假
isalpha 检查字符是否为字母 'a'~'z''A'~'Z' isalpha('K') → 真 isalpha('2') → 假
isalnum 检查字符是否为字母或数字 'a'`'z'`、`'A'`'Z''0'~'9' isalnum('B') → 真 isalnum('!') → 假
ispunct 检查字符是否为标点符号 任何不属于字母数字的可打印图形字符 ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ \ { | } ~` ispunct('!') → 真 ispunct(' ') → 假
isgraph 检查字符是否为图形字符 所有可打印字符(不包括空格) isgraph('A') → 真 isgraph(' ') → 假
isprint 检查字符是否为可打印字符 所有图形字符 + 空格' ' isprint('A') → 真 isprint('\n') → 假

代码练习

通过从小写字母中减去 32 将字符串转换为大写

转换原理: 在ASCII码中,小写字母比对应的大写字母正好大32

c 复制代码
#include <stdio.h>
#include <ctype.h>

int main()
{
    int i = 0;
    char str[] = "Test String.\n";
    char c;
    
    while (str[i])
    {
        c = str[i];
        if (islower(c))
            c -= 32;
        putchar(c);
        i++;
    }
    return 0;
}

字符转换函数(to表示转变的意思)

字符大小写转换函数

我们只需要学习前两种大小写转换函数,后面的我们作了解即可

C语言提供了2个字符转换函数:

c 复制代码
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写

示例代码

c 复制代码
#include <stdio.h>
#include <ctype.h>
int main()
{
	int i = 0;
	char str[] = "Test String.\n";
	char c;
	while (str[i])
	{
		c = str[i];
		if (islower(c)) {
			c = toupper(c);
		}
		putchar(c);
		i++;
	}
	return 0;
}
c 复制代码
#include <stdio.h>
#include <ctype.h>

int main() {
    char ch1 = 'a', ch2 = 'B', ch3 = '5';
    
    printf("'%c' 转换为大写: '%c'\n", ch1, toupper(ch1));
    printf("'%c' 转换为小写: '%c'\n", ch2, tolower(ch2));
    printf("'%c' 转换: '%c'\n", ch3, toupper(ch3)); // 数字不变
    
    return 0;
}

字符与数字转换

字符 ↔ 数字

一般情况下我们都会采取==+'0'或者-'0'==来转换
下面我们介绍几种字符转换函数

atoi() - 字符串转整数
c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    char str1[] = "123";
    char str2[] = "45.67";
    char str3[] = "abc123";
    
    printf("'%s' -> %d\n", str1, atoi(str1));     // 123
    printf("'%s' -> %d\n", str2, atoi(str2));     // 45(遇到非数字停止)
    printf("'%s' -> %d\n", str3, atoi(str3));     // 0(开头非数字)
    
    return 0;
}
  • atof() -- 字符串转浮点数
  • atol() -- 字符串转长整数
itoa() - 整数转字符串
c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    char buffer[20];
    
    // 十进制
    itoa(12345, buffer, 10);
    printf("十进制: %s\n", buffer);  // "12345"
    
    // 二进制
    itoa(10, buffer, 2);
    printf("二进制: %s\n", buffer);  // "1010"
    
    // 十六进制
    itoa(255, buffer, 16);
    printf("十六进制: %s\n", buffer);  // "ff"
    
    return 0;
}

sprintf() - 格式化输出到字符串
c 复制代码
#include <stdio.h>

int main() {
    char buffer[100];
    int integer = 123;
    float floating = 45.67;
    double double_num = 89.123456;
    
    // 整数转字符串
    sprintf(buffer, "%d", integer);
    printf("整数: %s\n", buffer);  // "123"
    
    // 浮点数转字符串
    sprintf(buffer, "%.2f", floating);
    printf("浮点数: %s\n", buffer);  // "45.67"
    
    // 多种数据类型组合
    sprintf(buffer, "整数:%d, 浮点数:%.3f", integer, double_num);
    printf("组合: %s\n", buffer);  // "整数:123, 浮点数:89.123"
    
    // 不同进制转换
    sprintf(buffer, "十进制:%d, 十六进制:%x, 八进制:%o", 255, 255, 255);
    printf("进制: %s\n", buffer);  // "十进制:255, 十六进制:ff, 八进制:377"
    
    return 0;
}

二)字符串函数

使用前记得添加头文件

c 复制代码
#include <string.h>  // 字符串函数
#include <stdio.h>   // 输入输出

字符串长度 - strlen

c 复制代码
char str[] = "hello";
int len = strlen(str); // len = 5

字符串复制 - strcpy / strncpy

  • 功能: 将源字符串 src(包括终止空字符 \0)复制到目标缓冲区 dest。
c 复制代码
#include <string.h>
char *strcpy(char *dest, const char *src);
  • 代码示例
c 复制代码
char src[] = "hello";
char dest[10];
strcpy(dest, src); // dest = "hello"

strncpy

在VS中好像会出现安全性问题,这时候我们可以添加宏定义

c 复制代码
#define _CRT_SECURE_NO_WARNINGS

  • 功能: 最多复制 n 个字符从 src 到 dest
c 复制代码
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
  • 代码示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello World";
    char dest[10];
    
    // 安全复制,留一个位置给 \0
    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';  // 手动添加终止符
    
    printf("安全复制: %s\n", dest); // Hello Wor
    
    return 0;
}

字符串连接 - strcat

  • 函数原型
c 复制代码
char * strcat ( char * destination, const char * source );
  • 功能: 字符串追加,把source指向的源字符串中的所有字符都追加到destination指向的空间
    中。
  • 参数:
    destination :指针,指向⽬的地空间
    source :指针,指向源头数据
  • 返回值:
    strcat 函数返回的⽬标空间的起始地址
c 复制代码
char str[20] = "Hello";
strcat(str, " World");     // "Hello World"
strncat(str, "!!!", 2);    // "Hello World!!"

字符串比较 - strcmp / strncmp

  • 函数原型
c 复制代码
int strcmp ( const char * str1, const char * str2 );
  • 功能: ⽤来⽐较str1str2指向的字符串,从两个字符串的第⼀个字符开始⽐较,如果两个字符
    的ASCII码值相等,就⽐较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束。
    参数:
    str1 :指针,指向要⽐较的第⼀个字符串
    str2 :指针,指向要⽐较的第⼆个字符串
  • 返回值:
  • 标准规定:
    第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
    ◦ 第⼀个字符串等于第⼆个字符串,则返回0
    ◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
  • 代码示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char password[] = "secret123";
    char input[50];
    
    printf("请输入密码: ");
    scanf("%49s", input);
    
    if (strcmp(input, password) == 0) {
        printf("密码正确!\n");
    } else {
        printf("密码错误!\n");
    }
    
    // 字符串排序判断
    char name1[] = "John";
    char name2[] = "Alice";
    
    if (strcmp(name1, name2) < 0) {
        printf("'%s' 在 '%s' 之前\n", name1, name2); // 不会执行
    } else {
        printf("'%s' 在 '%s' 之后\n", name1, name2); // 会执行
    }
    
    return 0;
}

strncpy
c 复制代码
#include <string.h>
int strncmp(const char *str1, const char *str2, size_t n);
  • 功能

    比较两个字符串的前 n 个字符

  • 代码示例

c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple pie";
    char str2[] = "apple cake";
    
    // 只比较前5个字符
    int result = strncmp(str1, str2, 5);
    printf("前5字符比较: %d\n", result); // 0(相同)
    
    // 比较前8个字符
    result = strncmp(str1, str2, 8);
    printf("前8字符比较: %d\n", result); // 1(不同)
    
    return 0;
}

字符串查找 - strstr

  • 函数原型
c 复制代码
char * strstr ( const char * str1, const char * str2);

strstr 的使⽤得包含<string.h>

  • 参数:
    str1 :指针,指向了被查找的字符串
    str2 :指针,指向了要查找的字符串
  • 返回值:
    如果str1指向的字符串中存在str2指向的字符串,那么返回第⼀次出现位置的指针
    如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL

  • 代码示例
c 复制代码
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");
	if (pch != NULL)
		printf("%s\n", pch);
	else
		printf("查找的字符串不存在\n");
return 0;
}

字符串分隔strtok

  • 函数原型
c 复制代码
#include <string.h>
char *strtok(char *str, const char *delim);
  • 参数说明

    str:要分割的字符串(第一次调用时传入,后续传入NULL)

    delim:分隔符字符串(包含所有分隔字符)

  • 返回值

    成功:返回指向下一个token的指针

    结束:返回NULL(没有更多token)

strtok 函数会:
记住位置:在第一次调用后,它内部保存了当前处理的位置
继续分割:后续调用时从上次结束的位置继续


  • 代码示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "apple,banana,cherry,date";
    char *token;
    
    printf("分割字符串: %s\n", str);
    
    // 第一次调用
    token = strtok(str, ",");
    
    // 后续调用
    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");   //告诉函数"继续处理同一个字符串,从上一次的位置开始"
    }
    
    return 0;
}

错误码 - strerror

  • 函数原型
c 复制代码
#include <string.h>
char *strerror(int errnum);
  • 功能

    将错误代码转换为对应的错误描述字符串

  • 参数
    errnum:错误代码(通常是errno变量的值)

  • 返回值

    返回指向错误描述字符串的指针


c 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main() {
    // 假设发生了文件不存在的错误
    errno = 2;  // ENOENT 错误代码
    
    printf("错误说明: %s\n", strerror(errno));
    // 输出: No such file or directory
    
    return 0;
}

在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在errno.h这个头文件中说
明的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程
序启动的时候 errno是 0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,
就会将对应的错误码,存放在 errno 中,而一个错误码的数字是整数,很难理解是什么意思,所
以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误码对应的错误信息字符串的地
址返回。


  • 代码示例

我们看看0-10对应的错误码表示什么

c 复制代码
#include <errno.h>
#include <string.h>
#include <stdio.h>
//我们打印---下0~10这些错误码对应的信息
int main()
{
int i = 0;
	for (i = 0; i <= 10; i++) {
printf("%d: %s\n", i, strerror(i));
}
return 0;
}
c 复制代码
0: No error
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted function call
5: Input/output error
6: No such device or address
7: Arg list too long
8: Exec format error
9: Bad file descriptor
10: No child processes

FILE结构体

下面我们简单讲解一下FILE 这个结构体的内容

我们看下面这段代码

c 复制代码
/* 
 * 错误处理演示程序
 * 展示strerror和errno的使用方法
 */

// 包含标准输入输出头文件,提供FILE类型和fopen、printf等函数
#include <stdio.h>

// 包含字符串处理头文件,提供strerror函数
#include <string.h>

// 包含错误号定义头文件,提供errno变量和错误代码常量
#include <errno.h>

// 包含文件控制头文件,提供文件操作相关函数和常量(在此程序中未实际使用)
#include <fcntl.h>

// 主函数,程序入口点
int main() {
    // 声明文件指针变量,用于指向打开的文件
    // FILE是一个结构体类型,包含文件操作所需的所有信息
    FILE *file;
    
    // 尝试以只读模式("r")打开一个不存在的文件
    // fopen函数返回:
    // - 成功:指向FILE结构的指针
    // - 失败:NULL指针,同时设置errno变量
    file = fopen("nonexistent_file.txt", "r");
    
    // 检查文件是否打开成功
    // 由于文件不存在,fopen会返回NULL
    if (file == NULL) {
        // 输出错误代码:errno是一个全局变量,存储最近一次系统调用的错误代码
        // 此时errno的值应该是2(ENOENT),表示"No such file or directory"
        printf("错误代码: %d\n", errno);
        
        // 使用strerror函数将错误代码转换为可读的错误描述字符串
        // strerror(errno)会返回类似于"No such file or directory"的字符串
        printf("错误描述: %s\n", strerror(errno));
    }
    // 注意:如果文件打开成功,这里应该有关闭文件的代码
    // else {
    //     fclose(file);
    // }
    
    // 演示循环:展示前5个错误代码对应的描述信息
    // 注意:不是所有数字都有对应的错误描述,有些可能是"Unknown error"
    for (int i = 0; i < 5; i++) {
        // 对每个错误代码i,输出其对应的错误描述
        // strerror(i)会查找代码i对应的错误描述字符串
        printf("错误代码 %d: %s\n", i, strerror(i));
    }
    
    // 程序正常结束,返回0表示成功
    return 0;
}
  • 程序执行流程详细说明:
  1. 声明阶段:FILE *file; 声明一个文件指针,此时它还没有指向任何有效的文件结构。
  2. 文件打开尝试:fopen("nonexistent_file.txt", "r") 尝试打开文件,但由于文件不存在而失败。
  3. 错误处理:
    errno 被自动设置为相应的错误代码(通常是2,表示文件不存在)
    strerror(errno) 将数字错误代码转换为人类可读的描述
  4. 错误代码演示:循环显示前5个错误代码的描述,帮助理解错误代码与描述之间的映射关系。

C 标准库中提供了许多函数来操作 FILE 结构体,从文件的打开、读取、写入到关闭文件等。以下是与 FILE 类型相关的常见函数及其功能解释。


1. fopen()

打开一个文件并返回一个文件指针(FILE*)

c 复制代码
FILE *fopen(const char *filename, const char *mode);
  • filename:文件的路径。
  • mode:文件打开模式(如 "r", "w", "a", "rb", "wb" 等)。
  • 返回值:如果成功,返回一个FILE*指针;如果失败,返回 NULL
c 复制代码
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
    perror("Error opening file");
}

2. fclose()

关闭一个打开的文件。

c 复制代码
int fclose(FILE *stream);
  • stream:指向一个已打开文件的 FILE*

  • 返回值:成功返回0,失败返回 EOF

c 复制代码
fclose(file);

3. fread()

从文件中读取数据到内存。

c 复制代码
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
  • ptr:指向存储读取数据的内存块。

  • size:每个数据项的字节大小。

  • count`:要读取的数据项数量。

  • stream:文件指针。

  • 返回值:成功读取的项数。如果返回值小于 count,可能是到达文件末尾或发生错误。

c 复制代码
char buffer[100];
size_t n = fread(buffer, 1, sizeof(buffer), file);

4. fwrite()

向文件中写入数据。

c 复制代码
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
  • ptr:指向要写入的数据的内存块。

  • size:每个数据项的字节大小。

  • count:要写入的数据项数量。

  • stream:文件指针。

  • 返回值:成功写入的项数。

c 复制代码
const char *data = "Hello, World!";
fwrite(data, 1, strlen(data), file);

5. fgetc()

从文件中读取一个字符。

c 复制代码
int fgetc(FILE *stream);
  • stream:文件指针。

  • 返回值:成功时返回一个字符(int 类型,允许返回 EOF)。如果到达文件末尾,返回 EOF。

c 复制代码
int c = fgetc(file);
if (c == EOF) {
    printf("End of file or error.\n");
}

6. fputc()

向文件写入一个字符。

c 复制代码
int fputc(int c, FILE *stream);
  • c:要写入的字符。

  • stream:文件指针。

  • 返回值:成功时返回写入的字符,失败时返回 EOF。

c 复制代码
fputc('A', file);

7. fgets()

从文件中读取一行(包含换行符)。

c 复制代码
char *fgets(char *str, int n, FILE *stream);
  • str:存储读取行的缓冲区。
  • n:最多读取的字符数(包括 \0 字符)。
  • stream:文件指针。
  • 返回值:返回指向缓冲区的指针,或者如果读取失败或到达文件末尾返回 NULL。
c 复制代码
char line[100];
if (fgets(line, sizeof(line), file)) {
    printf("Line: %s", line);
}

8. fputs()

向文件写入一个字符串。

c 复制代码
int fputs(const char *str, FILE *stream);
  • str:要写入的字符串。

  • stream:文件指针。

  • 返回值:成功时返回非负值,失败时返回 EOF。

c 复制代码
fputs("Hello, World!", file);

9. fflush()

刷新文件流缓冲区,即将缓冲区中的数据写入文件。

c 复制代码
int fflush(FILE *stream);
  • stream:文件指针。如果为 NULL,则刷新所有输出流。

  • 返回值:成功时返回 0,失败时返回 EOF。

c 复制代码
fflush(file);

10. fseek()

移动文件指针到指定位置。

c 复制代码
int fseek(FILE *stream, long offset, int whence);
  • stream:文件指针。

  • offset:偏移量。

  • whence:起始位置(SEEK_SET, SEEK_CUR, SEEK_END)。

  • 返回值:成功时返回 0,失败时返回 -1。

c 复制代码
fseek(file, 0, SEEK_END);  // 移动到文件末尾

11. ftell()

获取当前文件指针的位置。

c 复制代码
long ftell(FILE *stream);
  • stream:文件指针。

  • 返回值:返回当前位置的偏移量,失败时返回 -1L。

c 复制代码
long pos = ftell(file);

12. rewind()

将文件指针移动到文件开头,并清除文件的错误标志。

c 复制代码
void rewind(FILE *stream);
  • stream:文件指针。
c 复制代码
rewind(file);  // 将文件指针移回文件开头

13. feof()

检查是否到达文件末尾。

c 复制代码
int feof(FILE *stream);
  • stream:文件指针。

  • 返回值:到达文件末尾时返回非零值,否则返回 0。

c 复制代码
if (feof(file)) {
    printf("End of file reached.\n");
}

14. ferror()

检查文件是否发生错误。

c 复制代码
int ferror(FILE *stream);
  • stream:文件指针。

  • 返回值:如果文件出错,返回非零值,否则返回 0

c 复制代码
if (ferror(file)) {
    printf("Error reading from file.\n");
}

15. perror()

打印文件操作相关的错误信息。

c 复制代码
void perror(const char *str);
  • str:一个自定义的前缀字符串(如错误发生的上下文)。
c 复制代码
perror("File opening error");

额外:perror

  • 功能
    perror 函数将当前错误代码对应的描述信息输出到标准错误流(stderr),并可以附加自定义的前缀信息。

  • 函数原型

c 复制代码
#include <stdio.h>
void perror(const char *s);
  • 参数
    s:自定义的前缀字符串(可以为NULL

  • 基本用法

c 复制代码
#include <stdio.h>
#include <errno.h>

int main() {
    FILE *file;
    
    // 尝试打开不存在的文件
    file = fopen("nonexistent_file.txt", "r");
    if (file == NULL) {
        // 使用 perror 输出错误信息
        perror("文件打开失败");
        // 输出: 文件打开失败: No such file or directory
    }
    
    return 0;
}

总结

字符函数和字符串函数是 C 语言中处理字符和字符串的重要工具,它们用于执行一系列与字符和字符串相关的操作,广泛应用于数据处理、文本处理和文件处理等多个领域。

如果你觉得这篇文章对你有帮助,请给文章一个三连吧

相关推荐
懂得节能嘛.4 小时前
【设计模式】Java规则树重构复杂业务逻辑
java·开发语言·设计模式
syt_biancheng4 小时前
Qt--命名,快捷键及坐标系
开发语言·qt
极地星光4 小时前
协程:深入协程机制与实现(进阶篇)
开发语言
进击的圆儿5 小时前
高并发内存池项目开发记录 - 02
开发语言·c++·实战·项目·内存池
xingxing_F5 小时前
Swift Publisher for Mac 版面设计和编辑工具
开发语言·macos·swift
你才是向阳花5 小时前
如何用python来做小游戏
开发语言·python·pygame
夜晚中的人海5 小时前
【C++】使用双指针算法习题
开发语言·c++·算法
怀旧,5 小时前
【Linux系统编程】3. Linux基本指令(下)
linux·开发语言·c++
艾莉丝努力练剑5 小时前
【C++STL :stack && queue (三) 】优先级队列的使用以及底层实现
linux·开发语言·数据结构·c++·stl