C de neden "a"! = "A"?


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

Çıktı neden No, not equal?


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

47
Gömülü C derleyicileri void main () 'e izin verir çünkü bir dönüş kodu verecek herhangi bir işletim sistemi olmayabilir.
Jeanne Pindar

26
Böyle bir soru nasıl bu kadar sık ​​oylanabilir? Gerçekten o kadar ilginç değil ... Demek istediğim, dizeler dizilerdir ve diziler işaretçilerdir, gerçekten C'de eski bir şapka, değil mi?
Felix Dombek

64
@Felix, bu, dile yeni başlayanlar için ortak bir kafa karışıklığı noktasına hitap eden, kısaca yazılmış bir sorudur. SO sadece uzmanlar için değildir - yeni başlayanlar için de geçerlidir ve bunun gibi hedeflenmiş sorular gelecekte yeni başlayanlara yönlendirmek için iyidir.
bdonlan

37
@Felix: Yanılıyorsun. diziler işaretçi değildir
John Dibling

Yanıtlar:


209

Karşılaştırdığınız, farklı konumlarda saklanan farklı dizeler için iki bellek adresidir. Bunu yapmak esasen şuna benzer:

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

İki dize değerini karşılaştırmak için aşağıdaki kodu kullanın:

#include <string.h>

...

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

Ek olarak, "a" == "a"derleyicinize bağlı olarak gerçekten de true döndürebilir ve bu, derleme zamanında eşit dizeleri yer kazanmak için bir dizide birleştirebilir.

İki karakter değerini karşılaştırırken (işaretçi olmayanlar), bu sayısal bir karşılaştırmadır. Örneğin:

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

12
GCC da seçenekler vardır -fmerge-constantsve -fno-merge-constantsbazı GCC'lerde üzerinde o sürekli birleştirme bağımsız olarak her zaman bu seçeneğin etkin olduğunu görünmesine rağmen, etkinleştirmek / devre dışı bırakmak dize ve çeviri birimlerinde birleştirilmesi kayan nokta sabiti.
Adam Rosenfield

2
"A" yerine "a" kullanırsanız işe yarar. İlki, aslında sayısal bir değer olan bir karakterdir.
GolezTrol

@GolezTrol: C'de, 'a' harfi aslında inttüre sahiptir . :-) Ayrıca, işaretçilerin sayısal değerler olması gerekmez.
Bastien Léonard

intda sayısal, değil mi? Ama karakterlerin Byte olduğunu sanıyordum. Int, 4 bayttır. İşaretçilerin kendileri de tam sayıdır. Bir grup verinin adresini içerirler (gerçekten sayısal olması gerekmeyen veriler).
GolezTrol

'a' == 'A' // not true... MySQL farklı olmak için yalvarıyor.
Steven

52

Partiye biraz geç kaldım ama yine de cevaplayacağım; teknik olarak aynı bitler, ancak biraz farklı bir perspektiften (aşağıdaki C ifadesi):

C'de ifade "a", iki uzunluğunda statik adlandırılmamış bir dizi olan bir dize hazır bilgisini belirtir const char- dizi karakterlerden oluşur 'a've '\0'- sonlandırıcı boş karakter, dizenin sonunu belirtir.

Bununla birlikte, C'de, aynı şekilde dizileri işlevlere değere göre geçiremezsiniz - veya onlara değer atayamazsınız ( başlatmadan sonra ) - ==diziler için aşırı yüklenmiş bir operatör yoktur , bu nedenle onları doğrudan karşılaştırmak mümkün değildir. Düşünmek

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

Eğer == diziler karşılaştırma yapmadığı, aslında o zaman, ne yapar? C'de, hemen hemen tüm bağlamlarda - bu tek dahil - diziler işaretçilere (dizinin ilk öğesini işaret eden) bozulur ve eşitlik için işaretçileri karşılaştırmak beklediğinizi yapar. Çok etkili, bunu yaparken

"a" == "a"

aslında iki isimsiz dizideki ilk karakterlerin adreslerini karşılaştırıyorsunuz . C standardına göre, karşılaştırma doğru veya yanlış (yani 1 veya 0) sonucunu verebilir -"a" verebilir s gerçekte aynı diziyi veya iki tamamen ilgisiz diziyi gösterebilir. Teknik terimlerle, sonuçta elde edilen değer belirtilmemiştir , yani karşılaştırmaya izin verilir (yani, tanımlanmamış davranış veya sözdizimi hatası değildir), ancak her iki değer de geçerlidir ve uygulama (derleyiciniz) gerçekte ne olacağını belgelemek için gerekli değildir.

Başkalarının da belirttiği gibi, "c dizgilerini" (yani bir boş karakterle sonlandırılan dizeleri) karşılaştırmak için strcmpstandart başlık dosyasında bulunan kullanışlılık işlevini kullanırsınız string.h. İşlev, 0eşit dizeler için bir dönüş değerine sahiptir ; 0"! ´ operatörünü kullanmak yerine dönüş değerini açıkça karşılaştırmak iyi bir uygulama olarak kabul edilir , yani

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

