2009-02-27 36 views
11

Khi tôi thực hiện một cuộc gọi đến chuỗi C so sánh chức năng như thế này:Tại sao strcmp() trả về 0 khi đầu vào của nó bằng nhau?

strcmp("time","time")

Nó trả về 0, trong đó hàm ý rằng các dây không bằng nhau.

Bất cứ ai có thể cho tôi biết lý do tại sao các triển khai C dường như thực hiện việc này? Tôi nghĩ nó sẽ trả về giá trị khác 0 nếu bằng nhau. Tôi tò mò với những lý do tôi thấy hành vi này.

+0

Thời gian! = Tiền trực tiếp - trước tiên bạn phải sử dụng chuyển đổi đơn vị. –

+4

kudo cho bất cứ ai làm lại câu hỏi spam này thành một thứ có thể hữu ích cho người mới. Tôi vẫn không sẵn sàng bỏ phiếu cho nó mặc dù, vì sợ rằng nó khuyến khích OP để đăng tripe như vậy một lần nữa. – rmeador

+3

@remeador: Cảm ơn bạn, nhưng đừng xúc phạm OP. – GEOCHET

Trả lời

22

strcmp trả về sự khác biệt từ vựng (hoặc tôi nên gọi nó là "so sánh byte nối tiếp ngắn mạch"? :-)) của hai chuỗi bạn đã đưa ra làm tham số. 0 có nghĩa là cả hai chuỗi đều bằng nhau

Giá trị dương có nghĩa là s1 sẽ theo sau s2 trong từ điển.

Giá trị âm có nghĩa là s1 sẽ trước s2 trong từ điển.

Do đó, giá trị khác 0 khi so sánh "thời gian" và "tiền" rõ ràng là khác nhau, mặc dù người ta nói thời gian đó là tiền! :-)

+2

strcmp() không làm so sánh từ vựng, nó chỉ so sánh giá trị của mỗi ký tự cho đến khi có sự khác biệt hoặc cả hai chuỗi chấm dứt. – Ferruccio

+0

Tôi có thể thề là tôi đã đọc tài liệu cho biết strcmp() có so sánh lexical, nhưng một số googling nhanh chóng cho thấy Ferruccio là chính xác ...nó có thể thay đổi tại một thời điểm nào đó không? – rmeador

+0

Không. Luôn luôn như vậy :-) – Ferruccio

3

Bạn dường như muốn strcmp để làm việc như một (giả thuyết)

int isEqual(const char *, const char *) 

Để chắc chắn điều đó sẽ đúng với "zero là false" giải thích các kết quả số nguyên, nhưng nó sẽ phức tạp logic của phân loại bởi vì, đã thiết lập rằng hai dây không giống nhau, bạn vẫn sẽ cần phải tìm hiểu mà đến "sớm hơn".

Hơn nữa, tôi nghi ngờ rằng một thi chung trông giống như

int strcmp(const char *s1, const char *s2){ 
    const unsigned char *q1=s1, *q2=s2; 
    while ((*q1 == *q2) && *q1){ 
     ++q1; ++q2; 
    }; 
    return (*q1 - *q2); 
} 

đó là [chỉnh sửa: kinda] thanh lịch trong một K & R loại cách. Vấn đề quan trọng ở đây (mà ngày càng bị che khuất bởi nhận được mã phải (rõ ràng là tôi nên đã để lại cũng đủ một mình)) là cách câu lệnh return:

return (*q1 - *q2); 

mang đến cho các kết quả của việc so sánh một cách tự nhiên về các giá trị ký tự.

+0

Sẽ không phải là "phổ biến thực hiện" đi bộ ra khỏi bộ đệm (qua chấm dứt null?) Tôi không thấy làm thế nào nó sẽ trở lại 0 ... –

+0

tôi nghĩ rằng bạn phải chấm dứt vòng lặp nếu bạn đến \ 0 :) u cũng phải xem về dòng dưới trong * s1 - * s2 vì vậy s1 = -127, s2 = 2 => oops :) –

+0

@Daniel: Uh. Vâng. Khoảnh khắc khi tôi sửa lỗi này ... – dmckee

5

Thông thường các hàm sẽ trả về giá trị 0 cho trường hợp chung - hoặc một-of-a-type - case và khác không đối với các trường hợp đặc biệt. Lấy hàm chính, thường trả về số không thành công và một số giá trị khác không cho lỗi. Giá trị khác không chính xác cho biết điều gì đã xảy ra. Ví dụ: hết bộ nhớ, không có quyền truy cập hoặc cái gì khác.

Trong trường hợp của bạn, nếu chuỗi bằng nhau, thì không có lý do nào là lý do tại sao nó khác với các chuỗi chứa cùng một ký tự. Nhưng nếu chúng không bằng nhau thì đầu tiên có thể nhỏ hơn hoặc thứ hai có thể nhỏ hơn. Có nó trở lại 1 cho bằng nhau, 0 cho nhỏ hơn và 2 cho lớn hơn sẽ được bằng cách nào đó kỳ lạ tôi nghĩ.

Bạn cũng có thể suy nghĩ về nó trong điều kiện của phép trừ:

return = s1 - s2 

