文字列を適切に比較するにはどうすればよいですか?


182

ユーザーが単語や文字を入力して保存し、ユーザーがもう一度入力してプログラムを終了するまで印刷できるプログラムを取得しようとしています。私のコードは次のようになります:

#include <stdio.h>

int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    gets(input);
    printf("I will now repeat this until you type it back to me.\n");

    while (check != input)
    {
        printf("%s\n", input);
        gets(check); 
    }

    printf("Good bye!");


    return 0;
}

問題は、ユーザーによる入力(チェック)が元の(入力)と一致する場合でも、入力文字列の印刷を取得し続けることです。2つを誤って比較していますか?


13
gets( )標準から削除されました。fgets( )代わりに使用してください。
Edward Karak、2015年

1
このことを注意の答えなぜがないstrcmp()その入力が等しいリターンゼロは平等のための文字列を比較する方法について説明し、不平等、より小さい、より大きい、より小さいか等しい、より大きいか等しいです。すべての文字列比較が同等であるとは限りません。大文字と小文字を区別する比較は再び異なります。その他の特別な比較(辞書順など)には、より専門的なコンパレータが必要であり、さらに複雑な比較には正規表現があります。
ジョナサンレフラー

また、本質的に重複する質問があることにも注意してください。がこの前に尋ねられた文字列一致するかどうかを確認するにはどうすればよいですか
ジョナサンレフラー、2017

これはあなたの質問に答えますか?値が文字列と一致するかどうかを確認する方法
Andreas

この質問は良いですが、の使用はgets()ノーゴーです。また、C11以降、標準から削除されました->を参照してくださいなぜ機能が危険なので、使用しないでください。
RobertSは

回答:


276

!=またはを使用して文字列を(便利に)比較することはできません。==使用する必要がありますstrcmp

while (strcmp(check,input) != 0)

この理由はある!===だけそれらの文字列のベースアドレスを比較します。文字列自体の内容ではありません。


10
javaでも同じで、アドレスと比較するだけです。
Telerik、2014

29
書くことwhile (strcmp(check, input))は十分であり、良い習慣と考えられています。
Shiva


7
strncmpを使用する方が安全です。バッファオーバーフローは必要ありません。
Floam 2017年

@Floam実際には文字列がなく、長さがわかっているゼロ以外の文字のゼロが埋め込まれたシーケンスがある場合は、それが正しい呪文になります。しかし、それはまったく別のものです!
Deduplicator

33

いくつか問題があります。gets安全fgets(input, sizeof(input), stdin)はないため、バッファオーバーフローが発生しないように置き換える必要があります。

次に、文字列を比較するには、を使用する必要がありますstrcmp。戻り値0は、2つの文字列が一致することを示します。等号演算子(例:)を使用する!=と、2つの文字列char内の個々の文字列ではなく、2つの文字列のアドレスが比較されます。

また、この例では問題は発生しませんがfgets、改行文字を'\n'バッファーに格納することにも注意してください。gets()ではない。からのユーザー入力をfgets()文字列リテラルと比較した場合は、"abc"一致しません(バッファーが小さすぎてに'\n'収まらない場合を除く)。


「\ n」と文字列リテラルの関係/問題を明確にしていただけませんか?ファイルの文字列(行)を他のファイル全体と比較すると、等しくない結果になります。
無能

@incompetent —を使用してファイルから行を読み取る場合fgets()、文字列は改行を保持する"abc\n"ためである可能性がfgets()あります。それをと比較すると、ヌルバイト"abc"終端"abc"と読み取られたデータの改行との違いにより、「等しくない」という結果になります。したがって、改行をザップする必要があります。これを行うための信頼できる1行の方法buffer[strcspn(buffer, "\n")] = '\0';は、バッファーにデータがあるかどうか、またはそのデータが改行で終わるかどうかに関係なく、正しく機能するというメリットがあります。改行をザッピングする他の方法は簡単にクラッシュします。
ジョナサンレフラー

この回答はコードの問題に正確に対応しますが、最も支持され受け入れられている回答は、質問のタイトルにのみ回答します。特に最後のパラグラフについて言及するのは素晴らしいです。+1
RobertSは

11

を使用しstrcmpます。

これはstring.h図書館にあり、非常に人気があります。strcmp文字列が等しい場合は0を返します。何が戻るかについてのより良い説明についてはこれを見てくださいstrcmp

基本的に、あなたはしなければなりません:

while (strcmp(check,input) != 0)

または

while (!strcmp(check,input))

または

while (strcmp(check,input))

確認してもいい これのチュートリアルをstrcmpます。


7

このように配列を直接比較することはできません

array1==array2

それらを文字ごとに比較する必要があります。このため、関数を使用してブール値(True:1、False:0)を返すことができます。その後、whileループのテスト条件で使用できます。

これを試して:

#include <stdio.h>
int checker(char input[],char check[]);
int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    scanf("%s",input);
    printf("I will now repeat this until you type it back to me.\n");
    scanf("%s",check);

    while (!checker(input,check))
    {
        printf("%s\n", input);
        scanf("%s",check);
    }

    printf("Good bye!");

    return 0;
}

