简体   繁体   English

C中回文函数的意外输出

[英]Unexpected output from palindrome function in C

I've written this function isPalindrome that is meant to take a string input from a separate function, and return 1 if it is a palindrome, and 0 if it is not. 我已经编写了此函数isPalindrome,该函数旨在从单独的函数中获取字符串输入,如果它是回文,则返回1,否则返回0。 The input would be any characters, and may have capitals in it, and the function is meant to sort through these and purely check if it is a palindrome based on the alphabetic characters. 输入的内容可以是任何字符,也可以有大写字母,该函数用于对这些字符进行排序,并纯粹根据字母字符检查回文是否是回文。

I've been on this for a while and I can't figure out what's going wrong, the whole function is below, but I can't make sense of the output it's giving me, sometimes it completely skips the last else statement, and stops the loop, and I've no idea why. 我已经有一段时间了,我无法弄清楚出了什么问题,整个功能都在下面,但是我无法理解它给我的输出,有时它会完全跳过最后的else语句,并且停止循环,我不知道为什么。 When two non alphabetic characters are entered in a row, the variable a or b does not increment twice, rather it sends it to the last else statement and returns an incorrect value. 当连续输入两个非字母字符时,变量a或b不会增加两次,而是将其发送到最后的else语句并返回错误的值。

I'm trying to write this function without copying any information into separate arrays as well. 我正在尝试编写此函数,而不将任何信息也复制到单独的数组中。

int isPalindrome(char s[])
{
int logic;
int a = 0;
int b = 0;
int num = 0;
int count = 0;

while ( s[b]!='\0' )
{
    if ( isalpha(s[b]) != 0 )
    {
        num++;
    }
    b++;
}

b = b - 1;

printf("The number of characters is: %d\n", b);
printf("The number of alpha characters is: %d\n", num);

while ( count < num/2 )
{

    if ( !isalpha(s[a]) || s[a] == ' ')
    {
        a++;
    }
    else
    {
        count++;
    }
    if ( !isalpha(s[b]) || s[b] == ' ')
    {
        b--;
    }

    if ( toupper(s[a]) == toupper(s[b]) )
    {

        printf("s[%d]: %c | s[%d]: %c\n", a, toupper(s[a]), b, toupper(s[b]));

        a++;
        b--;

        if ( a == b )
        {
            logic = 1;
        }
    }
    else
    {
        logic = 0;
        break;
    }
}

   return logic;
}

There are multiple errors (1) logic must be initialized to 1 (2) Only one invalid char is checked per iteration of loop. 有多个错误(1)逻辑必须初始化为1(2)每次循环迭代仅检查一个无效字符。

If you remove the following code, it should work (I mean without valid char checking). 如果删除以下代码,它应该可以工作(我的意思是没有有效的字符检查)。

if ( !isalpha(s[a]) || s[a] == ' ')
{
    a++;
}
else
{
    count++;
}
if ( !isalpha(s[b]) || s[b] == ' ')
{
    b--;
}

For removing invalid characters, better do this before entering the loop or check for 'a < b' instead of count/2 and continue on invalid char as below. 要删除无效字符,最好在进入循环之前执行此操作,或者检查'a <b'而不是count / 2,然后继续对无效字符进行如下操作。

logic=1;
while (a<b)
{
    if ( !isalpha(s[a]))
    {
        a++;
        continue;
    }

    if ( !isalpha(s[b]))
    {
        b--;
        continue;
    }

    if ( toupper(s[a]) == toupper(s[b]) )
    {
        printf("s[%d]: %c | s[%d]: %c\n", a, toupper(s[a]), b, toupper(s[b]));

        a++;
        b--;
    }
    else
    {
        logic = 0;
        break;
    }
}

 return logic;

It seems you want your palindrome tester to only consider alphabetical characters, and disregard case. 看来您希望回文测试人员仅考虑字母字符,而忽略大小写。 If that is the case, the logic of your program is wrong. 如果真是这样,您的程序逻辑是错误的。

You have a and b as the indices of your string, where a starts from the beginning and b starts from the end. 您有ab作为字符串的索引,其中a从头开始, b从头开始。 Instead of computing the number of tests you have to do, I think it is better to just set b to the end, and start your work loop. 我认为最好将b设置为最后,然后开始工作循环,而不是计算必须执行的测试数量。 The loop continues so long as a < b is true: 只要a < b为真,循环就会继续:

int a = 0;
int b = strlen(s) - 1;

while (a < b)
{

In side of your loop, you should increment a if s[a] is not a letter, and decrement b if s[b] is not a letter, so long as a continues to be less than b . 在循环的身边,你应该增加a ,如果s[a]不能是字母,和减量b如果s[b]是不是一个字母,只要a持续小于b

    while (a < b && !isalpha(s[a]))
    {
        ++a;
    }
    while (a < b && !isalpha(s[b]))
    {
        --b;
    }

If after the adjustments, a is is still less than b , then we can compare s[a] and s[b] , disregarding case. 如果在调整之后, a仍小于b ,则可以不考虑大小写而比较s[a]s[b] If they are not equal, then the string is not a palindrome, so we can break from the loop. 如果它们不相等,则字符串不是回文,因此我们可以从循环中中断。 Otherwise, a is incremented, b is decremented, and the loop continues back to the top: 否则, a递增, b递减,循环继续回到顶部:

    if (a < b &&  toupper(s[a]) != toupper(s[b]))
    {
        break;
    }
    ++a;
    --b;
}

