c - 尝试通过使用字符串来检查数字是否为回文

标签 c string palindrome

<分区>

我正在尝试检查输入数字是否为回文。我是通过字符串而不是整数来完成的。所以,我正在接收一个字符串并将其反转为另一个字符串。但是,当我使用字符串比较函数时,它没有给我 0,说明字符串不相同。即使当我输入例如“1001”时,输入字符串和反向字符串都显示 1001。我已经用其他方法解决了这个问题,但我试图具体了解这个方法有什么问题。

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

int main(void)
{
    char input[100];
    char reverse[100];

    int numLen = 0;

    printf("Enter a number\n");
    fgets(input, 100, stdin);
    printf("The number is: %s\n", input);

    numLen = strlen(input) - 1;
    printf("Length of string is: %d\n", numLen);

    for (int i = 0; i < numLen; i++)
    {
        reverse[i] = input[numLen - 1 - i];

        if (i == numLen - 1)
        {
            reverse[i + 1] = '\0';
        }
    }

    printf("The reverse number is: %s\n", reverse);
    printf("The original number is: %s\n", input);

    int result = strcmp(input, reverse);
    printf("Result of strcmp gives us: %d\n", result);

    if (strcmp(input, reverse) == 0)
    {
        printf("These numbers are palindromes\n");
    }
    else
    {
        printf("These numbers are not palindromes\n");
    }

    return 0;
}

最佳答案

问题是您没有正确处理字符串。您应该覆盖 '\n'\0 .

    ...
    char input[100];
    char reverse[100];

    int numLen = 0;

    printf("Enter a number\n");
    fgets(input, 100, stdin);
    printf("The number is: %s\n", input);
    input[strcspn(input,"\n")]='\0'; // getting the length of the 
                                     // string without `\n` 
                                     // and overwriting with `\0`
    numLen = strlen(input) ;  // now you don't need to put the -1
    printf("Length of string is: %d\n", numLen);

    for (int i = 0; i < numLen; i++)
    {
        ....

除了这两个变化之外,其他一切都保持不变。你把它完全颠倒过来了。然后你使用了 strcmp正确的方法。但是额外的\n在我显示的代码中被删除。

(仍然)为什么有效?

现在给你一个更好的主意。你很好地形成了反转的字符串。但是原始字符串有 \n在其内部。

printf("The reverse number is: (%s)\n", reverse);
printf("The original number is: (%s)\n", input);

在前面的程序中,您只需编写这两行。你会明白你错在哪里。

关于提供输入 1001 Enter 它给出了这个输出。

The reverse number is: (1001)
The original number is: (1001
)

什么是strcspn在做什么?

我正在使用 strcspn函数得到了没有\n的长度并用 \0 覆盖它.

0 1 2 3  4  5   --> indices
1 0 0 1 \n \0   --> strcspn(input,"\n") returns 4.
1 0 0 1 \0 \0   --> input[strcspn(input,"\n")]='\0'

你可以像这样简单地做,而不需要复制和其他一切。

没有额外的内存 - 就地回文检查

bool checkPal(const char *s){
    for(int i = 0, j= strlen(s)-1; i< strlen(s) && j>=0 ; i++)
        if(s[i] != s[j])
            return false;
    return true;
}
int main(void)
{
    char input[100];
    char reverse[100];

    
    printf("Enter a number\n");
    if( fgets(input, 100, stdin) )
    printf("The number is: %s\n", input);
    
    input[strcspn(input,"\n")]='\0';
    int numLen = strlen(input) ;
    printf("Length of string is: %d \n", numLen);
  
    printf("These numbers are %spalindromes\n", checkPal(input)?"not ":"");
    return 0;
}

一种更简洁的方式来编写 checkPal()会是,

bool checkPal(const char *first){
    const char *last = first + strlen(first);
    while (first < last) {
       if (*first++ != *--last) {
           return false;
       }
   }
   return true;
}

last指向 \0特点。在我们开始比较之前,减法是必要的。要清楚地了解发生了什么,您必须知道优先级和一些规则。

first<last部分是显而易见的。我们一直在比较,直到达到我们 first > last 的地步。 (对于偶数长度的字符串)或 first = last (对于奇数长度的字符串)。

if有点棘手。 *first++涉及两个运营商。 * (间接)和 ++ (后增量)。

++的优先级高于取消引用 * .

所以 *first++将是 - 首先是递增的。然后你可能会认为我们第一次漏掉了一个字符,但事实并非如此。后缀表达式的值是我们做 first++ 之前的值.现在您有了第一个字符。

同理*--last将具有相同的效果,只是前缀表达式的值是操作后的值。所以你正在考虑最后一个字符。

如果匹配,我们继续。 firstlast已经包含修改后的值。我们对较小的子字符串中的其余字符重复相同的逻辑。

如果发生不匹配,我们会立即返回。 (因为它不是回文)。

关于c - 尝试通过使用字符串来检查数字是否为回文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47466639/

相关文章:

c - 为什么可以使用 typedef 的名称作为结构成员的名称?

C程序回文游戏

Java : Convert Color string value to Hexa value

android - 有没有比 Html.fromHtml() 更快的方法将 html 字符解码为字符串?

c - 打开文件后出现奇怪的段错误?

c - 指向范围外变量的指针在 C 中如何表现?

ruby - 如何在 Ruby 中返回整数的固定长度二进制表示?

c++ - 由两个 3 位数的乘积组成的所有回文数

algorithm - 无法理解寻找最长回文子串的解决方案之一

c++ - 为什么在使用STL列表时不能使用此回文功能?