字符串刷题整理-华为机试HJ90,1,4

1.字符串中关键字符切割

  • 获得最后一个单词长度
  • 获得切割后的字符串组数

2.字符串按长度切割

代码:
一.输入
1.scanf无法输入空格
2.含空格的多行输入如何实现?

1.gets函数:输入该字符串时,不包括最后的\n。
2.循环输入while(gets(str))

二.寻找关键字符并切割
最复杂的情况也就是切割成不同的字符串,存放入字符串数组。
首先实现切割功能,C语言无split函数,这里借用strtok函数实现split函数功能。
strtok()函数介绍:
首先这是C 标准库 - <string.h>的函数,声明为char *strtok(char *str, const char *delim),意即调用这个函数时需要传入①待切割字符串的地址,②切割符的地址。第一次调用时需传入待切割字符串的地址,切割符的地址,此时函数中保存切割符第一次出现的地址,返回字符串首地址。第二次起调用时需将字符串地址设置为NULL,切割符不变。此起函数返回上一次保存的切割符(的下一个字符的)地址,而保存寻找到的下一个地址。一旦函数搜索完所有字符而没找到切割符,返回NULL。
调用实例如下:

int main() 
{
        char s[length]={0}; 
        gets(s);
       /*  //用指针标记分割符串
        char *delim=" ";
        char *q;
        q=strtok(s, delim);
        printf("%s ", strtok(s, delim)); 
        printf("%s ", q); */
        char key[2]=" ";
        char *q=strtok(s,key);
        printf("%s",q);
    return 0;
}

strtok的使用注意两个点:①该函数未切割字符,且将原字符串做了修改(切割字符串处替换为‘\0’)②传入的切割符是作为字符串的形式,即使只是按照一个字符如‘@’切割,但字符串“”中存放的是两个字符。
显示所有切割后的字符串的代码如下:
在这里插入图片描述
三.将切割后的字符串输入数组存放
定义一个返回整型的函数
int split(char * str,char * * sub)
/ 传入参数为待分割字符串,以及一个二级指针。这里的二级指针如何理解呢?首先,二级指针意味着,指针sub指向的变量依然为指针,而这一层指针再指向的,就是我们需要的分隔符的地址了,也就是sub这个指针变量(变量名为sub)指向两次之后的类型为char,故表示为char* * sub。(* sub的类型为地址,由于不知道地址有没有类似于“char”这样的表达,所以中间就没表示。但是当你看到这里,可能会发现,用来表示这个变量指向的是地址的类似“char”的类型名,不就是char吗。所以还可以将sub看成一个整体,其类型是,指向字符型变量的指针char*,合起来就是char * * sub)。
以上是对这个二级指针作为指针的理解,那么怎么从数组的角度理解这个二级指针呢。在我之前发的一篇讲多级指针的文章中其实已经提到了指针和数组的关系。对于一个一维数组int a[3],a为数组名,也是这个数组的首地址,还是这个数组第一个元素的首地址。那么推广到二维数组,int a[3][4],可将其概念上理解为4个5维数组,分别是int a[0],int a[1],int a[2],int a[3],而对应的a[0],既是一个一维数组的数组名,也是这个一维数组对应的地址,也就是说a[0],a[1],a[2],a[3]这个数组中存放的都是地址,那么哪个数组用来存放这几个数组呢,就是a。此时这里的a和前面二级指针* * sub的作用一样:指向这个数组时,对应的是(指向4个元素的)地址,(可以理解为*sub),这个地址再指一次就是我们要的字符,也就是char * * sub。所以当我们定义了二级指针,并且想往这里存放地址时,我们可以将二级指针的变量名,此处也就是sub,视为二维数组的数组名,将得到的地址char *p=strtok(s,key)传入这个二维数组的每一行。
也就是说,我可以直接sub[i]=p,循环输入。
这里涉及到第三个问题,如何表示二维数组 的行与列?这个问题答主改日再答,今天光是以上知识我脑袋已经爆炸了哈哈哈。
那么,接下来从代码的角度实现split的功能:
int split(char *str,char**sub)
{
char key[2]=" ";
char *p=strtok(str,key);
int num=0;
int i=0;
while( p )
{
num++;
sub[i]=p;
i++
}
return ++num;
}
调用split函数后,分割后的字符串会存放在输入的二维数组中。

四.如何定义并传入这个二维数组?
首先,我们这里的二维数组存放的是分隔符,而概念上每行的首元素存放的都是地址。也就是说,将二维数组视作一维数组时,此时是一个存放地址的一维数组,也就是指针数组。那么指针数组如何定义呢? 首先这个是一个指向字符的数组,其类型是char * [],每个元素存放的地址,字节不超过8个,故其类型补充为char * [10],设此时函数名为a,即定义一个指针数组char *a[10]。其第一个元素如何表示呢?首先这还是个数组,所以a是其数组名,则其元素类比普通一维数组为:a[0],a[1]……类似刚刚在定义形参时定义的二维数组的数组名。说到这里,只是想告诉大家,指针数组的数组名可作为地址以二维数组的形式被传入到函数中,且指针数组的数组名效果等同于二维数组的数组名效果。
故在调用前面定义的split函数前,先定义一个指针数组 char *sub[10]。(至于为什么设为10,我没有完全摸清楚,有清楚的大佬希望指教一下,嘿嘿)

五.如何调用被存放起来的字符串?
上面的指针数组中存放的是分隔符的地址,分别表现为sub[0],sub[1]……,也就是说,我们有分割后字符串的首地址(的前一位),那么有地址需要对其值操作自然而然想到的是……?对是形参调用。这里,由于在题目中可能需要对字符串的如“长度、数值、格式”等进行判断,故我们可以放在一个函数里,一起判断。那么这个函数需要传入的参数就是分割后的字符串的地址(可以在调用该函数时通过循环对每个字符串实现一次判断),输出就是0/1来表示是否符合条件。
那么,定义一个函数 int is_OK(),这里如果形参设为char *sub[i],那么传入的就是指针数组的地址,而数组中每一个元素的值都是地址,需要再次用变量定义表达为最后的字符串。而我们需要的是sub[i]的值,所以在传入时,传入我们需要的字符串的地址,也就是sub[i],在函数中,对这个地址指向的字符串进行操作。由于指向的是字符串,故这里有个比较高阶的用法,直接在定义函数时将这个要传进来的地址对应的字符串设为字符串IP[10]。
也就是定义函数 int is_OK(char IP[10])。顺向理解,传入的地址是字符串的首地址,那么直接读取这个字符串也就不足为奇。

六.对每个字符串进行判断/操作(is_OK函数的功能代码实现)
要求如下:
①每个字符为数字
②不能出现第一个字符为0而第二个字符为数字(或者说若第一个字符为0,则后面紧跟的必须为’\0‘)
③字符串转换为十进制后为0~255之间的数

int is_OK(char IP[10])
{
    int i=0;
    int len=strlen(IP);
    for(i=0;i<len;i++)
    {
        if(IP[i]>'9'||IP[i]<'0')
        {
            return 0;
        }
    }
    i=0;
    if(IP[i]=='0'&&IP[i+1]!='\0')  
    {
        return 0;
    }
    int a =atoi(IP);
    if(a<0||a>255)
    {
        return 0;
    }
    return 1;
}

注,这里return用法,读到return直接跳出,类似于定义一个中间变量ret=1,一旦符合条件就为0,否则为1,并返回这个整型变量。

2.字符串按长度切割
一.如何实现按长度分割?
我的做法是每隔一个长度单位将其地址放入指针数组char sub[10]
二.最后长度不够,如何测出长度?如何补足?
字符串初始化为0,(字符串中0=‘\0’),以最后一个起始地址开始检索,若为0,改为(题目需要,如改为‘0’输出,循环次数为长度。
代码实现:
定位到某一个字符的表达式为: * (sub[i]+m) 或者用存放地址的指针p表示为
(p+i)

for(i=0;i<8;i++)
        {
            if(*(p+i)=='\0')
            {
                *(p+i)='0';
            }
        }

以下为输出,输出时按另一种方式输出了。

for(i=0;i<num;i++)
        {
            int m=0;
            while(m<8)
            {
                printf("%c",*(sub[i]+m));
                m++;
            }
            //printf("%8s\n",sub[i]);
            printf("\n");
        }

为保质量,先写这么多,感谢观看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值