Tại sao “a”! = “A” trong C?


110
void main() {
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

Tại sao lại là đầu ra No, not equal?


100
void main??? Ew ...
Paul R

47
Các trình biên dịch C nhúng cho phép void main () vì có thể không có bất kỳ hệ điều hành nào cung cấp mã trả về.
Jeanne Pindar

26
Làm thế nào một câu hỏi như thế này có thể được ủng hộ thường xuyên như vậy? Nó thực sự không thú vị cho lắm ... Ý tôi là, chuỗi là mảng và mảng là con trỏ thực sự là một cái mũ cũ trong C, phải không?
Felix Dombek,

64
@Felix, đó là một câu hỏi được viết ngắn gọn giải quyết điểm nhầm lẫn phổ biến cho những người mới sử dụng ngôn ngữ này. SO không chỉ dành cho các chuyên gia - nó cũng dành cho người mới bắt đầu và những câu hỏi được nhắm mục tiêu như thế này rất tốt cho việc giới thiệu những người mới bắt đầu trong tương lai.
bdonlan

37
@Felix: Bạn nhầm rồi. mảng không phải là con trỏ
John Dibling

Câu trả lời:


209

Những gì bạn đang so sánh là hai địa chỉ bộ nhớ cho các chuỗi khác nhau, được lưu trữ ở các vị trí khác nhau. Làm như vậy về cơ bản trông giống như sau:

if(0x00403064 == 0x002D316A) // Two memory locations
{
    printf("Yes, equal");
}

Sử dụng mã sau để so sánh hai giá trị chuỗi:

#include <string.h>

...

if(strcmp("a", "a") == 0)
{
    // Equal
}

Ngoài ra, "a" == "a"có thể thực sự trả về true, tùy thuộc vào trình biên dịch của bạn, có thể kết hợp các chuỗi bằng nhau tại thời điểm biên dịch thành một để tiết kiệm dung lượng.

Khi bạn so sánh hai giá trị ký tự (không phải là con trỏ), đó là một so sánh số. Ví dụ:

'a' == 'a' // always true

12
GCC cũng có các tùy chọn -fmerge-constants-fno-merge-constantsđể bật / tắt hợp nhất chuỗi và dấu phẩy động liên tục giữa các đơn vị dịch, mặc dù trên một số GCC, có vẻ như tính năng hợp nhất liên tục luôn được bật bất kể tùy chọn đó.
Adam Rosenfield

2
Nó sẽ hoạt động nếu bạn sử dụng 'a' thay vì "a". Đầu tiên là một ký tự, thực sự là một giá trị số.
GolezTrol

@GolezTrol: trong C, chữ 'a' thực sự có intkiểu. :-) Ngoài ra, con trỏ không cần phải là giá trị số.
Bastien Léonard

intcũng là số phải không? Nhưng tôi nghĩ ký tự là Byte. Int là 4 byte. Bản thân con trỏ cũng là số nguyên. Chúng chứa địa chỉ của một loạt dữ liệu (dữ liệu thực sự không cần phải là số).
GolezTrol

'a' == 'A' // not true... MySQL yêu cầu sự khác biệt.
Steven

52

Tôi đến bữa tiệc hơi muộn, nhưng dù sao thì tôi cũng sẽ trả lời; về mặt kỹ thuật là các bit giống nhau, nhưng từ góc độ khác một chút (cách nói của C bên dưới):

Trong C, biểu thức biểu "a"thị một chuỗi ký tự , là một mảng tĩnh không có tên const char, với độ dài là hai - mảng bao gồm các ký tự 'a''\0'- ký tự rỗng kết thúc báo hiệu sự kết thúc của chuỗi.

Tuy nhiên, trong C, theo cách tương tự, bạn không thể truyền mảng cho các hàm theo giá trị - hoặc gán giá trị cho chúng ( sau khi khởi tạo ) - không có toán tử nạp chồng ==cho mảng, vì vậy không thể so sánh chúng trực tiếp. Xem xét

int a1[] = {1, 2, 3};
int a2[] = {3, 4, 5};
a1 == a2 // is this meaningful? Yes and no; it *does* compare the arrays for
         // "identity", but not for their values. In this case the result
         // is always false, because the arrays (a1 and a2) are distinct objects

Nếu ==không phải là so sánh các mảng, thì nó thực sự làm gì? Trong C, trong hầu hết các ngữ cảnh - bao gồm cả ngữ cảnh này - các mảng phân rã thành các con trỏ (trỏ đến phần tử đầu tiên của mảng) - và việc so sánh các con trỏ để bình đẳng thực hiện những gì bạn mong đợi. Vì vậy, hiệu quả, khi làm điều này

"a" == "a"

bạn thực sự đang so sánh địa chỉ của các ký tự đầu tiên trong hai mảng không có tên . Theo tiêu chuẩn C, phép so sánh có thể mang lại kết quả đúng hoặc sai (tức là 1 hoặc 0) - "a"s thực sự có thể biểu thị cùng một mảng hoặc hai mảng hoàn toàn không liên quan. Về mặt kỹ thuật, giá trị kết quả là không xác định , có nghĩa là phép so sánh được phép (tức là nó không phải là hành vi không xác định hoặc lỗi cú pháp), nhưng một trong hai giá trị là hợp lệ và việc triển khai (trình biên dịch của bạn) không bắt buộc phải ghi lại những gì sẽ thực sự xảy ra.

