#Cprove 28~31 字符数组与字符串处理

  • no.1 字符统计
  • no.2 删除指定字符
  • no.3 情书解密
  • no.4 字符串处理函数
  • no.5 编程处理C++源代码

NO.1 字符统计

编写一函数,由实参传来一个字符串,统计此字符串中字母、数字、空格和其它字符的个数,在主函数中输入字符串以及输出上述的结果。

代码
#include<stdio.h>
#include<string.h>
#include<ctype.h>
/** 字符统计函数fltj(char str[], int a[])
 *统计str[]中字母、数字、空格及其他字符数目并将结果放入数组a[]
 * 输入:str[],a[];
 * 输出:a[]
 */
void fltj(char str[], int a[])
{
    int ll,i;
    ll=strlen(str); //ll赋值为字符串长度(真实长度,不含'\0')
    for (i=0; i<ll; i++)
    {
        if (isalpha(str[i])) a[0]++;         //统计字母个数
        else if (isdigit(str[i])) a[1]++;   //统计数字个数
        else if (isspace(str[i])) a[2]++;   //统计空格数
        else a[3]++;
    }
}
int main()
{
    static char str[60];
    static int a[4]= {0,0,0,0};
    gets(str);
    fltj(str,a);
    printf("%s char:%d digit:%d space:%d other:%d",str,a[0],a[1],a[2],a[3]);
    return 0;
}
执行结果

在这里插入图片描述

NO.2 删除指定字符

有一行文字,要求删去某一个字符。此行文字和要删去的字符均由键盘输入,要删去的字符以字符形式输入(如输入a表示要删去所有的 a字符)。

代码
#include<stdio.h>
int main()
{
    /*str1表示原来的一行文字,str2表示删除指定字符后的文字*/
    char str1[100],str2[100];
    char ch;
    int i=0,k=0;
    printf("please input an sentence:\n");
    gets(str1);
    scanf("%c",&ch);
    for (i=0; str1[i]!='\0'; i++)
        if (str1[i]!=ch)
        {
            str2[k]=str1[i];
            k++;
        }
    str2[k]='\0';
    printf("\n%s\n",str2);
    return 0;
}
执行结果

在这里插入图片描述

NO.3 情书解密

背景:小明让同学传纸条给小丽。小丽接到会心一笑,大家却不知所云。纸条上写着M p s z i pszi psziy,两人暗中约定是,真实字符为实际字符前面的第4个!M p s z i pszi psziy是神马意思?推算一下,或从ASCII码表中查一下,自然是I love u。
(1)小明请你写一个程序,在给小丽写情书时,再不用费功夫自己“翻译”,原信中每一个字符加密为其后的第4个字符。例,输入I love u,输出M p s z i pszi psziy。
(2)小丽请你写一个程序,在看小明的情书时,让程序帮着“解密”。因为有同学知道了他们俩人的“加密”手段,决定纸条由人传,加密数字(1-9)用两人约好的手势传,所以解密时,需要将加密数字作为程序输入。例,输入M p s z i pszi psziy(回车)4,输出I love u
(3)小刚常帮着传纸条,想知道俩人的秘密,但不知道加密数字,于是写了一个程序,可以列出所有可能的情况。例,输入M p s z i pszi psziy,多行输出中必然有一行是I love u。你就是小刚,写出这个程序来吧。

代码一
#include<stdio.h>
#include<string.h>
#define SIZE 20
int main()
{
    char ming[SIZE];
    int i;
    printf("XiaoMing means:\n");
    gets(ming);
    for(i=0;ming[i]!='\0';i++)
        ming[i]+=4;
    printf("XiaoMing says:\n");
    puts(ming);
    return 0;
}
执行结果

在这里插入图片描述

代码二
#include<stdio.h>
#include<string.h>
#define SIZE 20
int main()
{
    char li[SIZE];
    int i,n;
    printf("XiaoLi receives:\n");
    gets(li);
    printf("Input encrypted number:\n");
    scanf("%d",&n);
    for(i=0;li[i]!='\0';i++)
        li[i]-=n;
    printf("XiaoLi gets:\n");
    puts(li);
    return 0;
}
执行结果

在这里插入图片描述

代码三
#include<stdio.h>
#include<string.h>
#define SIZE 20
int main()
{
    char li[SIZE],putli[SIZE];	//也可以用putli[SIZE]={'\0'}初始化
    int i,n;
    memset(putli,'\0',SIZE);	//初始化putli[]字符数组
    printf("XiaoLi receives:\n");
    gets(li);
    do
    {
        printf("Input encrypted number:\n");
        //fflush(stdin);
        scanf("%d",&n);
        for(i=0; li[i]!='\0'; i++)
            putli[i]=li[i]-n;
        putli[i]='\0';
        printf("XiaoLi gets:\n");
        puts(putli);
    }
    while(n!=0);

    return 0;
}
执行结果

