Làm thế nào để tôi so sánh đúng chuỗi?


182

Tôi đang cố gắng để có được một chương trình cho phép người dùng nhập một từ hoặc ký tự, lưu trữ và sau đó in nó cho đến khi người dùng nhập lại, thoát khỏi chương trình. Mã của tôi trông như thế này:

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

Vấn đề là tôi tiếp tục in chuỗi đầu vào, ngay cả khi đầu vào của người dùng (kiểm tra) khớp với bản gốc (đầu vào). Tôi có đang so sánh hai cái không chính xác?


13
gets( )đã được loại bỏ khỏi tiêu chuẩn. Sử dụng fgets( )thay thế.
Edward Karak

1
Lưu ý rằng câu trả lời này cho Tại sao không strcmp()trả về 0 khi các đầu vào của nó bằng nhau giải thích cách so sánh các chuỗi cho đẳng thức, bất đẳng thức, nhỏ hơn, lớn hơn, nhỏ hơn hoặc bằng và lớn hơn hoặc bằng. Không phải tất cả các so sánh chuỗi là cho bình đẳng. So sánh trường hợp nhạy cảm là khác nhau một lần nữa; các so sánh đặc biệt khác (ví dụ thứ tự từ điển) đòi hỏi các bộ so sánh chuyên biệt hơn, và có các biểu thức cho các so sánh phức tạp hơn.
Jonathan Leffler

Cũng lưu ý rằng có một câu hỏi trùng lặp về cơ bản Làm thế nào để tôi kiểm tra xem một giá trị có khớp với chuỗi đã được hỏi nhiều năm trước không.
Jonathan Leffler

Điều này có trả lời câu hỏi của bạn không? Làm cách nào để kiểm tra xem giá trị có khớp với chuỗi không
Andreas

Câu hỏi này là tốt, nhưng việc sử dụng gets()là không có. Nó cũng đã bị xóa khỏi tiêu chuẩn kể từ C11 -> Vui lòng đọc Tại sao chức năng get lại nguy hiểm đến mức không nên sử dụng?
RobertS hỗ trợ Monica Cellio

Câu trả lời:


274

Bạn không thể (hữu ích) so sánh các chuỗi bằng !=hoặc ==, bạn cần sử dụng strcmp:

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

Lý do cho điều này là bởi vì !===sẽ chỉ so sánh các địa chỉ cơ sở của các chuỗi đó. Không phải nội dung của chuỗi.


10
tương tự trong java, có thể chỉ so sánh với địa chỉ.
Telerik

29
Viết while (strcmp(check, input))là đủ và được coi là thực hành tốt.
Shiva


7
Sử dụng strncmp sẽ an toàn hơn! Đừng muốn tràn bộ đệm!

@Floam Nếu bạn không thực sự có các chuỗi, nhưng các chuỗi không đệm của các ký tự khác không có độ dài đã biết, chắc chắn, đó sẽ là câu thần chú đúng. Nhưng đó là một cái gì đó hoàn toàn khác!
Ded repeatator

33

Ok một vài điều: getskhông an toàn và nên được thay thế fgets(input, sizeof(input), stdin)để bạn không bị tràn bộ đệm.

Tiếp theo, để so sánh các chuỗi, bạn phải sử dụng strcmp, trong đó giá trị trả về là 0 cho biết hai chuỗi khớp với nhau. Sử dụng các toán tử đẳng thức (ví dụ. !=) So sánh địa chỉ của hai chuỗi, trái ngược với các chars riêng lẻ bên trong chúng.

Và cũng lưu ý rằng, trong ví dụ này, nó sẽ không gây ra sự cố, cũng fgetslưu trữ ký tự dòng mới, '\n'trong bộ đệm; gets()không làm. Nếu bạn so sánh đầu vào của người dùng từ fgets()một chuỗi ký tự như vậy "abc"thì nó sẽ không bao giờ khớp (trừ khi bộ đệm quá nhỏ để '\n'không phù hợp với nó).


Bạn có thể vui lòng làm rõ mối quan hệ / vấn đề của "\ n" và chuỗi ký tự không? Tôi nhận được kết quả không bằng nhau khi so sánh các chuỗi (dòng) của một tệp với toàn bộ tệp khác.
bất tài

@incompetent - nếu bạn đọc một dòng từ một tệp với fgets(), thì chuỗi có thể là "abc\n"fgets()giữ dòng mới. Nếu bạn so sánh điều đó với "abc", bạn sẽ nhận được 'không bằng' vì sự khác biệt giữa chấm dứt byte null "abc"và dòng mới trong dữ liệu đọc. Vì vậy, bạn phải hạ gục dòng mới. Cách một dòng đáng tin cậy để làm điều đó là buffer[strcspn(buffer, "\n")] = '\0';có công đức hoạt động chính xác bất kể có dữ liệu nào trong bộ đệm hay dữ liệu đó có kết thúc bằng một dòng mới hay không. Các cách khác để hạ gục dòng mới dễ dàng sụp đổ.
Jonathan Leffler

Câu trả lời này giải quyết các vấn đề của mã một cách chính xác, trong khi câu trả lời được đánh giá cao nhất và được chấp nhận chỉ bao gồm để trả lời tiêu đề của câu hỏi. Đặc biệt phải kể đến đoạn cuối là siêu. +1
RobertS hỗ trợ Monica Cellio

11

Sử dụng strcmp.

Đây là trong string.hthư viện, và rất phổ biến. strcmptrả về 0 nếu các chuỗi bằng nhau. Xem điều này để giải thích tốt hơn về những gì strcmptrở lại.

Về cơ bản, bạn phải làm:

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

hoặc là

while (!strcmp(check,input))

hoặc là

while (strcmp(check,input))