int checker(char input[],char check[])
{
    int i,result=1;
    for(i=0; input[i]!='\0' || check[i]!='\0'; i++) {
        if(input[i] != check[i]) {
            result=0;
            break;
        }
    }
    return result;
}

1
ソリューションの詳細を追加していただけませんか?
アバリゾン

はい、これはstring.hヘッダー@Jongwareを使用せずにstrcmp関数とsolitionを置き換えるものです
mugetsu

2
これは動作しません。ときchecker発見は、'\0'文字列のいずれかで、それがために別の文字列をチェックしません'\0'。関数は1、一方の文字列がもう一方の文字列の接頭辞のみであっても(「等しい」)を返します(たとえば、"foo"and "foobar")。
lukasrozs

1
||代わりに使用します&&
lukasrozs

3

ポインターの概念へようこそ初代プログラマーの世代はその概念をとらえどころのないものにしていますが、有能なプログラマーに成長したい場合は、最終的にこの概念を習得する必要があります。さらに、あなたはすでに正しい質問をしています。それは良い。

住所は何ですか?次の図を参照してください。

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    7   |
----------     ----------

この図では、整数1がメモリのアドレス 0x4000に格納されています。なぜ住所にいるのですか?メモリが大きく、多くの整数を格納できるため、都市が大きく、多くの家族を収容できるのと同じです。各家族は家に住んでいるので、各整数はメモリ位置に保存されます。各家はアドレスで識別されるため、各メモリ位置はアドレスで識別されます。

図の2つのボックスは、2つの異なるメモリ位置を表しています。それらを家のように考えることができます。整数1は、アドレス0x4000のメモリ位置にあります(「4000 Elm St.」と考えてください)。整数7は、アドレス0x4004のメモリ位置にあります( "4004 Elm St."と考えてください)。

あなたのプログラムは1と7を比較していると思っていましたが、そうではありませんでした。0x4000と0x4004を比較していました。では、このような状況になった場合はどうなりますか?

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    1   |
----------     ----------

2つの整数は同じですが、アドレスが異なります。プログラムはアドレスを比較します。


2

文字列を比較する場合は、文字ごとに比較してください。これには、strcmp(input1、input2)という組み込みの文字列関数を使用できます。と呼ばれるヘッダーファイルを使用する必要があります#include<string.h>

このコードを試してください:

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

int main() 
{ 
    char s[]="STACKOVERFLOW";
    char s1[200];
    printf("Enter the string to be checked\n");//enter the input string
    scanf("%s",s1);
    if(strcmp(s,s1)==0)//compare both the strings  
    {
        printf("Both the Strings match\n"); 
    } 
    else
    {
        printf("Entered String does not match\n");  
    } 
    system("pause");  
} 

0

文字列を適切に比較するにはどうすればよいですか?

char input[40];
char check[40];
strcpy(input, "Hello"); // input assigned somehow
strcpy(check, "Hello"); // check assigned somehow

// insufficient
while (check != input)

// good
while (strcmp(check, input) != 0)
// or 
while (strcmp(check, input))

なぜcheck != input十分ではないのか、さらに深く掘り下げてみましょう。

Cでは、stringは標準ライブラリ仕様です。

文字列は、最初のヌル文字で終了し、最初のヌル文字を含む、連続した文字のシーケンスです。
C11§7.1.11

input上記は文字列ではありません。 inputあるチャーのアレイ40

の内容は文字列にinputなります

ほとんどの場合、配列が式で使用されると、配列は最初の要素のアドレスに変換されます。

変換以下checkinput最初の要素のそれぞれのアドレスに、それらのアドレスを比較します。

check != input   // Compare addresses, not the contents of what addresses reference

文字列を比較するには、これらのアドレスを使用して、それらが指すデータを調べる必要があります。
strcmp()仕事をします。§7.23.4.2

int strcmp(const char *s1, const char *s2);

strcmpこの関数は、文字列がで指さ比較s1によって指された文字列へs2

strcmpより大きな整数関数戻り、等しい、またはゼロ未満には、文字列がによって指さしたがってとしてs1以下の文字列がによって指さと等しい、または、より大きいs2

文字列が同じデータであるかどうかをコードで見つけるだけでなく、文字列が異なる場合、どちらが大きいか小さいかを見つけることができます。

以下は、文字列が異なる場合に当てはまります。

strcmp(check, input) != 0

洞察については、独自の関数の作成を参照してくださいstrcmp()


-2
    #include<stdio.h>
    #include<string.h>
    int main()
    {
        char s1[50],s2[50];
        printf("Enter the character of strings: ");
        gets(s1);
        printf("\nEnter different character of string to repeat: \n");
        while(strcmp(s1,s2))
        {
            printf("%s\n",s1);
            gets(s2);
        }
        return 0;
    }

これは非常にシンプルなソリューションで、必要な出力を得ることができます。


2
gets();C11以降、標準Cの一部ではありません。
chux-モニカを

2
strcmp(s1,s2)s2最初はコンテンツが指定されていないため、UB です。
chux-モニカを

このスニペットの出力を何らかの形で提供できると便利です。
not2qubit
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.