【C语言字符串与文件操作全攻略:从入门到记忆诀窍】
2026/5/24 10:59:37 网站建设 项目流程

文章目录

    • 一、字符串函数
      • 1. 长度不受限制的字符串函数
        • 1.1 strcpy – 字符串拷贝
        • 1.2 strcat – 字符串追加
        • 1.3 strcmp – 字符串比较
      • 2. 长度受限制的字符串函数(更安全)
        • 2.1 strncpy
      • 2.2 strncat
      • 2.3 strncmp
      • 3. strstr – 查找子串
      • 4. strtok – 字符串分割
      • 5. strlen – 字符串长度
    • 二、文件操作核心知识
      • 1. 标准流
      • 2. 文件指针 FILE
      • 3. 对比一组函数:scanf/fscanf/sscanf 与 printf/fprintf/sprintf
        • 输入方向(从…读入)
        • 输出方向(向…写入)
      • Linux 重定向的对应关系
    • 三、如何高效记忆这些函数?
      • 1. 字符串函数记忆法
        • ① 根据功能分类
        • ② 图解英文缩写
        • ③ 特别记忆易错点
      • 2. 格式化输入输出函数记忆法
      • 3. 文件操作记忆法
      • 总结

大家好,这里是小J,最近在深入学习Linux系统编程时,我发现自己的C语言字符串函数和文件操作知识有些生疏了。为此,我花时间系统地整理了一遍相关知识点,形成了这篇笔记。本文将结合我的学习心得和实战代码,详细讲解C语言中常用的字符串处理函数(包括长度不受限制与受限制的函数、strstr、strtok等)以及文件操作的核心概念(标准流、FILE指针、scanf/printf家族函数)。最后,我还会分享一套高效的记忆方法,帮助你彻底掌握这些内容。


一、字符串函数

C语言中的字符串函数主要定义在 <string.h> 头文件中。根据安全性(是否容易导致缓冲区溢出)可以分成两大类:长度不受限制 和 长度受限制。

1. 长度不受限制的字符串函数

这类函数在处理字符串时依赖 ‘\0’ 结束符,不指定操作的字符个数,容易造成数组越界,使用时要格外小心。

1.1 strcpy – 字符串拷贝
char*strcpy(char*dest,constchar*src);

·功能:将 src 指向的字符串(包括结束符 ‘\0’)复制到 dest 指向的空间。
·返回值:返回 dest。
·注意事项
· dest 必须有足够的空间容纳 src。
· src 和 dest 不能有重叠(标准未定义重叠行为)。
· 自己复制给自己时,由于 ‘\0’ 会被覆盖,导致无法终止,形成未定义行为。

模拟实现