Bạn có thể kiểm tra điều này , một hướng dẫn trên strcmp.


7

Bạn không thể so sánh các mảng trực tiếp như thế này

array1==array2

Bạn nên so sánh chúng char-by-char; để làm điều này, bạn có thể sử dụng hàm và trả về giá trị boolean (True: 1, false: 0). Sau đó, bạn có thể sử dụng nó trong điều kiện thử nghiệm của vòng lặp while.

Thử cái này:

#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
Bạn có thể vui lòng thêm chi tiết về giải pháp của bạn?
abarisone

vâng, đây là sự thay thế cho chức năng và giải pháp strcmp mà không cần sử dụng tiêu đề chuỗi.h @Jongware
Mugetsu

2
Điều này không hoạt động. Khi checkertìm thấy '\0'một trong các chuỗi, nó không kiểm tra chuỗi khác '\0'. Hàm trả về 1("bằng") ngay cả khi một chuỗi chỉ là tiền tố của chuỗi khác (ví dụ: "foo""foobar").
lukasrozs

1
Tôi sẽ sử dụng ||thay vì &&.
lukasrozs

3

Chào mừng bạn đến khái niệm về con trỏ. Các thế hệ lập trình viên khởi đầu đã tìm thấy khái niệm khó nắm bắt, nhưng nếu bạn muốn phát triển thành một lập trình viên có năng lực, cuối cùng bạn phải nắm vững khái niệm này - và hơn nữa, bạn đã đặt câu hỏi đúng. Điều đó thật tốt.

Có rõ ràng cho bạn một địa chỉ là gì? Xem sơ đồ này:

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

Trong sơ đồ, số nguyên 1 được lưu trong bộ nhớ tại địa chỉ 0x4000. Tại sao tại một địa chỉ? Bởi vì bộ nhớ lớn và có thể lưu trữ nhiều số nguyên, giống như một thành phố lớn và có thể chứa nhiều gia đình. Mỗi số nguyên được lưu trữ tại một vị trí bộ nhớ, vì mỗi gia đình cư trú trong một ngôi nhà. Mỗi vị trí bộ nhớ được xác định bởi một địa chỉ , vì mỗi ngôi nhà được xác định bởi một địa chỉ.

Hai hộp trong sơ đồ đại diện cho hai vị trí bộ nhớ riêng biệt. Bạn có thể nghĩ về chúng như thể chúng là những ngôi nhà. Số nguyên 1 nằm trong vị trí bộ nhớ tại địa chỉ 0x4000 (nghĩ, "4000 Elm St."). Số nguyên 7 nằm trong vị trí bộ nhớ tại địa chỉ 0x4004 (nghĩ, "4004 Elm St.").

Bạn nghĩ rằng chương trình của bạn đang so sánh 1 với 7, nhưng thực tế không phải vậy. Nó đã so sánh 0x4000 với 0x4004. Vậy điều gì xảy ra khi bạn gặp tình huống này?

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

Hai số nguyên giống nhau nhưng địa chỉ khác nhau. Chương trình của bạn so sánh các địa chỉ.


2

Bất cứ khi nào bạn đang cố gắng so sánh các chuỗi, hãy so sánh chúng với từng nhân vật. Để làm điều này, bạn có thể sử dụng hàm chuỗi tích hợp có tên strcmp (input1, input2); và bạn nên sử dụng tệp tiêu đề được gọi là#include<string.h>

Hãy thử mã này:

#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

Làm thế nào để tôi so sánh đúng chuỗi?

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))

Hãy để chúng tôi đào sâu hơn để xem tại sao check != inputkhông đủ .

Trong C, chuỗi là một đặc tả thư viện tiêu chuẩn.

Một chuỗi là một chuỗi liền kề của các nhân vật kết thúc bằng và bao gồm các ký tự null đầu tiên.
C11 §7.1.1 1

inputở trên không phải là một chuỗi . inputmảng 40 của char .

Các nội dung inputcó thể trở thành một chuỗi .

Trong hầu hết các trường hợp, khi một mảng được sử dụng trong một biểu thức, nó được chuyển đổi thành địa chỉ của phần tử thứ 1 của nó.

Các bên dưới chuyển đổi checkinputthành địa chỉ tương ứng của phần tử đầu tiên, sau đó các địa chỉ đó được so sánh.

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

Để so sánh các chuỗi , chúng ta cần sử dụng các địa chỉ đó và sau đó xem dữ liệu họ trỏ đến.
strcmp()hiện công việc . §7,23.4.2

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

Các strcmpchức năng so sánh chuỗi trỏ đến bởi s1vào chuỗi trỏ đến bởi s2.

Các strcmphàm trả về một số nguyên lớn hơn hơn, bằng hoặc nhỏ hơn không, theo như chuỗi trỏ đến bởi s1lớn hơn, bằng, hoặc ít hơn so với chuỗi trỏ đến bởi s2.

Mã không chỉ có thể tìm thấy nếu các chuỗi có cùng dữ liệu, mà chuỗi nào lớn hơn / ít hơn khi chúng khác nhau.

Điều dưới đây là đúng khi chuỗi khác nhau.

strcmp(check, input) != 0

Để hiểu rõ hơn, hãy xem Tạo strcmp()chức năng của riêng tôi


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

Đây là giải pháp rất đơn giản, trong đó bạn sẽ nhận được đầu ra như bạn muốn.


2
gets();không phải là một phần của tiêu chuẩn C kể từ C11.
chux - Phục hồi Monica

2
strcmp(s1,s2)là UB vì s2nội dung không được chỉ định lúc đầu.
chux - Phục hồi Monica

Sẽ thật tuyệt nếu bạn cũng có thể cung cấp đầu ra của đoạn trích này, dưới hình thức này hay hình thức khác.
not2qubit
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.