在这里插入图片描述

小结

如果内循环结束没有putli[i]='\0';,那么后面会跟着一堆乱码,从而影响结果。

NO.4 字符串处理函数

请编制函数,对字符串的进行各种操作。

功能用数组名作形参用指针作形参
1字符串str1和str2连接,连接后的结果存放到str1中char *astrcat(char str1[], char str2[])char *pstrcat(char *str1, char *str2)
2去除字符串str中的特定字符c(如空格),结果仍保存到原字符串中char *adelchar(char str[], char c)char *pdelchar(char *str, char c)
3求字符串str的长度并返回int astrlen(char str[])
4统计句子str中单词的个数不再重重复,做右边的(下同)int pwordnum(char *str)
5去除句子中第一个单词前的空格,返回去除了空格的字符串char *ptrim(char *str)
6去除句子中所有多余的空格,返回去除了空格的字符串char *palltrim(char *str)
7比较两个字符串,返回值同strcmp()int pstrcmp(const char *str1, const char *str2)
代码一:编制字符串连接函数
/**< 编制字符串连接函数 */
#include <stdio.h>
#include<string.h>
char *astrcat(char *str1, char *str2);
int main()
{
    char s1[50],s2[25];     //不可直接赋值s1[50]="……",否则还要添加指针变量进行操作,因为此时s1[50]被当做常量了
    strcpy(s1,"I am handsome!");
    strcpy(s2,"She is so delicious!");
    puts(s1);
    puts(s2);
    astrcat(s1,s2); //不可写成s1=astrcat(s1,s2),因为s1是字符数组不是指针变量,不能直接赋值,但可以写成下面这样
    /**<
    char *p1,*p2;
    p1=s1;
    p2=s2;
    p1=astrcat(p1,p2);
    */
    puts(s1);
    return 0;
}

/** char *astrcat(char str1[], char str2[])
 *字符串str1和str2连接,连接后的结果存放到str1中
 * input:str1[],str2[]
 * 
 * return:str1[]
 */
char *astrcat(char *str1, char *str2)
{
    int i=0,j=0;
    while(*(str1+i)!='\0')
        i++;
    while(*(str2+j)!='\0')
    {
        *(str1+i)=*(str2+j);
        j++;
        i++;
    }
    *(str1+i)='\0';
    return str1;
}
执行一

在这里插入图片描述

代码二:字符串中删除指定字符的函数(参见NO.2)
代码三:求字符串str的长度并返回
/**< 编制求字符串str的长度函数 */
#include <stdio.h>
#include<string.h>
int pstrlen(char *str);
int main()
{
    char s[]="The sun shines.";
    puts(s);
    printf("长度为 %d\n",pstrlen(s));
    return 0;
}

/** int pstrlen(char *str)
 *求字符串str的长度并返回
 * input:char *str
 * return:int n
 */
int pstrlen(char *str)
{
    int n=0;
    while(str[n]!='\0')
        n++;
    return n;
}
代码四:统计句子str中单词的个数
/**< 编制统计句子str中单词个数的函数 */
#include <stdio.h>
#include<string.h>
int pwordnum(char *str);
int main()
{
    char s[]="The sun shines.";
    int n;
    n=pwordnum(s);
    puts(s);
    printf("\n单词数:%d",n);
    return 0;
}

/** int pstrlen(char *str)
 *统计句子str中单词的个数
 * input:char *str
 * return:int 
 */
int pwordnum(char *str)
{
    int n=0,i=0,word=0; //word作为是否遇到过空格的标志,遇到置0否则为1
    while(str[i]!='\0')
    {
        if(str[i]==' ')
            word=0;
        else if(word==0)
        {
            n++;
            word=1;
        }
        i++;
    }
    return n;
}
代码五:去除句子中第一个单词前的空格,返回去除了空格的字符串
#include <stdio.h>
#include<string.h>
char *ptrim(char *str);
int main()
{
    char s[]="       The sun shines.";
    puts(s);
    puts(ptrim(s));
    return 0;
}

/** char *ptrim(char *str)
 *去除句子中第一个单词前的空格,返回去除了空格的字符串
 * input:char *str
 * return:char *str
 */
char *ptrim(char *str)
{
    int i=0,j=0;
    while(str[i]==' ')
        i++;
    while(str[i]!='\0')
    {
        str[j++]=str[i];
        i++;
    }
    str[j]='\0';
    return str;
}

在这里插入图片描述

代码六:去除句子中所有多余的空格,返回去除了空格的字符串
#include <stdio.h>
#include<string.h>
char *palltrim(char *str);
int main()
{
    char s[]="       The sun shines.";
    puts(s);
    puts(palltrim(s));
    return 0;
}

