如何在此代码回文问题中修复这些错误,以判断它是奇数还是偶数

时间:2019-07-06 06:12:25

标签: c

给定的字符串是回文,您需要声明它是偶数回文(长度为偶数的回文)或奇数回文(长度为奇数的回文),否则返回No。

我编写此代码,但未获得真实输出

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

int main(){
    int n ;
    char s[100000],b[100000];
    int count=0,d,h,i,t,j;

    if(count<1)
    {
        scanf("%d", &n);
        if(n<=50)
        {
            for(t=1;t<=n;t++)
            {
                i=0,j=0,h=0;

                scanf("%s", s);

                h=strlen(s)-1;
                if(h>=1&&h<=100000)
                {
                    for(i=0,j=h;i<=h&&j>=0; j--,i++)
                    {
                        b[i]=s[j];

                    } 

                    if(strcmp(s,b)==0)
                    {
                        if(h%2==0)
                        {
                            printf("YES EVEN");
                            printf("\n");
                        }
                        else
                        {
                            printf("YES ODD");
                            printf("\n");
                        }
                    }
                    else{
                        printf("NO");
                        printf("\n");
                    }
                }
            }       
        }
        count++;
    }
    return 0;
}
#include<string.h>
#include <stdio.h>

int main(){
    int n ;
    char s[100000],b[100000];
    int count=0,d,h,i,t,j;

    if(count<1)
    {
        scanf("%d", &n);
        if(n<=50)
        {
            for(t=1;t<=n;t++)
            {
                i=0,j=0,h=0;

                scanf("%s", s);

                h=strlen(s)-1;
                if(h>=1&&h<=100000)
                {
                    for(i=0,j=h;i<=h&&j>=0; j--,i++)
                    {
                        b[i]=s[j];

                    } 

                    if(strcmp(s,b)==0)
                    {
                        if(h%2==0)
                        {
                            printf("YES EVEN");
                            printf("\n");
                        }
                        else
                        {
                            printf("YES ODD");
                            printf("\n");
                        }
                    }
                    else{
                        printf("NO");
                        printf("\n");
                    }
                }
            }       
        }
        count++;
    }
    return 0;
}

忘记语法错误,只会发现逻辑错误。

我希望输出是

输入

3
abc
abba
aba

您代码的输出

NO
YESODD
NO

预期正确输出

NO
YESEVEN
YESODD

当我提供不超过一个的字符串时,我得到真实的结果 但是哪里出错了?

3 个答案:

答案 0 :(得分:0)

  1. 在创建字符串b时,您忘记添加终止字符\0
  2. 在检查时也使用h%2。但是hstrlen(s)-1。因此,如果h%2 == 0
  3. ,则需要设置为奇数

相关更改如下所示

for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
    b[i]=s[j];

} 
b[h+1] = '\0';

if(strcmp(s,b)==0)
{
    if(h%2!=0)
    {
        printf("YES EVEN");
        printf("\n");
    }
    else
    {
        printf("YES ODD");
        printf("\n");
    }
}
  

忘记语法错误,只会发现逻辑错误。

我发现这种说法非常错误。除非您修复语法,否则您将无法从逻辑上对其进行查看。另外,适当的缩进确实有助于调试代码并自行查找错误。

答案 1 :(得分:0)

