Mengapa “a”! = “A” di C?

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

Mengapa hasilnya No, not equal?

Javed Akram
sumber
100
void main??? Ew ...
Paul R
47
Kompiler C yang disematkan mengizinkan void main () karena mungkin tidak ada sistem operasi yang dapat memberikan kode pengembalian.
Jeanne Pindar
26
Bagaimana pertanyaan seperti ini bisa mendapat suara positif begitu sering? Ini benar-benar tidak menarik ... Maksud saya, string adalah array dan array adalah pointer benar-benar topi lama di C, bukan?
Felix Dombek
64
@Felix, ini adalah pertanyaan yang ditulis secara singkat yang membahas titik kebingungan umum bagi pendatang baru di bahasa ini. SO tidak hanya untuk ahli - ini juga untuk pemula, dan pertanyaan bertarget seperti ini bagus untuk merujuk pemula di masa depan.
bdonlan
37
@Felix: Anda salah. array bukanlah penunjuk
John Dibling

Jawaban:

209

Yang Anda bandingkan adalah dua alamat memori untuk string berbeda, yang disimpan di lokasi berbeda. Melakukannya pada dasarnya terlihat seperti ini:

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

Gunakan kode berikut untuk membandingkan dua nilai string:

#include <string.h>

...

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

Selain itu, "a" == "a"mungkin memang mengembalikan true, tergantung pada kompiler Anda, yang dapat menggabungkan string yang sama pada waktu kompilasi menjadi satu untuk menghemat ruang.

Saat Anda membandingkan dua nilai karakter (yang bukan penunjuk), ini adalah perbandingan numerik. Sebagai contoh:

'a' == 'a' // always true
Tim Cooper
sumber
12
GCC juga memiliki opsi -fmerge-constantsdan -fno-merge-constantsuntuk mengaktifkan / menonaktifkan string dan penggabungan konstan floating-point di seluruh unit terjemahan, meskipun pada beberapa GCC tampaknya penggabungan konstan selalu diaktifkan terlepas dari opsi itu.
Adam Rosenfield
2
Ini akan berhasil jika Anda menggunakan 'a', bukan "a". Yang pertama adalah karakter, yang sebenarnya merupakan nilai numerik.
GolezTrol
@ GolezTrol: di C, literal 'a' sebenarnya memiliki inttipe. :-) Selain itu, pointer tidak harus berupa nilai numerik.
Bastien Léonard
intapakah numerik juga, bukan? Tapi saya pikir karakter itu Byte. Int adalah 4 byte. Pointer itu sendiri adalah bilangan bulat juga. Mereka berisi alamat sekumpulan data (data yang memang tidak harus numerik).
GolezTrol
'a' == 'A' // not true... MySQL sangat berbeda.
Steven
52

Saya agak terlambat ke pesta, tetapi saya akan tetap menjawab; secara teknis bit yang sama, tetapi dari perspektif yang sedikit berbeda (C bahasa di bawah):

Dalam C, ekspresi "a"menunjukkan literal string , yang merupakan array statis tanpa nama const char, dengan panjang dua - array terdiri dari karakter 'a'dan '\0'- karakter null yang mengakhiri menandakan akhir string.

Namun, di C, dengan cara yang sama Anda tidak bisa meneruskan array ke fungsi berdasarkan nilai - atau menetapkan nilai padanya ( setelah inisialisasi ) - tidak ada operator yang kelebihan beban ==untuk array, jadi tidak mungkin membandingkannya secara langsung. Mempertimbangkan

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

Jika ==tidak membandingkan array, lalu apa yang sebenarnya dilakukannya? Di C, di hampir semua konteks - termasuk yang satu ini - array meluruh menjadi pointer (yang mengarah ke elemen pertama dari array) - dan membandingkan pointer untuk persamaan melakukan apa yang Anda harapkan. Sangat efektif, saat melakukan ini

"a" == "a"

Anda sebenarnya membandingkan alamat karakter pertama dalam dua larik tanpa nama . Menurut standar C, perbandingan tersebut dapat menghasilkan benar atau salah (yaitu 1 atau 0) - "a"s sebenarnya dapat menunjukkan larik yang sama atau dua larik yang sama sekali tidak terkait. Dalam istilah teknis, nilai yang dihasilkan tidak ditentukan , artinya perbandingan diperbolehkan (yaitu bukan perilaku tidak terdefinisi atau kesalahan sintaksis), tetapi salah satu nilai tersebut valid dan implementasi (kompilator Anda) tidak diperlukan untuk mendokumentasikan apa yang sebenarnya akan terjadi.

