1

別の関数から文字列入力を取得し、回文の場合は 1 を返し、そうでない場合は 0 を返すこの関数 isPalindrome を作成しました。入力は任意の文字で、大文字が含まれる場合があります。この関数は、これらをソートし、アルファベット文字に基づいて回文であるかどうかを純粋にチェックすることを目的としています。

私はしばらくこれを行ってきましたが、何が問題なのかわかりません。関数全体は以下にありますが、出力を理解できません。最後のelseステートメントを完全にスキップすることがあります。ループを停止しますが、その理由はわかりません。アルファベット以外の文字を 2 つ続けて入力すると、変数 a または b が 2 回インクリメントされず、最後の else ステートメントに送られ、正しくない値が返されます。

情報を別の配列にもコピーせずに、この関数を作成しようとしています。

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;
}
4

4 に答える 4

2

複数のエラーがあります (1) ロジックを 1 に初期化する必要があります (2) ループの反復ごとに 1 つの無効な文字のみがチェックされます。

次のコードを削除すると、動作するはずです (つまり、有効な文字チェックなし)。

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

無効な文字を削除するには、ループに入る前にこれを行うか、count/2 の代わりに 'a < b' をチェックして、以下のように無効な文字を続行することをお勧めします。

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;
于 2013-09-13T02:49:07.687 に答える
2

回文テスターに​​アルファベット文字のみを考慮させ、大文字と小文字を区別しないようにしたいようです。その場合、プログラムのロジックが間違っています。

文字列のインデックスとしてandがaあり、最初から始まり、最後から始まります。実行しなければならないテストの数を計算する代わりに、最後に設定して作業ループを開始する方がよいと思います。ループは true である限り継続します。babba < b

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

while (a < b)
{

ループの側では、 が文字でないa場合はインクリメントし、 が文字でない場合はs[a]デクリメントする必要があります。bs[b]ab

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

調整後でaも が より小さい場合は、大文字と小文字を区別せずにとbを比較できます。それらが等しくない場合、文字列は回文ではないため、ループから抜け出すことができます。それ以外の場合は、インクリメントされ、デクリメントされ、ループが先頭に戻ります。s[a]s[b]ab

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

ループが終了し、a < bまだ true の場合、それは であることを意味するtoupper(s[a]) != toupper(s[b])ため、文字列は回文ではなく、false を返すことができます。そうでなければ回文です。したがって、関数はその事実を返すことができます:

if (a < b)
{
    return false;
}
else
{
    return true;
}
// or more succinctly: return !(a < b);
于 2013-09-13T03:05:47.830 に答える
1

英字以外の文字をスキップするコードは、複数の連続する英字以外の文字のケースを処理しません。前処理パスからアルファベット文字の数がわかるので、ifステートメントをループで置き換え、無条件whileの本体を作成する必要があります。else

私が自動的に作成するコードには、他にも多くの単純化があります。

#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;
}

これは、アルファベットおよび非アルファベット文字のひねくれたシーケンスに対して機能します。空行とすべての非アルファベット文字からなる行を回文として扱います。それらを拒否したい場合は、アルファベットの文字数をカウントするループの後にアルファベットの文字数がゼロのときに「回文ではない」と報告することで処理できます。このコードは、文字列が回文ではないことを検出すると、アーリー リターンを実行します。テストの前に、ループ内の print ステートメントを移動することができます。次に、成功した比較だけでなく、各比較の結果を確認できます。

于 2013-09-13T03:23:59.933 に答える
1

エラーは、「ペイロード」回文条件チェックにつながるコードにあります。

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

そのチェックの前のコードは、 と が両方とも文字であるような状態で、 をもたらすはずですabs[a]s[b]

あなたのコードはそれを行いません: 具体的には、複数の非アルファベット文字のシーケンスは、文字を非文字、または 2 つの非文字と比較したときに状態になります。

この問題に対処するより簡単な方法は、プログラムを 2 つの段階に分割することです。最初の段階では、入力文字列からすべての非文字を削除します。第 2 段階では、回文チェックが実行されます。

入ってくる文字列のコピーを作成し、それを文字ごとに調べて、文字だけを文字列にコピーして戻します。元の文字列よりも短いか同じ長さの文字列になってしまいます。

これで、回文チェックは簡単になります。両端から開始しtoupper、2 つの端が中央で交わるまで が等しいかどうかをチェックします。文字列のコピーを解放することを忘れないでください!

于 2013-09-13T02:43:58.027 に答える