为什么输出末尾有随机字符?

时间:2019-10-08 03:41:25

标签: c

我正在尝试解决toph.co平台中的问题。我已经编写了代码。它无法正常运行。在某些情况下给我正确的输出。但是,当我尝试使用'o'的情况时,它正在进入一个循环。也许问题就在那里。但我无法找到答案。

问题链接:https://toph.co/p/better-passwords

请帮助我解决代码中的问题。我正在使用c编程语言。由于我是编程新手,所以我没有弄错地方。

我已经尝试了很多方法。一次又一次地修改代码。现在我发疯了。

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

int main()
{
    char s[40], i, j;
    int len;
    gets(s);
    len= strlen(s);
    for(i=0; i<=len; i++)
    {
        if(s[i] == 's')
        {
            s[i]= '$';
        }
        else if(s[i] == 'i')
        {
            s[i]= '!';
        }
        else if(s[i] == 'o')
        {
            s[i]= '(';
            for(j=len; j>i; j--)
            {
                s[j]=s[j-1];
                len= strlen(s);
            }
            s[i+1]=')';
        }
        else
        {
            continue;
        }
        len= strlen(s);
    }
    if (s[0]>='a' && s[0]<='z')
    {
        s[0]= s[0]- 32;
    }
    int new_len=strlen(s);
    s[new_len]='.';
    puts(s);
    return 0;
}

我希望输出Un $()ph!$ t!cated。 ,但显示的是Un $()ph!$ t!cated .....“很多不需要的字符” .....

3 个答案:

答案 0 :(得分:1)

您的字符串空字节在操作后会丢失,这是避免此类问题的最简单方法-将整个字符数组初始化为零字节:

char s[40] = {0}, // was char s[40], uninitialized !

您还注意到编译消息“ 警告:'gets'函数很危险,不应使用”吗?

gets()很危险,因为它没有受到缓冲区溢出的保护-尝试以超过缓冲区s容量的超长字符串运行程序,您将会崩溃:

  

*检测到堆栈崩溃* :已终止中止(核心已转储)

使用fgets()代替gets(),就像这样:

fgets(s, 39, stdin);
if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; // deleting newline character

请注意,我们在此处读取BUFFER_SIZE - 1个字符,即-比缓冲区可以容纳的字符数少40个字符(因为减少了1个字符),因为如果我们输入的是完整缓冲区大小的长字符串,则您的代码扩展字符串将再次粉碎堆栈。您需要认真对待缓冲区溢出。

答案 1 :(得分:0)

正如大多数评论员所说:您不要在扩展字符串的后面放置字符串结尾字符'\ 0'。 C中的字符串在末尾用这个额外的字符标记。需要找到字符串的结尾。

示例:字符串“ abc”实际上是由4个字符组成的序列,即“ a”,“ b”,“ c”和“ \ 0”。其长度为3,其s[3]包含'\ 0'。

您的循环:

        for(j=len; j>i; j--)
        {
            s[j]=s[j-1];
            len= strlen(s);
        }

在循环的第一轮中,s[len]处的字符被s[len-1]处的字符替换。这样会用字符串的最后一个(可见)字符覆盖原始的'\ 0'。

如果将循环更改为:

        for (j = len; j > i; j--)
        {
            s[j + 1] = s[j];
        }

“ \ 0”将在第一次运行时被复制。

注意1:将分配移到循环后面的len

注2:确保变量s对于所有输入都足够大。

注3:看到我使用的空白吗?采用良好的代码风格并坚持下去。

答案 2 :(得分:0)

您的代码中有几个地方要覆盖“ \ 0”。 这些是:

s[j]=s[j-1];

s[new_len]='.';

因此纠正后的代码将是...。

int main()
{
    char s[40], i, j;
    int len;
    gets(s);
    len= strlen(s);
    for(i=0; i<=len; i++)
    {
        if(s[i] == 's')
        {
        s[i]= '$';
        }
        else if(s[i] == 'i')
        {
            s[i]= '!';
        }
        else if(s[i] == 'o')
        {
            s[i]= '(';
            for(j=len+1; j>i; j--) //j needs to be one more than the length
            {
                s[j]=s[j-1];
                len= strlen(s);
            }
            s[i+1]=')';
        }
        else
        {
            continue;
        }
        len= strlen(s);
    }
    if (s[0]>='a' && s[0]<='z')
    {
        s[0]= s[0]- 32;
    }
    int new_len=strlen(s); 
    s[new_len]='.';//add a '.'
    s[new_len+1] = '\0'; //add the terminating character
    puts(s);
    return 0;
}