If the loop ends and a < b is still true, it means that toupper(s[a]) != toupper(s[b]) , so the string is not a palindrome, and we can return false. 如果循环结束并且a < b仍然为true,则意味着toupper(s[a]) != toupper(s[b]) ,因此该字符串不是回文,我们可以返回false。 Otherwise, it is a palindrome. 否则,它是回文。 So the function can return that fact: 因此该函数可以返回以下事实:

if (a < b)
{
    return false;
}
else
{
    return true;
}
// or more succinctly: return !(a < b);

Your error is in the code that leads to the "payload" palindrome condition check: 您的错误在导致“有效载荷”回文条件检查的代码中:

if ( toupper(s[a]) == toupper(s[b]) )

The code before that check is supposed to bring a and b in such a state that both s[a] and s[b] are letters. 该检查之前的代码应该使ab处于s[a]s[b]均为字母的状态。

Your code does not do that: specifically, sequences of multiple non-alphabetic characters would bring you to a state when you compare a letter to a non-letter, or even two non-letters. 您的代码无法做到这一点:特别是,当您将一个字母与一个非字母甚至两个非字母进行比较时,多个非字母字符的序列会使您进入一种状态。

A simpler way of dealing with this problem would be splitting your program into two stages. 解决此问题的更简单方法是将程序分为两个阶段。 The first stage would eliminate all non-letters from the input string; 第一阶段将消除输入字符串中的所有非字母; the second stage would perform the palindrome check. 第二阶段将执行回文检查。

Make a copy of the incoming string, then go through it character-by-character, copying only letters back into the string. 复制输入字符串,然后逐个字符地进行遍历,仅将字母复制回字符串中。 You would end up with a string that is either shorter or the same length as the original. 您最终会得到一个比原始字符串短或相同长度的字符串。

Now palindrome check becomes trivial: start from both ends, and check for equality of toupper until the two ends meet in the middle. 现在回文检查变得无足轻重了:从两端开始,检查是否有toupper直到两端在中间相遇。 Don't forget to free the copy of your string! 不要忘记释放您的字符串副本!

Your code to skip over non-alpha characters doesn't handle the case of multiple consecutive non-alpha characters. 您跳过非字母字符的代码无法处理多个连续的非字母字符的情况。 You know from the preprocessing pass how many alphabetic characters there are, so you need to replace your if statements by while loops, and make the body of the else unconditional. 您可以从预处理过程中知道有多少个字母字符,因此您需要用while循环替换if语句,并使else的主体成为无条件的。

There are a number of other simplifications in the code that I'd make automatically. 我会自动在代码中进行许多其他简化。

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

static
int isPalindrome(char s[])
{
    int a = 0;
    int b = 0;
    int num = 0;
    int count = 0;

    while (s[b] != '\0')
    {
        if (isalpha(s[b++]))
            num++;
    }

    printf("The number of characters is: %d\n", b);
    printf("The number of alpha characters is: %d\n", num);

    while (count < num/2)
    {
        count++;
        while (!isalpha(s[a]))
            a++;
        while (!isalpha(s[b]))
            b--;

        if (toupper(s[a]) != toupper(s[b]))
            return 0;
        printf("s[%d]: %c | s[%d]: %c\n", a, toupper(s[a]), b, toupper(s[b]));
        a++;
        b--;
    }

    return 1;
}

int main(void)
{
    char line[256];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        line[strlen(line)-1] = '\0';
        printf("Input: <<%s>>\n", line);
        if (isPalindrome(line))
            puts("Palindrome");
        else
            puts("Not a palindrome");
    }
    return 0;
}

This works for perverse sequences of alphabetic and non-alphabetic characters. 这适用于字母和非字母字符的错误序列。 It treats an empty line and a line consisting of all non-alphabetic characters as palindromes; 它将空行和由所有非字母字符组成的行视为回文。 if you want them to be rejected, you could treat that by reporting 'not a palindrome' when the number of alphabetic characters is zero after the loop that counts the number of alphabetic characters. 如果希望它们被拒绝,则可以在对字母字符数进行计数的循环之后,当字母字符数为零时报告“不是回文”,以解决该问题。 The code does an early return when it detects that the string cannot be a palindrome. 当检测到字符串不能是回文字符串时,该代码会尽早返回。 You might move the print statement in the loop before the test; 您可以在测试之前在循环中移动打印语句; then you get to see the results of each comparison, not just the comparisons that succeed. 然后您将看到每个比较的结果,而不仅仅是成功的比较。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM