本文写于 2016年11月29日,距今已超过 1 年,距 2020年03月26日 的最后一次修改也已超过 3 个月,部分内容可能已经过时,您可以按需阅读。如果图片无法显示或者下载链接失效,请给我反馈,谢谢!


0 0 投票数
评分

因为这次的作业仍是补充函数的定义,所以下面将只给出这一部分的代码。

Lab0901,EOJ3172。

将数字转换成字符串,我的第一反应就是sprintf()。

{ //TODO: your function definition -- RECURSIVE SOLUTION
 sprintf(s,"%I64d",n);
 return;
}

可惜竟然WA了,究其原因是要写 %I64d ,而不能只写 %d 。

当然,这道题在这里作为作业,应该是希望我们写成这个样子的:

{ //TODO: your function definition -- RECURSIVE SOLUTION
long long int tmp=n;
int cnt=0;
if (tmp==0) {
    cnt=1;
} else {
    while (tmp>0){
        cnt++;
        tmp/=10;
    }
}

tmp=n;
s[cnt]='\0';

for (int i=cnt-1;i>=0;i--){
    s[i]=tmp%10+'0';
    tmp/=10;
}

return;
}

这里的做法是,首先依次整除10计算位数,然后把每一位保留下来。

当然也可以倒序保存在数组里面,然后再想办法把顺序颠倒过来。

这里注意一个地方,也是我WA过一次的地方,那就是要单独考虑输入n=0这种情形。

也就是说,如果输入的数字是0,那么 while (tmp>0) 是不成立的,所以如果不对tmp==0做单独的考虑,就会导致问题。

除此而外,tmp需要是long long类型,并且s[i]=tmp%10以后还要加上’0’(即48)。

由于题目要求使用递归,所以12月1日在课堂上又写出了下面这段代码,代码与注释一起给出。

#include <stdio.h>
#include <string.h>

void getreverse(char s[],long long int n){
    //用来获得反过来的字符串
    if (n) {
        s[0]=n%10+'0';
        //如果n不是0,取出个位存入数组
        getreverse(&s[1],n/10);
        //递归的时候houn整除10
        //数组的话,用后面一个单元的地址,也就是s[1]的地址,即&s[1]
    } else {
        s[0]='\0';
        //做完以后,加上字符串结束符
    }
    return;
}

void i2a(char s[],long long int n){
    if (n) {
        getreverse(s,n);
        //如果n不是0,获取反过来的字符串
    } else {
        s[0]='0';
        getreverse(&s[1],0);
        //否则的话,单独处理0字符
    }
    int h=0,t=strlen(s)-1;
    //h表示head,t表示tail
    while (h<t){
        char c=s[h];
        s[h]=s[t];
        s[t]=c;
        h++;
        t--;
    }
    //颠倒
    return;
}


如果能用全局变量的话,递归的时候传的就是s和n/10就好了,下标用全局的i来控制。

于是就会有形如这样的语句。

s[cnt++]=n%10;
i2a(s,n/10);

如果不能用全局变量,也可以在i2a的参数表中增加一个参数,递归的时候传s和n/10和i+1即可。

于是就会有形如这样的语句。

void i2a(char s[],long long int n, long long int i);
i2a(s,n/10,i+1)

Lab0902,EOJ3173。

二分,一般来说是用循环的。但是题目要求写成递归形式,那么就把代码改一改,很顺利就写出来了。

{ //TODO: your function definition -- RECURSIVE SOLUTION
 if (L>R) {
    return -1;
 } else {
    int M=(L+R)/2;
    if (x>a[M]){
        binarySearch(a,M+1,R,x);
    } else if (x<a[M]){
        binarySearch(a,L,M-1,x);
    } else {
    return M;
    }
}

}

Lab0903,EOJ3017。

直接计算出结果,然后统计个数。

{ //TODO: your function definition
long long int sum=1;
for (int i=1;i<=n;i++){
    sum*=i;
}
int cnt=0;
while (!(sum%10)){
    cnt++;
    sum/=10;
}
return cnt;
}
for (int i=1;i<=n;i++){
    sum*=i;
}

这个for循环是在计算。

while (!(sum%10)){
    cnt++;
    sum/=10;
}

这个while循环是在统计个数。

事实上,因为题目的输入数据只到20,所以这题还可以写成这个样子:

{ //TODO: your function definition
return n/5;
}

至于原因,数学上可以证明,在20以内只要用n整除5(只要判断5的倍数)就可以了。

Lab0904,EOJ3105。

首先给出最中规中矩的做法。

{ //TODO: your function definition
    int pos = 0, max = 0, len = 0, tmp;

    for ( int i = 0; i <= strlen ( str ); i++ ) {
        if ( str[i] != ' ' && i < strlen ( str ) ) {
            if (  i == 0 || str[i - 1] == ' ') tmp = i;

            len++;

        } else {
            if ( max < len ) {
                max = len;
                pos = tmp;
            }

            len = 0;
        }
    }

    for ( int i = 0; i < max; i++ ) {
        result[i] = str[pos + i];
    }

    result[max] = '\0';

    return;
}

首先说明各个变量的含义。

pos记录最长单词的起始字母位置,max记录最长单词的长度,len记录当前单词的长度,tmp记录当前单词的起始字母位置。

需要注意的一点是,这里的变量是都要赋初值的,这里这个步骤不能省略。

如果没有赋初值,譬如没有对pos赋初值,因为局部变量没有缺省值,而由于if语句的存在,很有可能当函数结束的时候pos并没有被初始化过,于是导致错误。

主要的思路是,依次遍历整个字符串,记录下每个单词(以空格分隔)的长度,从中找出最长的单词,记下pos和max。

实现的时候,很多地方容易出错,下面一一说明。

for ( int i = 0; i <= strlen ( str ); i++ )

这里如果写成

for ( int i = 0; i < strlen ( str ); i++ )

就会导致最后一个单词没有被记录下,也就是,虽然比到了最后一个单词,但是没能把它的信息保存下来。

因此,等号要加上去。

可是,等号加上去的话就会导致死循环,那么下面的判断条件就要加上

&& i < strlen ( str )

这么做还有一个问题,那就是第一个值没有办法记录下来,这里的第一个值指的是第一个单词的第一个开头字母的位置(字符串的0号位)。

当然有一种可能的做法是在声明tmp的时候给它初始化为0,即写成int tmp=0。

我这里采用的方法是

 i == 0 ||

这句话不仅保证了当字符串处在开头的时候,就先让tmp=0,于是这里完成的事情与写成int tmp=0完成的事情是一样的。

而且,这句话还可以保证,如果i为0,那么就短路,短路以后就不会去做str[i – 1] ,也就是避免了出现str[-1]这样的局面出现。

后面的代码理解起来没有难度。

    for ( int i = 0; i < max; i++ ) {
        result[i] = str[pos + i];
    }

这是在获取结果。

最后要加上’\0’表示字符串结束,否则的话有可能会输出奇怪的字符(因为没有正常截断字符串)。

写完这个程序,再回过头来想一想,如果摆脱作业的要求,不写成函数的形式,我可以用另外一种输入和输出的方式,让程序变得更简单。

#include <stdio.h>
#include <string.h>
#define N 80
int main()
{   char st[N+1][N+1];
    int cnt=0,max=0,len=0,pos=0;
    while (scanf("%s",st[cnt++])!=EOF);
    max=strlen(st[0]);
    for (int i=0;i<cnt-1;i++){
        len=strlen(st[i]);
        if (max<len) {pos=i;max=len;}
    }

    printf("%s\n",st[pos]);
    return 0;
}

由于本题输入的内容已经纯天然地被用空格分隔了,所以我利用一个循环体为空的while循环读入所有的字符串,保存在一个二维char数组里(或者可以认为保存在一个一维的string数组里,只不过这里的每个string就是一个一维的char[]数组)。

全部读入以后,依次遍历每一个数组,很顺利得到答案。

0 0 投票数
评分
2条留言
订阅评论
提醒
guest

在点击发表评论按钮时,网络请求的数据包含浏览器版本、操作系统版本和 IP 地址;您的网络服务提供商、雇主或学校、政府机构可能会看到您的访问活动;根据浏览器默认行为、操作系统设置和安全防护软件的设置不同,您的浏览器可能会也可能不会在本地 Cookies 缓存您输入的用户名、邮箱以便下次评论使用。

请对自己的言行负责。

您想以什么身份发表评论
邮箱将在您的评论被回复时给您通知
(可选)如果您也有个人网站,不妨分享一下
我对这篇文章的评分
这篇文章给您带来多大帮助
2 评论
内联反馈
查看所有评论
闫 壮
闫 壮(@zerozone)
2016年12月1日 23:38

请问防止全局变量风险的方法是每次调用时初始化吗?