【问题标题】:Palindrome - C language onlyPalindrome - 仅限 C 语言
【发布时间】:2017-06-12 13:27:25
【问题描述】:

我想知道为什么结果不正确。 如果我输入字符串来测试字符串是否为回文, 每次尝试的结果都是一样的。

例如,如果我输入“dad”进行测试,这表明它不是回文。 但是,如果我输入“god”,它仍然显示这不是回文。

我不知道如何以正确的方式解决此问题... 请让我知道我该怎么做。

谢谢。

(以下代码)

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

void isPalindrome(char *str, int n);

int main() {
    char str[100];
    int n = strlen(str);
    char choice;
    printf("Will you run this program? : ");
    scanf("%c", &choice);
    getchar();

    while (choice == 'Y' || choice == 'y') {
        isPalindrome(str, n);
        printf("Retry? : ");
        scanf("%c", &choice);
        getchar();
    }
}

void isPalindrome(char *str, int n) {
    int flag = 1;
    printf("Type strings : ");
    gets_s(str, 100);

    for (int i = 0; i < n / 2; i++) { 
        if ('A' <= str[i] && str[i] <= 'Z') {
            str[i] = str[i] - 'A' + 'a';
        }

        if (strlen(str) / 2 == 0) {
            if (str[i] != str[n - i - 1]) {
                flag = 0;
                break;
            }
        } else
        if (strlen(str) / 2 != 0) {
            if (str[i] != str[n - i]) {
                flag = 0;
                break;
            }
        }
    }
    if (flag == 1) {
        printf("%s is a palindrome \n", str);
    } else {
        printf("%s is not a palindrome \n", str);
    }
}

【问题讨论】:

  • 现在是学习如何使用调试器的好时机。
  • (strlen(str) / 2 == 0) 没有意义。也许你的意思是(strlen(str) %% 2 == 0)
  • "你会运行这个程序吗?" -- 但是……但是……我不是已经这样做了吗?
  • 当你给它字符串 b 时这个工作吗?它打印b is a palindrome 吗?如果是,那么我可能在我之前的评论中发现了你的错误。
  • str in main() 是一个未初始化的数组。因此,调用 strlen(str) 具有未定义的行为。这发生在第一个 printf() 之前和调用 IsPalindrome() 之前。

标签: c string palindrome


【解决方案1】:

对于根据 C 标准的初学者,不带参数的函数 main 应声明为

int main( void )

函数isPalindrome 应该只做一件事——检查提供的字符串是否是回文。所有输入都应在 main 中完成。

此外,由于该函数不会更改字符串本身,其对应的参数应使用限定符const 声明。

函数的返回类型应为int_Bool

main 中的第二条语句

char str[100];
int n = strlen(str);

没有意义,因为数组str 不包含任何字符串。而且变量n的类型应该是size_T,因为它是函数strlen的返回类型。

而不是这些操作

    if ('A' <= str[i] && str[i] <= 'Z')
    {
        str[i] = str[i] - 'A' + 'a';
    }

使用标准函数tolower会好很多,而且你必须同时转换字符串的两个符号。

程序可以如下所示。

#define __STDC_WANT_LIB_EXT1__  1

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

#define N 100

int isPalindrome(const char s[], size_t n)
{
    size_t i = 0;

    while (i < n / 2 &&
        tolower((unsigned char)s[i]) == tolower((unsigned char)s[n - i - 1])) ++i;

    return i == n / 2;
}

int main( void )
{
    char choice;

    printf( "Will you run this program? : " );
    scanf( " %c", &choice );
    getchar();

    while ( choice == 'Y' || choice == 'y' )
    {
        char s[N];

        printf( "Type a string : " );
        gets_s( s, N );

        if ( isPalindrome( s, strlen( s ) ) )
        {
            printf( "\"%s\" is a palindrome\n", s );
        }
        else
        {
            printf("\"%s\" is not a palindrome\n", s);
        }

        printf( "Retry? : " );
        scanf( " %c", &choice );
        getchar();
    }

    return 0;
}

程序输出可能看起来像

Will you run this program? : y
Type a string : dad
"dad" is a palindrome
Retry? : y
Type a string : god
"god" is not a palindrome
Retry? : n

【讨论】:

    【解决方案2】:

    以下是您可以使用的示例实现,其中包含 C 编程中的良好实践,并且使用内置函数 tolower() 不区分大小写:

    Try it online!

    #include <stdio.h>
    #include <string.h>
    #include <stdbool.h>
    #include <ctype.h>
    
    bool isPalindrome(char*, size_t);
    void printIsPalindrome(char*);
    
    int main() {
        printIsPalindrome("abba");
        printIsPalindrome("abbccbba");
        printIsPalindrome("aBBcCbbA");
        printIsPalindrome("geeks");
        printIsPalindrome("");
    
        return 0;
    }
    
    bool isPalindrome(char* buf, size_t len) {
        size_t i = 0;
        size_t j = len;
        char a;
        char b;
    
        while (j > i) {
            a = tolower(buf[i++]);
            b = tolower(buf[--j]);
    
            if (a != b) {
                return false;
            }
        }
    
        return true;
    }
    
    void printIsPalindrome(char* str) {
        if (isPalindrome(str, strlen(str))) {
            printf("%s is a palindrome\r\n", str);
        } else {
            printf("%s is not a palindrome\r\n", str);
        }
    }
    

    本质上,您希望将驱动逻辑与检查字符串是否为回文的实现分开。这就是函数被拆分为isPalindrome()printIsPalindrome() 的原因。

    检查条件是否为真的函数不应该有输出到控制台的副作用,这通常是一种很好的做法,而不仅仅是在 C 中。

    预期会被重复使用的通用函数(即isPalindrome())也不应该假定传递的缓冲区(char* buf)是一个 C 字符串,所以检查strlen() 应该只在驱动程序中完成代码printIsPalindrome(),不是可移植逻辑。这样做的原因是通过缓冲区溢出攻击避免安全漏洞,如果其他人打算在他们的程序中使用您的 isPalindrome() 实现作为依赖项,假设。它允许他们明确指定他们传递的缓冲区的大小,因此他们需要验证缓冲区是否在分配的内存块之外没有被访问。

    最后,检查缓冲区索引(ij)的任何内容都应该是 size_t,以便成为可移植代码,因为 size_t 保证足够大以处理所有内存空间, 而int 不持有该保证。

    【讨论】:

    • isPalindrome 对空字符串有未定义的行为。
    猜你喜欢
    • 2018-01-05
    • 2016-08-20
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多