47

C99'a göre (Bölüm 6.4.5 / 6)

Dize Değişmezleri

Elemanlarının uygun değerlere sahip olması koşuluyla, bu dizilerin farklı olup olmadığı belirtilmemiştir .

Dolayısıyla bu durumda, her ikisinin "a"de farklı olup olmadığı belirtilmemiştir . Optimize edilmiş bir derleyici, bir single'ı "a"salt okunur konumda tutabilir ve her iki referans da buna başvurabilir.

Gcc'deki çıktıya buradan göz atın


19

Çünkü bunlar 2 ayrı const char*işaretçi, gerçek değer yok. 0x019181217 == 0x0089178216Tabii ki HAYIR döndüren bir şey söylüyorsunuz

Yerine strcmp()kullanın==


7
Dize değişmezleri işaretçi değil, dizilerdir. Yine de karşılaştırma üzerine işaretlere dönüşüyorlar.
GManNickG

@Gman doğru, bu konuda gerçekten net olmadığım için üzgünüm, unutmaya meyilli :)
Antwan van Houdt

9

Basitçe ifade etmek gerekirse, C'nin yerleşik dize karşılaştırma operatörü yoktur. Dizeleri bu şekilde karşılaştıramaz.

Bunun yerine, dizeler strcmp () gibi standart kitaplık yordamları kullanılarak veya dizedeki her karakterde döngü yapmak için kod yazarak karşılaştırılır.

C'de, çift tırnak içindeki bir metin dizisi, dizeye bir işaretçi döndürür. Örneğiniz işaretçileri karşılaştırıyor ve görünüşe göre dizenin iki sürümü farklı adreslerde var.

Ama beklediğiniz gibi dizelerin kendilerini karşılaştırmıyor.


3

İşaretçiler.

İlk "a" , boş sonlandırılmış bir ASCII dizgesine bir göstericidir.

İkinci "a" , boş sonlandırılmış başka bir ASCII dizgesine bir göstericidir.

32 bitlik bir derleyici kullanıyorsanız, umarım "a"=="a"-4. Yine de tcc / Win32 ile denedim ve anladım "a"=="a"-2. Oh iyi...


6
Neden dizelerin 4 baytlık sınıra hizalanmasını bekliyorsunuz? İnts değiller. 2 beklediğim şeydir (derleyici onları birleştirmezse), çünkü her dizge boş sonlandırıcı da dahil olmak üzere iki bayt uzunluğundadır.
Sergei Tachenov

Örneğin bir dereceye kadar hizalama strcmp, bir seferde birkaç bayt çalıştırılmasına izin verebilir . Bazı derleyiciler bunu yapar, bazıları yapmaz, bazıları sadece minimumdan daha uzun dizeler için yapar ...
zwol

@Zack: Gerçekten karşılaştırmadan önce dizenin uzunluğunu nasıl bilebilirler?
Joachim Sauer

Demek istediğim, bazı derleyiciler dizeleri minimumdan daha uzun hizalar.
zwol

1

İki bellek adresini karşılaştırıyorsunuz, bu nedenle sonuç her zaman doğru olmayacak. Denedin if('a' == 'a'){...}mi


1

bu soru tüm yeni başlayanlar için çok iyi bir açıklama yolu oluşturuyor ....
ben de katkıda bulunayım .....

yukarıda herkesin açıkladığı gibi, neden bu kadar çıktı alıyorsunuz.

şimdi programınızı istiyorsanız. "Evet eşittir" yazdırmak için

ya kullan

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

}

veya
dizge olarak "a" kullanmayın, bunları karakter olarak kullanın ....

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

C karakterleri 1 bayt kısa tam sayıdır .......


Karakterler yalnızca 1 bayt kaplar, ancak gibi karakter değişmezleri 'a'aslında tamsayılardır.
Spidey

0

Bazı derleyiciler, tüm sabit dizeleri aynı adrese sahip olmaya zorlamak için kullanabileceğiniz 'dizeleri birleştirme' seçeneğine sahiptir. Eğer bunu kullanırsan, "a" == "a"olur true.


0

karakter arasındaki karşılaştırma her zaman tek tırnak içindeyse, örneğin

if('a' == 'a')

ve C gibi dize karşılaştırmasını destekleyemez "abc" == "abc"

İle bitti strcmp("abc","abc")


-5

Bu adam değişken kullanmıyor. Bunun yerine, geçici olarak metin dizileri kullanır: ave a. Sebebi ise

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

Tabii ki işe yaramıyor, değişkenleri karşılaştırmamanızdır.
Aşağıdaki gibi değişkenler oluşturmak isterseniz:

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

o zaman karşılaştırabilirsiniz textile text2ve olması gerektiği doğrudur

Belki Kullanmak unutmamalıyız {ve }) =

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

1
" Ve olması gerektiği doğrudur " - Hayır. Öyle belirtilmemiş dize hazır aynı belleğe kaydedilir olsun. Diğer cevapları okuyun.
Spikatrix
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.