/** char *palltrim(char *str)
 *去除句子中所有多余的空格,返回去除了空格的字符串
 * input:char *str
 * return:char *str
 */
char *palltrim(char *str)
{
    int i=0,j=0;
    while(str[i]!='\0')
    {
        if(str[i]!=' ')
        str[j++]=str[i];
        i++;
    }
    str[j]='\0';
    return str;
}

在这里插入图片描述

代码七:比较两个字符串,返回值同strcmp()
#include <stdio.h>
#include<string.h>
int pstrcmp(const char *str1, const char *str2);
int main()
{
    char s1[]="The sun shines",s2[]="The sun rises";
    puts(s1);
    puts(s2);
    printf("\n比较结果:%d",pstrcmp(s1,s2));
    return 0;
}

/** int pstrcmp(const char *str1, const char *str2)
 *比较两个字符串,返回值同strcmp()
 * input:const char *str1, const char *str2
 * return:int
 */
int pstrcmp(const char *str1, const char *str2)
{
    int i=0,flag=0; //默认两个字符串相等
    while(str1[i]==str2[i]&&(str1[i]!='\0'&&str2[i]!='\0'))
        i++;
    if(str1[i]>str2[i])
        flag=1;
    else if(str1[i]<str2[i])
        flag=-1;
    //if(str1[i]=='\0'&&str2[i]=='\0')
    //    flag=0;
    return flag;
}

在这里插入图片描述

NO.5 编程处理C++源代码

(1)读入一个C程序,判断其中是否只有一个main()函数,输出“暂时没有发现问题”,或者“没有main()函数”,或者“不能定义多个main()函数”;
提示1:简单处理,可以只比较判断“main()”,考虑实际上的各种可能,main后面的括号中还有其他多种写法。建议按最简单的情形处理。
提示2:建议设计一个函数,将读到的代码与字符串“main()”进行比较。函数用于判断s1是否“包含”在读入的一行s2中,调用时,形参s1处的实参用“main()”即可,这样写提升了“抽象”级别,更容易实现,对应更高的代码质量。

代码一
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int appear(const char *s1, const char *s2);
int main()
{
    int i;
    char str1[200],str2[]="main()";
    FILE *fp;
    fp=fopen("test.c","r"); //只读方式打开
    if(fp==NULL)
    {
        printf("Can not open file!");
        exit(1);    //exit函数包含在stdlib.h中,exit(1)表示异常退出
    }
    //下面此读取为全部读取,计算量稍大于后一种
    i=0;
    while(!feof(fp))
    {
        fscanf(fp,"%c",&str1[i]);
        i++;
    }
    str1[i]='\0';	//可不要,因为文件结束字符即为'\0'
/**< 循环读取还可用fgets函数
    while(!feof(fp))
    {
        fgets(str1,200,fp);     //读取一行,当读取 (n-1) 个字符,或者读取到换行符,或者到达文件末尾时,它会停止,具体视情况而定。
        num+=appear(str1,str2);
        if(num>1)               //如果str2字符串出现超过1次,停止循环不必再读取
            break;
    }
*/
    fclose(fp);
    printf("文件test.c共 %d 个\"main()\"字符串\n",appear(str1,str2));
    return 0;
}

//定义出现次数appear()函数
int appear(const char *s1, const char *s2)
{
    int i=0,k=0,flag=0,count=0;
    while(s1[i]!='\0')
    {
        if(s1[i]==s2[0])    //首字母m对上
        {
            for(k=1;k<6;k++)    //看后面5个字符ain()
            {
                if(s1[i+k]!=s2[k])  //有一个对不上标志位置0,否则标志位置1
                {
                    flag=0;
                    break;
                }
                else
                    flag=1;
            }
            if(flag==1) //跟s2全部对上了计数加一
                count++;
        }
        if(count>1)
            break;
        i++;
    }
    return count;
}

在这里插入图片描述

小结1

巧用状态变量flag,与字符串不相等的时候少些计算,省得先循环求出一段字符串再来和已知字符串比较。

(2)编写一个程序并取名test.c,统计该文件中出现"if",“while”,"for"的次数。

