C语言练习大全(四):字符串与指针进阶
🎯 字符串处理和指针操作是 C 语言的核心难点。本篇通过实际练习,让你真正理解指针和字符串的配合使用。
目录
- 字符分类统计
- 字母频率统计
- 删除指定字符
- 提取数字和字母
- 字符串查找
- 字符串逆序(指针版)
- 字符串循环左移
- 字符串插入排序
- 单词首字母大写
- 字符串转整数(atoi实现)
- 求 e 的近似值
- 级数求和(PI的近似)
1. 字符分类统计
知识点:指针遍历 + 字符判断
统计字符串中字母、数字、空格、其他字符的个数。
#include<stdio.h>voidpin(char*a,int*le,int*dig,int*ta,int*out){for(;*a!='\0';a++){if(('A'<=*a&&*a<='Z')||('a'<=*a&&*a<='z'))(*le)++;elseif('0'<=*a&&*a<='9')(*dig)++;elseif(*a==' ')(*ta)++;else(*out)++;}}intmain(){chara[200]="aowduh wankdnia ska1i1e38/']CIOQONVBm1354&^%$@";intle=0,dig=0,ta=0,out=0;pin(a,&le,&dig,&ta,&out);printf("字母:%d, 数字:%d, 空格:%d, 其他:%d",le,dig,ta,out);return0;}新手要点:
- 指针遍历字符串:
for (; *a != '\0'; a++)— 逐个字符访问直到遇到结束符 - 传指针给函数可以在函数内部修改外部变量的值(传地址)
2. 字母频率统计
知识点:数组作为哈希表
统计字符串中每个小写字母出现的次数。
#include<stdio.h>voidfun(char*tt,intpp[]){inti;for(i=0;tt[i];i++){if(tt[i]>='a'&&tt[i]<='z'){pp[tt[i]-'a']++;// 核心技巧:字符转下标}}}intmain(){chartt[100]="awdhuwabcbjakjakwudhksbac hdgfqtywcdttyskzkkjeiq";intpp[26]={0};fun(tt,pp);chara='a';inti;for(i=0;i<26;i++){printf("%c: %d\n",a+i,pp[i]);}return0;}新手要点:
pp[tt[i] - 'a']是经典技巧:'a'-'a'=0,'b'-'a'=1,用字符值做数组下标- 这就是桶计数思想,时间复杂度 O(n)
3. 删除指定字符
知识点:双指针法
从字符串中删除所有'a'字符。
#include<stdio.h>intmain(){chara[100]="waodhuabciaaaadwa";puts(a);char*p,*q;p=a;q=a;for(;*p!='\0';p++){if(*p!='a'){*q=*p;q++;}}*q='\0';puts(a);return0;}新手要点:
- 双指针法:
p是读指针,q是写指针 p遍历所有字符,遇到不是'a'的就写到q的位置- 最后别忘了加
'\0'结束符
4. 提取数字和字母
知识点:字符判断 + 双指针
从混合字符串中提取数字和字母,去掉其他字符。
#include<stdio.h>#include<string.h>voidfunc(intlen,chars[]){inti,j;// 先提取前面的数字for(i=0,j=0;i<len;){if('1'<=s[i]&&s[i]<='9'){s[j++]=s[i++];}else{break;}}// 再提取后面的字母while(s[i]!='\0'){if(('A'<=s[i]&&s[i]<='Z')||('a'<=s[i]&&s[i]<='z')){s[j++]=s[i++];}else{i++;}}s[j]='\0';}intmain(){chars[]="1234ASDXFR12321aihdbbiioa12344dnn";intlen=strlen(s);func(len,s);puts(s);return0;}5. 字符串查找
知识点:字符串匹配
在主字符串中查找子字符串第一次出现的位置。
#include<stdio.h>#include<string.h>intmain(){charch[]="mdsdufhawbduiwmark,auhwuidac bimarkwian";charc[100],s[100];intlen,i,j,sign=-1;scanf("%s",s);len=strlen(s);for(i=0;ch[i]!='\0';i++){if(s[0]==ch[i]){for(j=0;j<len&&ch[i+j]!='\0';j++){c[j]=ch[i+j];}c[j]='\0';if(strcmp(c,s)==0){sign=-sign;break;}}}if(sign>0){printf("找到字符串: ");puts(c);printf("第一次出现的位置: %d",i);}else{printf("你要找的字符串不存在");}return0;}新手要点:
- 这是最朴素的字符串匹配算法(暴力法)
- 先找到首字符匹配的位置,再逐个比较后续字符
- 更高效的算法可以学习 KMP 算法
6. 字符串逆序
知识点:指针 + 首尾交换
用指针实现字符串逆序。
#include<stdio.h>#include<string.h>intmain(){charstr[]="qwerty";char*p,*q,temp;for(p=str+1,q=str+strlen(str)-2;p<q;p++,q--){printf("%c, %c\n",*p,*q);temp=*p;*p=*q;*q=temp;}printf("%s\n",str);return0;}新手要点:
str + 1跳过第一个字符,str + strlen(str) - 2跳过最后一个- 两个指针从两端向中间靠拢,逐对交换
7. 字符串循环左移
知识点:字符数组操作
把字符串前 m 个字符移到末尾。
#include<stdio.h>#include<string.h>voidfun(chars[],intm){intlen=strlen(s);inti,j;charn;for(i=0;i<m;i++){n=s[0];// 保存第一个字符for(j=1;j<len;j++){s[j-1]=s[j];// 所有字符前移一位}s[j-1]=n;// 把第一个放到最后}}intmain(){chars[9]="abcdefgh";intm;scanf("%d",&m);fun(s,m);puts(s);return0;}8. 字符串插入排序
知识点:字符串排序
对字符串中的字符进行插入排序(降序)。
#include<stdio.h>#include<string.h>voidfun(charch[]){intlen=strlen(ch);inti,j;charkey;for(i=1;i<len;i++){key=ch[i];j=i-1;while(j>=0&&ch[j]<key){ch[j+1]=ch[j];j--;}ch[j+1]=key;}}intmain(){charch[100];gets(ch);fun(ch);puts(ch);return0;}9. 单词首字母大写
知识点:状态机思想
把句子中每个单词的首字母转为大写,其余转为小写。
#include<stdio.h>intmain(){chark=' ';inti,j;chars[80]="i haVe attAChEd to thIs teTTer person InFORMAtion";for(i=1;s[i];i++){if(k==' '&&s[i-1]!=' '){// 前一个是空格,当前不是 → 单词开头if('a'<=s[i-1]&&s[i-1]<='z')s[i-1]=s[i-1]-32;// 转大写// 单词其余部分转小写for(j=i;s[j]!=' '&&s[j]!='\0';j++){if('A'<=s[j]&&s[j]<='Z')s[j]+=32;// 转小写}}k=s[i-1];}puts(s);return0;}新手要点:
- 大写转小写:
+ 32(ASCII 中 A=65, a=97,差 32) - 小写转大写:
- 32 - 通过前一个字符是否为空格来判断"单词边界"
10. 字符串转整数
知识点:手写atoi函数
把字符串 “123” 转换为整数 123。
#include<stdio.h>intpun(char*a){char*i;intsum=0,j;for(i=a;*i!='\0';i++){j=(*i-'0');// 字符转数字sum=sum*10+j;// 核心公式}returnsum;}intmain(){chara[100]="123";intsum1=pun(a);printf("%d\n",sum1);return0;}新手要点:
*i - '0'把字符'1'转为数字1sum = sum * 10 + j是逐位累加的核心公式- 例如 “123”:
0*10+1=1→1*10+2=12→12*10+3=123
11. 求 e 的近似值
知识点:级数求和
e = 1 + 1/1! + 1/2! + 1/3! + … 直到某项小于 1e-6
#include<stdio.h>intmain(){doublee=1;doubleitem=1;inti;for(i=1;1.0/item>1e-6;i++){item*=i;// 累乘求阶乘e+=1.0/item;// 累加倒数}printf("%f\n",e);return0;}新手要点:
- 自然常数 e ≈ 2.718282
- 每次循环算一个阶乘的倒数,累加到结果中
- 当新项足够小时停止——这就是精度控制
12. 级数求和(PI 的近似)
知识点:交替级数
PI/4 = 1 - 1/3 + 1/5 - 1/7 + …(莱布尼茨公式)
#include<stdio.h>#include<math.h>intmain(){inti;doublesum=0,item;intsign=1;for(i=1;fabs(item=1.0/(2*i-1))>1e-6;i++){sum+=item*sign;sign=-sign;// 正负交替}printf("PI ≈ %lf\n",4*sum);return0;}新手要点:
sign = -sign实现正负交替:1, -1, 1, -1…- 这个级数收敛很慢,需要很多项才能得到精确值
本篇总结
| 知识点 | 涉及题目 |
|---|---|
| 指针遍历字符串 | 字符分类统计、字母频率 |
| 双指针法 | 删除字符、提取数字字母 |
| 字符串操作 | 查找、逆序、循环左移、排序 |
| 字符转换 | 首字母大写、字符串转整数 |
| 级数求和 | e 的近似、PI 的近似 |
💡学习建议:指针是 C 语言的灵魂,也是最大的难点。多画内存图,多调试,不要怕——每个 C 语言程序员都是从"指针恐惧症"中走出来的。
下篇预告:《C语言练习大全(五):结构体与综合应用》— 结构体排序、文件操作、递归函数…