Seperti yang telah ditunjukkan orang lain, untuk membandingkan "string c" (yaitu string yang diakhiri dengan karakter null) Anda menggunakan fungsi kemudahan yang strcmpditemukan di file header standar string.h. Fungsi tersebut memiliki nilai kembalian 0untuk string yang sama; dianggap praktik yang baik untuk secara eksplisit membandingkan nilai yang dikembalikan 0daripada menggunakan operator `! ´, yaitu

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

Menurut C99 (Bagian 6.4.5 / 6)

String Literals

Tidak ditentukan apakah array ini berbeda asalkan elemennya memiliki nilai yang sesuai .

Jadi dalam kasus ini tidak ditentukan apakah keduanya "a"berbeda. Kompiler yang dioptimalkan bisa menyimpan satu "a"di lokasi hanya-baca dan kedua referensi bisa merujuk ke sana.

Lihat hasilnya di gcc di sini

Prasoon Saurav
sumber
19

Karena keduanya terpisah const char*, pointer, tidak ada nilai aktual. Anda mengatakan sesuatu seperti 0x019181217 == 0x0089178216yang tentu saja mengembalikan TIDAK

Gunakan strcmp()sebagai ganti==

Antwan van Houdt
sumber
7
String literal bukanlah pointer, melainkan array. Namun, mereka membusuk menjadi petunjuk perbandingan.
GManNickG
@Gman benar, maaf karena tidak terlalu jelas tentang itu, cenderung melupakannya :)
Antwan van Houdt
9

Sederhananya, C tidak memiliki operator perbandingan string bawaan. Ini tidak dapat membandingkan string dengan cara ini.

Sebaliknya, string dibandingkan menggunakan rutinitas pustaka standar seperti strcmp () atau dengan menulis kode untuk mengulang setiap karakter dalam string.

Di C, string teks dalam tanda kutip ganda mengembalikan pointer ke string. Contoh Anda adalah membandingkan pointer, dan tampaknya kedua versi string Anda ada di alamat yang berbeda.

Tapi itu tidak membandingkan string itu sendiri, seperti yang Anda harapkan.

Jonathan Wood
sumber
3

Pointer.

Yang pertama "a"adalah penunjuk ke string ASCII yang diakhiri dengan null.

Yang kedua "a"adalah penunjuk ke string ASCII lain yang diakhiri dengan null.

Jika Anda menggunakan kompiler 32-bit, saya harapkan "a"=="a"-4. Saya baru saja mencobanya dengan tcc / Win32, dan saya mengerti "a"=="a"-2. Baiklah...

Nico57
sumber
6
Mengapa Anda mengharapkan string disejajarkan dengan batas 4 byte? Mereka bukan int. 2 adalah yang saya harapkan (jika kompilator tidak menggabungkannya), karena setiap string memiliki panjang dua byte, termasuk terminator null.
Sergei Tachenov
Beberapa derajat kesejajaran mungkin, misalnya, memungkinkan strcmpuntuk menjalankan beberapa byte sekaligus. Beberapa kompiler melakukannya, beberapa tidak, beberapa melakukannya hanya untuk string yang lebih panjang dari beberapa minimum ...
zwol
@ Zack: bagaimana mereka mengetahui panjang string sebelum benar-benar membandingkannya?
Joachim Sauer
Maksud saya, beberapa kompiler menyelaraskan string lebih lama dari beberapa minimum.
zwol
1

Anda membandingkan dua alamat memori, jadi hasilnya tidak selalu benar. Apakah kamu sudah mencobanya if('a' == 'a'){...}?

SK9
sumber
1

pertanyaan ini menetapkan jejak penjelasan yang sangat baik untuk semua pemula ....
izinkan saya juga berkontribusi untuk itu .....

seperti yang dijelaskan semua orang di atas, mengapa Anda mendapatkan keluaran seperti itu.

sekarang jika Anda menginginkan prog Anda. Untuk mencetak "ya sama" lalu

baik digunakan

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

}

atau
jangan gunakan "a" sebagai string, gunakan sebagai karakter ....

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

dalam karakter C adalah 1 byte bilangan bulat pendek .......

T-JOY
sumber
Karakter hanya menempati 1 byte, tetapi literal karakter, seperti 'a', sebenarnya adalah bilangan bulat.
Spidey
0

Beberapa kompiler memiliki opsi 'merge string' yang dapat Anda gunakan untuk memaksa semua string konstan memiliki alamat yang sama. Jika Anda akan menggunakan itu, "a" == "a"akan true.

Daniel Mošmondor
sumber
0

jika perbandingan antar karakter selalu dalam satu kutipan, mis

if('a' == 'a')

dan C tidak dapat mendukung perbandingan string seperti "abc" == "abc"

Selesai dengan strcmp("abc","abc")

Bhavin Patel
sumber
-5

Orang ini tidak menggunakan variabel. Sebagai gantinya, dia menggunakan larik teks sementara: adan a. Alasan mengapa

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

tidak bekerja tentu saja, adalah bahwa Anda tidak membandingkan variabel.
Jika Anda ingin membuat variabel seperti:

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

maka Anda bisa membandingkan textdengan text2, dan itu harus benar

Mungkin Anda tidak boleh lupa menggunakan {dan }=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}
D. Ace
sumber
1
" dan itu harus benar " - Tidak. Tidak ditentukan apakah literal string akan disimpan di lokasi memori yang sama. Baca jawaban lainnya.
Spikatrix