代码二
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int appear(const char *s1, const char *s2);
int main()
{
    int num[3]={0};
    char str1[200],str2[]="if",str3[]="while",str4[]="for";
    FILE *fp;
    fp=fopen("test.c","r"); //只读方式打开
    if(fp==NULL)
    {
        printf("Can not open file!");
        exit(1);    //exit函数包含在stdlib.h中,exit(1)表示异常退出
    }
/**< 循环读取用fgets函数 */
    while(!feof(fp))
    {
        fgets(str1,200,fp);     //读取一行,当读取 (n-1) 个字符,或者读取到换行符,或者到达文件末尾时,它会停止,具体视情况而定。
        num[0]+=appear(str1,str2);  //num[0]存放“if”出现次数
        num[1]+=appear(str1,str3);  //num[1]————“while”次数
        num[2]+=appear(str1,str4);  //num[2]————“for”次数
    }
    fclose(fp);

    printf("文件test.c共 %d 个\"if\"字符\n",num[0]);
    printf("文件test.c共 %d 个\"while\"字符\n",num[1]);
    printf("文件test.c共 %d 个\"for\"字符\n",num[2]);
    return 0;
}

//定义出现次数appear()函数
int appear(const char *s1, const char *s2)
{
    int i=0,k=0,flag=0,count=0;
    while(s1[i]!='\0')
    {
        if(s1[i]==s2[0])    //首字母m对上
        {
            for(k=0;s2[k]!='\0';k++)
            {
                if(s1[i+k]!=s2[k])  //有一个字符对不上,标志位置0,否则标志位置1
                {
                    flag=0;
                    break;
                }
                else
                    flag=1;
            }
            if(flag==1) //跟s2全部对上了计数加一
                count++;
        }
        if(count>1)
            break;
        i++;
    }
    return count;
}

(3)读入一个C程序,使程序中的所有左花括号“{”和右花括号“}”都单独占一行,新程序保存到另一个.c文件中,并在屏幕上显示处理过的程序,显示时加上行号。

代码三
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void formatpgm(char* ,char* );
void showpgm(char*);
int main()
{
    formatpgm("source.c","target.c");
    printf("花括号占单行处理后的程序:\n");
    showpgm("target.c");
    return 0;
}
//花括号占单行处理函数
void formatpgm(char *sourcefile,char *targetfile)
{
    char ch1,ch2;
    FILE *fp1=fopen(sourcefile,"r");
    if(fp1==NULL)
    {
        printf("Source file read error!\n");
        exit(1);
    }
    FILE *fp2=fopen(targetfile,"w");
    if(fp2==NULL)
    {
        printf("Target file write error!\n");
        exit(1);
    }
    ch1='\0';
    while(!feof(fp1))
    {
        ch2=fgetc(fp1);
        if((ch2=='{'||ch2=='}')&&ch1!='\n')   //当前读的是花括号且前一个字符不是换行,“···{”
            fputc('\n',fp2);
        else if((ch1=='{'||ch1=='}')&&ch2!='\n')  //前一个读到花括号且当前读的不是换行,“{···”
            fputc('\n',fp2);
        fputc(ch2,fp2);
        ch1=ch2;
    }
    fclose(fp2);
    fclose(fp1);
}
void showpgm(char *s)
{
    int i=1;
    char str[256];
    FILE *fp=fopen(s,"r");
    if(fp==NULL)
    {
        printf("Source file read error!\n");
        exit(1);
    }
    while(!feof(fp))
    {
        fgets(str,256,fp);
        printf("%d\t%s",i,str);
        i++;
    }
}
小结3

格式处理函数中循环读取字符时,ch1类似于一个状态变量用法,有3种状态:换行符,花括号,其他字符。用来配合ch2

(4)读入一个C程序,输入m、n两个数字,从第m行起的n行代码将作为注释使用(即在这些行前面加上”//”),新程序保存到另一个.c文件中。

代码四
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void notepgm(char* ,char* ,int ,int);

int main()
{
    int m,n;
    printf("输入要注释的行:\n");
    scanf("%d %d",&m,&n);               //注释掉m到n行
    notepgm("source.c","target.c",m,n);
    return 0;
}
//注释掉m到n行的函数
void notepgm(char *sourcefile,char *targetfile, int m, int n)
{
    int i=1;
    char ch2[256];
    FILE *fp1=fopen(sourcefile,"r");
    if(fp1==NULL)
    {
        printf("Source file read error!\n");
        exit(1);
    }
    FILE *fp2=fopen(targetfile,"w");
    if(fp2==NULL)
    {
        printf("Target file write error!\n");
        exit(1);
    }

    while(!feof(fp1))
    {
        fgets(ch2,256,fp1);
        if(i>=m&&i<=n)
            fputs("//",fp2);
        fputs(ch2,fp2);
        i++;
    }
    fclose(fp2);
    fclose(fp1);
}

(5)(拓展)读入一个C++程序,整理其格式,使其按规范排版,包括:①所有左花括号“{”和右花括号“}”都单独占一行;②每个语句单独占一行;③各行采用统一的缩格排放(每遇一个“{”,其下一行的程序,在第一个有意义的符号前的空格数增加4,每遇一个“}”,其下一行的程序,在第一个有意义的符号前的空格数减少4。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值