char*my_strcpy(char*dest,constchar*src){char*ret=dest;while((*dest++=*src++)){;// 赋值操作本身即可判断结束}returnret;}
1.2 strcat – 字符串追加
char*strcat(char*dest,constchar*src);

·功能:将 src 附加到 dest 末尾(覆盖 dest 的 ‘\0’,并追加新的 ‘\0’)。
·返回值:返回 dest。
·注意事项
· dest 空间必须足够大。
· 不能自己追加自己,否则会死循环(因为追加过程中 ‘\0’ 被覆盖,永远找不到结束符)。

模拟实现

char*my_strcat(char*dest,constchar*src){char*ret=dest;while(*dest){// 找到 dest 的末尾dest++;}while((*dest++=*src++)){;}returnret;}
1.3 strcmp – 字符串比较
intstrcmp(constchar*s1,constchar*s2);

·功能:按字典序比较两个字符串。
·返回值
· 0:相等
· >0:s1 大于 s2
· <0:s1 小于 s2
·注意事项:比较的是字符的ASCII码,不是字符串长度。

模拟实现

intmy_strcmp(constchar*s1,constchar*s2){while(*s1&&*s2&&(*s1==*s2)){s1++;s2++;}return*s1-*s2;}

2. 长度受限制的字符串函数(更安全)

这类函数要求你显式指定最多操作的字符个数,可以有效防止缓冲区溢出,推荐优先使用。

2.1 strncpy
char*strncpy(char*dest,constchar*src,size_tn);

·功能:从 src 复制最多 n 个字符到 dest。
· 若 src 长度小于 n,则剩余部分用 ‘\0’ 填充。
· 若 src 长度大于等于 n,则不会自动追加 ‘\0’。
·返回值:返回 dest。

2.2 strncat

char*strncat(char*dest,constchar*src,size_tn);

·功能:从 src 追加最多 n 个字符到 dest 末尾,并总是添加 ‘\0’。
·返回值:返回 dest。

2.3 strncmp

intstrncmp(constchar*s1,constchar*s2,size_tn);

·功能:比较两个字符串的前 n 个字符。
·返回值:同 strcmp。


3. strstr – 查找子串

char*strstr(constchar*haystack,constchar*needle);

·功能:在字符串 haystack 中查找第一次出现子串 needle 的位置。
·返回值:若找到,返回指向该位置的指针;否则返回 NULL。若 needle 为空字符串,返回 haystack。

模拟实现

char*my_strstr(constchar*str1,constchar*str2){constchar*s1=NULL;constchar*s2=NULL;constchar*cur=str1;// 1. 处理特殊情况:如果子串是空字符串,直接返回原串if(*str2=='\0')return(char*)str1;// 2. 遍历主串中的每一个位置作为起点while(*cur){// 用 s1 和 s2 来匹配,不破坏 cur 和 str2 的原始位置s1=cur;// s1 从当前位置开始s2=str2;// s2 从子串开头开始// 3. 逐个字符比较while(*s1!='\0'&&*s2!='\0'&&*s1==*s2){s1++;s2++;}// 4. 判断是否匹配成功if(*s2=='\0')// 子串的所有字符都比较完了且都相等{return(char*)cur;// 返回匹配成功的位置}// 5. 匹配失败,cur 后移一位,重新开始cur++;}// 6. 遍历完整个主串都没找到,返回 NULLreturnNULL;}

图解执行过程
假设主串"ababc",子串"abc"

第1轮:cur 指向位置0 a b a b c ↑ (cur) a b c → a==a, b==b, 但 a!=c → 失败 ↑ (s1) ↑ (s2) 第2轮:cur 指向位置1 a b a b c ↑ (cur) a b c → b!=a → 失败 ↑ (s1) ↑ (s2) 第3轮:cur 指向位置2 a b a b c ↑ (cur) a b c → a==a, b==b, c==c → 成功! ↑ (s1) ↑ (s2) ↑ (s2移动) 返回位置2的指针

思路:用 cur 遍历主串,每到一个位置就尝试匹配子串。


4. strtok – 字符串分割

char*strtok(char*str,constchar*sep);

·功能:将字符串按分隔符集合 sep 拆分成多个标记(token)。
·使用规则

第一次调用时传入待分割的字符串 str,后续调用传入 NULL 以继续分割同一字符串。
· 函数内部会修改原字符串,将分隔符替换成 ‘\0’,因此原字符串会被破坏(通常先拷贝再操作)。
· 当找不到更多标记时返回 NULL。

·注意事项:不支持重入(多线程中使用需谨慎)。

示例:

chararr[]="Julian@yeah.net";chararr2[30]={0};strcpy(arr2,arr);// 先备份,因为 strtok 会修改原串constchar*sep="@.";char*ret=NULL;for(ret=strtok(arr,sep);ret!=NULL;ret=strtok(NULL,sep)){printf("%s\n",ret);}// 输出:// Julian// yeah// net

另一个例子包含多个连续分隔符:

chararr[]="Julian@yeah.net@hehe";// 同样用法,输出:// zpengwei// yeah// net// hehe

5. strlen – 字符串长度

size_tstrlen(constchar*s);

·功能:返回字符串 s 的长度(不包括 ‘\0’)。
·返回值:size_t 无符号整数类型。

模拟实现(三种经典写法):

// 计数器法size_tmy_strlen(constchar*s){size_tcount=0;while(*s++)count++;returncount;}// 指针相减法size_tmy_strlen2(constchar*s){constchar*p=s;while(*p)p++;returnp-s;}// 递归法(不推荐,仅展示)size_tmy_strlen3(constchar*s){if(*s=='\0')return0;return1+my_strlen3(s+1);}

二、文件操作核心知识

文件操作涉及到流、文件指针、以及一组格式化输入输出函数。

1. 标准流

C语言程序启动时会默认打开三个流,我们无需手动打开即可使用:

流名称含义默认关联设备常用函数
stdin标准输入流键盘scanf
stdout标准输出流显示器printf
stderr标准错误流显示器perror,fprintf(stderr, ...)

正是因为这些默认打开的流,我们才能直接使用 printf 和 scanf 进行输入输出。

2. 文件指针 FILE

缓冲文件系统中,每个被使用的文件都在内存中对应一个文件信息区,这个区域是一个结构体变量,类型名为 FILE(在 stdio.h 中定义)。

例如,VS2013 中的声明如下:

struct_iobuf{char*ptr;// 文件输入的下一个位置int_cnt;// 当前缓冲区的剩余字符数char*base;// 缓冲区基址int_flag;// 文件状态标志int_file;// 文件描述符int_charbuf;// 单字符缓冲int_bufsize;// 缓冲区大小char*tmpfname;// 临时文件名};typedefstruct_iobufFILE;

我们通常用 FILE* 指针来操作文件,例如:

FILE*fp=fopen("data.txt","r");if(fp==NULL){perror("fopen");return1;}// ... 读取或写入操作fclose(fp);

Linux 设计中“一切皆文件”的理念,使得FILE*不仅能操作普通文件,还能操作标准流:

FILE*fp=fopen("/proc/meminfo","r");// 读取内存信息FILE*fp=popen("ls -l","r");// 读取命令输出FILE*fp=fdopen(3,"r");// 将文件描述符转为 FILE*

3. 对比一组函数:scanf/fscanf/sscanf 与 printf/fprintf/sprintf

这一组函数功能相似,但作用的“目标”不同。

输入方向(从…读入)
函数作用对象说明
scanf标准输入stdin从键盘读取格式化数据。
fscanf任意文件流从指定的FILE*流中读取格式化数据。
sscanf字符串从字符串中提取格式化数据(相当于反向的sprintf)。

示例:

inta,b;sscanf("123 456","%d %d",&a,&b);// a=123, b=456
输出方向(向…写入)
函数作用对象说明
printf标准输出stdout向屏幕打印格式化字符串。
fprintf任意文件流向指定的FILE*流(如文件或stderr)写入格式化数据。
sprintf字符串将格式化数据输出到字符数组中(注意缓冲区溢出风险,建议用snprintf)。

示例:

charbuf[100];sprintf(buf,"答案 = %d",42);// buf 内容:"答案 = 42"

Linux 重定向的对应关系

C 代码Linux 命令行等价
printf("hello")echo "hello"
fprintf(fp, "hello")echo "hello" > file.txt
fprintf(stderr, "error")echo "error" >&2
scanf("%d", &n)read n

三、如何高效记忆这些函数?

C语言的字符串和文件函数数量较多,但大多遵循一定的命名规律。下面是我的记忆方法,希望能帮你告别死记硬背。

1. 字符串函数记忆法

① 根据功能分类
功能核心动词相关函数
复制cpystrcpy,strncpy
连接catstrcat,strncat
比较cmpstrcmp,strncmp
查找子串strstrstr
分割tokstrtok
求长度lenstrlen

其中 n 表示长度受限制,例如 strncpy 中的 n 就是最多复制的字符数。

② 图解英文缩写

· str → string
· cpy → copy
· cat → concatenate
· cmp → compare
· tok → tokenize
· len → length

理解了这些缩写,函数名就变得非常直观。

③ 特别记忆易错点

· strtok 会破坏原字符串 → 使用前建议先 strcpy 备份。
· strcat 不能自己连接自己 → 可改用 strncat 并指定长度。
· strncpy 不自动补 ‘\0’ → 需手动添加结束符。


2. 格式化输入输出函数记忆法

记住一个核心公式:前缀决定目标,后缀决定方向。

前缀含义方向示例
标准流输入/输出printf,scanf
f文件流(file)输入/输出fprintf,fscanf
s字符串(string)输入/输出sprintf,sscanf

sprintf 中的 s 是输出到字符串,sscanf 中的 s 是从字符串输入。一正一反,对称记忆。


3. 文件操作记忆法

· 打开文件:fopen — file open
· 关闭文件:fclose — file close
· 读文件:fgetc, fgets, fread
· 写文件:fputc, fputs, fwrite
· 格式化读写:fprintf, fscanf
· 文件指针定位:fseek, ftell, rewind

只要记住 f 前缀代表文件操作,后面跟动词即可。


总结

这次回炉整理让我对C语言的字符串和文件操作有了更深的理解。总结一下重点:

  1. 优先使用长度受限制的字符串函数(strncpy/strncat/strncmp),避免缓冲区溢出。
  2. strtok 很好用,但注意它会修改原字符串,而且不可重入。
  3. FILE 是核心抽象,标准流 stdin/stdout/stderr 让我们能立即使用 printf/scanf。
  4. printf 家族:无前缀→标准流,f→文件流,s→字符串。

希望这篇笔记加心得能帮助你快速回忆起这些重要的知识点。如果你也有自己的记忆妙招,欢迎在评论区交流!


附录:完整代码示例可以参考文中的 my_strstr、my_strcpy 等模拟实现,建议你自己动手敲一遍,加深理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询