Nếu s1 là "thứ tự từ điển" ít hơn, sau đó nó sẽ cho là một giá trị âm.

+0

Tôi khá chắc chắn bạn cần phải dereference của bạn ... – dmckee

+0

tôi có nghĩa là nó tượng trưng là mã giả. –

+0

Ah. Tôi rút lại đề nghị. – dmckee

0

Tôi đoán nó chỉ đơn giản là đối xứng: -1 nếu ít hơn, 0 nếu bằng nhau, 1 nếu có.

10

Những điều tốt đẹp về một thực hiện như thế này là bạn có thể nói

if(strcmp(<stringA>, <stringB>) > 0) // Implies stringA > stringB 
if(strcmp(<stringA>, <stringB>) == 0) // Implies stringA == stringB 
if(strcmp(<stringA>, <stringB>) < 0) // Implies stringA < stringB 
if(strcmp(<stringA>, <stringB>) >= 0) // Implies stringA >= stringB 
if(strcmp(<stringA>, <stringB>) <= 0) // Implies stringA <= stringB 
if(strcmp(<stringA>, <stringB>) != 0) // Implies stringA != stringB 

Lưu ý như thế nào so với 0 trùng khớp với so sánh trong ngụ ý.

+1

Có một macro tuyệt vời/khủng khiếp từ câu hỏi thường gặp comp.lang.c thực hiện gần như chính xác hành vi chuỗi này. '#define StrTest (str1, op, str2) (strcmp (str1, str2) op 0)' Với nó, bạn sẽ viết 'if (StrTest (stringA, ==, stringB))' và bạn bè. Tôi đang ở trên hàng rào để xem đó là một ý tưởng khủng khiếp hay một ý tưởng tuyệt vời. –

2

Có ba kết quả có thể có: chuỗi 1 xuất hiện trước chuỗi 2, chuỗi 1 xuất hiện sau chuỗi 2, chuỗi 1 giống như chuỗi 2. Điều quan trọng là giữ riêng ba kết quả này; sử dụng strcmp() là sắp xếp các chuỗi. Câu hỏi đặt ra là cách bạn muốn gán giá trị cho ba kết quả này và cách giữ cho mọi thứ ngày càng ít phù hợp. Bạn cũng có thể xem xét các tham số cho qsort() và bsearch(), yêu cầu các hàm so sánh giống như strcmp().

Nếu bạn muốn một hàm bình đẳng chuỗi, nó sẽ trả về nonzero cho các chuỗi bằng nhau và bằng không cho các chuỗi không bằng nhau, để đi cùng với các quy tắc của C về đúng và sai. Điều này có nghĩa rằng sẽ không có cách nào để phân biệt chuỗi 1 đến trước hay sau chuỗi 2. Có nhiều giá trị thực cho một int, hoặc bất kỳ kiểu dữ liệu C nào khác mà bạn quan tâm, nhưng chỉ có một giá trị sai.

Do đó, việc có strcmp() trả về true cho chuỗi bình đẳng sẽ đòi hỏi nhiều thay đổi đối với phần còn lại của ngôn ngữ, điều đơn giản là sẽ không xảy ra.

4

Một lý do khác strcmp() trả về mã nó làm là để nó có thể được sử dụng trực tiếp trong hàm thư viện chuẩn qsort(), cho phép bạn sắp xếp một mảng của chuỗi:

#include <string.h> // for strcmp() 
#include <stdlib.h> // for qsort() 
#include <stdio.h> 

int sort_func(const void *a, const void *b) 
{ 
    const char **s1 = (const char **)a; 
    const char **s2 = (const char **)b; 
    return strcmp(*s1, *s2); 
} 

int main(int argc, char **argv) 
{ 
    int i; 
    printf("Pre-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    qsort((void *)(argv + 1), argc - 1, sizeof(char *), sort_func); 
    printf("Post-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    return 0; 
} 

chương trình mẫu nhỏ này phân loại đối số của nó ASCIIbetically (những gì một số sẽ gọi lexically). Lookie:

$ gcc -o sort sort.c 
$ ./sort hi there little fella 
Pre-sort: 
Argument 1 is hi 
Argument 2 is there 
Argument 3 is little 
Argument 4 is fella 
Post-sort: 
Argument 1 is fella 
Argument 2 is hi 
Argument 3 is little 
Argument 4 is there 

Nếu strcmp() trở 1 (true) cho chuỗi bình đẳng và 0 (false) cho những người thân inequal, nó sẽ không thể sử dụng nó để đạt được mức độ hoặc hướng của bất bình đẳng (ví dụ như thế nào khác nhau, và cái nào lớn hơn) giữa hai chuỗi, do đó làm cho nó không thể sử dụng nó như một hàm phân loại.

Tôi không biết bạn quen thuộc thế nào với C. Mã trên sử dụng một số khái niệm khó hiểu nhất của C - số học con trỏ, con trỏ recasting và con trỏ hàm - vì vậy nếu bạn không hiểu một số mã đó, don Đừng lo, bạn sẽ đến đó đúng giờ. Cho đến lúc đó, bạn sẽ có rất nhiều câu hỏi thú vị để hỏi về StackOverflow. ;)

Các vấn đề liên quan