Như những người khác đã chỉ ra, để so sánh "chuỗi c" (nghĩa là các chuỗi được kết thúc bằng ký tự rỗng), bạn sử dụng hàm tiện lợi strcmpđược tìm thấy trong tệp tiêu đề chuẩn string.h. Hàm có giá trị trả về 0cho các chuỗi bằng nhau; nó được coi là phương pháp hay để so sánh rõ ràng giá trị trả về 0thay vì sử dụng toán tử `! ´, tức là

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)

47

Theo C99 (Mục 6.4.5 / 6)

String Literals

Không xác định được liệu các mảng này có khác biệt hay không miễn là các phần tử của chúng có các giá trị thích hợp .

Vì vậy, trong trường hợp này, không xác định được liệu cả hai "a"s có khác biệt hay không. Một trình biên dịch được tối ưu hóa có thể giữ một"a" ở vị trí chỉ đọc và cả hai tham chiếu đều có thể tham chiếu đến điều đó.

Kiểm tra đầu ra trên gcc tại đây


19

Vì chúng là 2 const char*con trỏ riêng biệt , không có giá trị thực. Bạn đang nói điều gì đó như0x019181217 == 0x0089178216 tất nhiên trả về KHÔNG

Sử dụng strcmp()thay vì==


7
Chuỗi ký tự không phải là con trỏ, chúng là mảng. Tuy nhiên, chúng phân rã thành các con trỏ so sánh.
GManNickG

@Gman đúng, xin lỗi vì đã không thực sự rõ ràng trên đó, có xu hướng quên nó :)
Antwan van Houdt

9

Nói một cách đơn giản, C không có toán tử so sánh chuỗi tích hợp sẵn. Nó không thể so sánh các chuỗi theo cách này.

Thay vào đó, các chuỗi được so sánh bằng cách sử dụng các thủ tục thư viện tiêu chuẩn như strcmp () hoặc bằng cách viết mã để lặp qua từng ký tự trong chuỗi.

Trong C, một chuỗi văn bản trong dấu ngoặc kép trả về một con trỏ đến chuỗi. Ví dụ của bạn là so sánh các con trỏ và dường như hai phiên bản chuỗi của bạn tồn tại ở các địa chỉ khác nhau.

Nhưng nó không phải là so sánh các chuỗi, như bạn có vẻ mong đợi.


3

Con trỏ.

Đầu tiên "a"là một con trỏ đến một chuỗi ASCII kết thúc bằng null.

Thứ hai "a"là một con trỏ đến một chuỗi ASCII được kết thúc bằng null.

Nếu bạn đang sử dụng trình biên dịch 32-bit, tôi mong đợi "a"=="a"-4. Tuy nhiên, tôi vừa thử nó với tcc / Win32 và tôi nhận được "a"=="a"-2. Mà thôi ...


6
Tại sao bạn mong đợi các chuỗi được căn chỉnh theo ranh giới 4 byte? Chúng không phải là ints. 2 là những gì tôi mong đợi (nếu trình biên dịch không hợp nhất chúng), vì mỗi chuỗi dài hai byte, bao gồm cả dấu chấm dứt rỗng.
Sergei Tachenov

Ví dụ, một số mức độ căn chỉnh có thể cho phép strcmpchạy nhiều byte cùng một lúc. Một số trình biên dịch làm điều đó, một số không, một số làm điều đó chỉ cho các chuỗi dài hơn một số tối thiểu ...
Zwol

@Zack: làm sao họ biết được độ dài của chuỗi trước khi thực sự so sánh chúng?
Joachim Sauer,

Ý tôi là, một số trình biên dịch căn chỉnh các chuỗi dài hơn một số mức tối thiểu.
zwol

1

Bạn đang so sánh hai địa chỉ bộ nhớ, vì vậy kết quả không phải lúc nào cũng đúng. Bạn đã thử if('a' == 'a'){...}?


1

câu hỏi này đặt ra một dấu vết giải thích rất tốt cho tất cả những người cầu xin ....
hãy để tôi cũng đóng góp cho nó .....

như mọi người ở trên đã giải thích về lý do tại sao bạn nhận được đầu ra như vậy.

bây giờ nếu bạn muốn prog của bạn. Để in "có bằng" thì

hoặc sử dụng

if(strcmp("a", "a") == 0)
{

}

hoặc
không sử dụng "a" làm chuỗi, sử dụng chúng như ký tự….

if('a'=='a')  
{  
printf ("yes Equal");  
}  

ký tự trong C là số nguyên ngắn 1 byte .......


Các ký tự chỉ chiếm 1 byte, nhưng các ký tự, chẳng hạn như 'a', thực sự là số nguyên.
Spidey

0

Một số trình biên dịch có tùy chọn 'hợp nhất chuỗi' mà bạn có thể sử dụng để buộc tất cả các chuỗi không đổi có cùng địa chỉ. Nếu bạn muốn sử dụng nó, "a" == "a"sẽ là true.


0

nếu so sánh giữa các ký tự luôn ở trong một câu trích dẫn, ví dụ:

if('a' == 'a')

và C không thể hỗ trợ so sánh chuỗi như "abc" == "abc"

Nó được thực hiện với strcmp("abc","abc")


-5

Anh chàng này không sử dụng các biến. Thay vào đó, anh ấy sử dụng tạm thời các mảng văn bản: aa. Lý do tại sao

void main() 
{
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

tất nhiên không hoạt động, là bạn không so sánh các biến.
Nếu bạn muốn tạo các biến như:

char * text = "a";
char * text2 = "a";

thì bạn có thể so sánh textvới text2, và nó phải đúng

Có lẽ bạn không nên quên sử dụng {}=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}

1
" and it should be true " - Không. Không xác định được liệu chuỗi ký tự có được lưu trong cùng một vị trí bộ nhớ hay không. Đọc các câu trả lời khác.
Spikatrix
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.