您有很多问题,但是主要问题在于您的冲销。您尝试通过以下方式进行逆转:

    h=strlen(s)-1;
    if(h>=1&&h<=100000){
     for(i=0,j=h;i<=h&&j>=0; j--,i++) {
        b[i]=s[j];
    }

这将strlen(s) == 1失败,不能确保终止,并且因为您使用h=strlen(s)-1;,所以h中的if (h % 2 == 0)会导致相反 EVENODD的确定。相反,您需要:

#define MAXC 100000     /* if you need a constant, #define one (or more) */
...
    h = strlen (s);             /* h must be strlen(s) - not - 1 */
    if (h >= 1 && h < MAXC) {   /* now loop j=h-1; j < h  times */
        for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
            b[i] = s[j];
        b[i] = 0;               /* and ensure b is nul-terminated */

注意:适当间隔的代码更易于阅读和调试)

接下来,您将无法验证每次对scanf的调用的返回,而是盲目地使用变量而没有任何指示输入是否成功的提示-未定义行为的秘诀。您必须验证每个用户输入,例如

    if (scanf ("%d", &n) != 1 || n > 50) {
        fputs ("error: invalid integer or out-of-range.\n", stderr);
        return 1;
    }

    while (n-- && scanf ("%s", s) == 1) {

只需选择代码的逻辑因式,就完全不需要变量td。请注意,您在n上的条件是(1)有效,并且(2)不超过50。这些可以合并为一张支票。将单词读入n时,s循环执行同样的操作。

进行这些更改后,您的代码可简化为:

#include <stdio.h>

#define MAXC 100000     /* if you need a constant, #define one (or more) */

int main (void)
{
    char s[MAXC];
    int n;

    if (scanf ("%d", &n) != 1 || n > 50) {
        fputs ("error: invalid integer or out-of-range.\n", stderr);
        return 1;
    }

    while (n-- && scanf ("%s", s) == 1) {
        char b[MAXC];               /* b is only needed within loop */
        int h = strlen (s), i = 0, j;   /* as are h, i, j, no - 1 for h */
        if (h >= 1 && h < MAXC) {   /* now loop j=h-1; j < h  times */
            for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
                b[i] = s[j];
            b[i] = 0;               /* and ensure b is nul-terminated */

            if (strcmp (s, b) == 0) {
                if (h % 2 == 0)
                    printf ("YES EVEN\n");
                else
                    printf ("YES ODD\n");
            }
            else
                printf ("NO\n");
        }
    }
    return 0;
}

现在可以提供您所需要的回文检查和ODDEVEN长度的输出,例如

使用/输出示例

$ echo "5 abcba abccba abcdba a aa" | ./bin/pdromerefmt
YES ODD
YES EVEN
NO
YES ODD
YES EVEN

您应该通过为s转换添加 field-width 修饰符来进一步保护"%s"的数组范围,例如"%99999s"消除了检查h <= 100000的需要(如果输入的字符为100000或更大,则已经检查了 Undefined Behavior )。无需检查h >= 1,因为循环限制对h = 0不起任何作用,但可以确保为空字符串。

通过进一步的调整和数组边界保护,您的循环简化为:

    while (n-- && scanf ("%99999s", s) == 1) {
        char b[MAXC];                   /* b is only needed within loop */
        int h = strlen(s), i = 0, j = h;/* as are h, i, j, no -1 for h */
        while (j--)             /* must loop j times, regardless */
            b[i++] = s[j];      /* reversing characters in s in b */
        b[i] = 0;               /* and ensure b is nul-terminated */

        if (strcmp (s, b) == 0) {
            if (h % 2 == 0)
                printf ("YES EVEN\n");
            else
                printf ("YES ODD\n");
        }
        else
            printf ("NO\n");
    }

答案 2 :(得分:0)

  

忘记语法错误,只会发现逻辑错误。

这就是铅笔和纸(或者也许是橡皮鸭)的用途,目的是找出一种算法并从逻辑上遵循其步骤。但是,您有一个完整的程序,并有大量测试可以尝试。现在是时候消除您可以找到的每个错误,从语法错误开始,这些错误在编译时可以“轻松”检测到。

已经有足够的答案来解决发布的代码中的缺陷,但是至少还没有涉及到一件事,但这实际上不是错误或逻辑错误。

对于每个测试用例,发布的算法都将执行以下操作:

  • 读一个单词(用scanf)。

  • 查找尺寸(使用strlen)。

  • 创建一个反向副本(使用for循环)。

  • 将副本与原始副本进行比较以检查回文率(使用strcmp)。

为什么所有这些副本和数组遍历?一旦知道了单词的长度,就可以将字符串的左侧与右侧进行比较。

#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#define MAX_CHARS_IN_STR  100000
#define MAX_N_TESTS           50

// Performs the check without copying the the string
// length: size of the word
bool is_palindrome(size_t length, const char *str);

#define STRINGIFY_IMPL(x) #x
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STR_WIDTH_FMT(x) "%" STRINGIFY(x) "s"

int main(void)
{
    int n_words;
    if ( scanf("%d", &n_words) != 1  ||  n_words < 1  ||  n_words > MAX_N_TESTS)
    {
        fprintf(stderr, "Error: the input is not a valid integer between 1 and %d.",
                MAX_N_TESTS);
        return 1;
    }

    int n_chars;
    // Allocates an array big enough (including the null-terminator)
    char word[MAX_CHARS_IN_STR + 1];
    // It will use an array of two pointers instead of another if-else
    const char *even_or_odd_str[] = { "IS EVEN", "IS ODD" };
    while ( n_words-- )
    {
        // consume whitespace characters left in the input
        scanf(" ");

        // reads the string up to its maximum width or until the first whitespace.
        // The macro expands to "%100000s" and that literal will be concatenated to "%n",
        // which returns the number of characters read.
        if ( scanf(STR_WIDTH_FMT(MAX_CHARS_IN_STR) "%n", word, &n_chars) != 1 )
        {
            fputs("Error: unable to read word.", stderr);
            break;
        }

        if ( is_palindrome(n_chars, word) )
            puts(even_or_odd_str[n_chars % 2]);
        else
            puts("NO");
    }
}

bool is_palindrome(size_t n, const char *str)
{
    assert(n && str);
    size_t i = 0, j = n - 1;
    while ( i < j  &&  str[i] == str[j] )
    {
        ++i;
        --j;
    }
    // It's a palindrome only if the two indices met halfway
    return i >= j;
}