Wbudowane kompilatory C zezwalają na void main (), ponieważ może nie istnieć żaden system operacyjny, któremu można by podać kod powrotu.
Jeanne Pindar
26
Jak to możliwe, że takie pytanie jest tak często brane pod uwagę? To naprawdę nie jest takie interesujące ... Mam na myśli to, że łańcuchy to tablice, a tablice to wskaźniki, to naprawdę stara czapka w C, prawda?
Felix Dombek
64
@Felix, to zwięźle napisane pytanie, które dotyczy częstego zamieszania wśród nowicjuszy w tym języku. SO nie jest tylko dla ekspertów - jest również dla początkujących, a ukierunkowane pytania, takie jak to, są dobre do odniesienia się do początkujących w przyszłości.
bdonlan,
37
@Felix: Mylisz się. tablice nie są wskaźnikami
John Dibling
Odpowiedzi:
209
Porównujesz dwa adresy pamięci dla różnych ciągów, które są przechowywane w różnych lokalizacjach. Zasadniczo wygląda to następująco:
if(0x00403064==0x002D316A)// Two memory locations{
printf("Yes, equal");}
Użyj poniższego kodu, aby porównać dwie wartości ciągów:
Ponadto "a" == "a"może rzeczywiście zwrócić wartość true, w zależności od kompilatora, który może łączyć równe ciągi w czasie kompilacji w jeden, aby zaoszczędzić miejsce.
Kiedy porównujesz dwie wartości znakowe (które nie są wskaźnikami), jest to porównanie liczbowe. Na przykład:
GCC posiada również opcje -fmerge-constantsi -fno-merge-constantswłączyć / wyłączyć ciąg i zmiennoprzecinkowej stałej łączących w poprzek jednostek tłumaczeniowych, choć na niektórych GCCs wydaje się, że stała łączenie jest zawsze włączony, niezależnie od wybranej opcji.
Adam Rosenfield,
2
To zadziała, jeśli użyjesz „a” zamiast „a”. Pierwsza to znak, który w rzeczywistości jest wartością liczbową.
GolezTrol
@GolezTrol: w C dosłowne „a” ma inttyp. :-) Ponadto wskaźniki nie muszą być wartościami liczbowymi.
Bastien Léonard
intjest też numeryczny, prawda? Ale myślałem, że znaki to bajty. Int to 4 bajty. Same wskaźniki również są liczbami całkowitymi. Zawierają adres zbioru danych (danych, które rzeczywiście nie muszą być numeryczne).
GolezTrol
'a' == 'A' // not true... MySQL ma inne zdanie.
Steven
52
Trochę spóźniłem się na przyjęcie, ale i tak odpowiem; technicznie te same bity, ale z nieco innej perspektywy (język C poniżej):
W języku C wyrażenie "a"oznacza literał łańcuchowy , który jest statyczną nienazwaną tablicą o const chardługości dwóch - tablica składa się ze znaków 'a'i'\0' - kończący znak null sygnalizuje koniec ciągu.
Jednak w C w ten sam sposób nie można przekazywać tablic do funkcji według wartości - ani przypisywać do nich wartości ( po inicjalizacji ) - nie ma przeciążonego operatora ==dla tablic, więc nie jest możliwe ich bezpośrednie porównanie. Rozważać
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
Jeśli narzędzie ==nie porównuje tablic, to co właściwie robi? W C prawie we wszystkich kontekstach - w tym w tym - tablice rozpadają się na wskaźniki (które wskazują na pierwszy element tablicy) - a porównywanie wskaźników równości robi to, czego można się spodziewać. Tak skutecznie, kiedy to robisz
"a"=="a"
faktycznie porównujesz adresy pierwszych znaków w dwóch nienazwanych tablicach . Zgodnie ze standardem C, porównanie może dać prawdę lub fałsz (tj. 1 lub 0) - "a"s mogą w rzeczywistości oznaczać tę samą tablicę lub dwie zupełnie niepowiązane tablice. Z technicznego punktu widzenia wynikowa wartość jest nieokreślona , co oznacza, że porównanie jest dozwolone (tj. Nie jest to niezdefiniowane zachowanie ani błąd składniowy), ale żadna z wartości jest prawidłowa, a implementacja (Twój kompilator) nie jest wymagana do udokumentowania tego, co faktycznie się wydarzy.
Jak zauważyli inni, aby porównać „łańcuchy c” (tj. Łańcuchy zakończone znakiem null), należy skorzystać z wygodnej funkcji strcmpznajdującej się w standardowym pliku nagłówkowym string.h. Funkcja zwraca wartość 0równych ciągów; za dobrą praktykę uważa się jawne porównywanie zwracanej wartości 0zamiast używania operatora `! ´, tj
strcmp(str1, str2)==0// instead of !strcmp(str1, str2)
Nie jest określone, czy te tablice są różne, pod warunkiem, że ich elementy mają odpowiednie wartości .
W tym przypadku nie jest określone, czy oba "a"są różne. Zoptymalizowany kompilator może przechowywać pojedynczy plik "a"w lokalizacji tylko do odczytu i oba odwołania mogą się do tego odnosić.
Literały łańcuchowe nie są wskaźnikami, są tablicami. Jednak w porównaniu rozpadają się do wskaźników.
GManNickG,
@Gman prawda, przepraszam, że nie jestem tego pewien, zwykle o tym zapominam :)
Antwan van Houdt
9
Mówiąc najprościej, C nie ma wbudowanego operatora porównania ciągów. W ten sposób nie może porównywać łańcuchów.
Zamiast tego, łańcuchy są porównywane przy użyciu standardowych procedur bibliotecznych, takich jak strcmp (), lub przez pisanie kodu w celu wykonania pętli przez każdy znak w ciągu.
W języku C ciąg tekstu w cudzysłowach zwraca wskaźnik do ciągu. Twój przykład to porównanie wskaźników i najwyraźniej twoje dwie wersje ciągu istnieją pod różnymi adresami.
Ale nie jest to porównywanie samych strun, jak można się spodziewać.
Dlaczego miałbyś oczekiwać, że łańcuchy będą wyrównane do 4-bajtowej granicy? Nie są intersami. 2 jest tym, czego bym się spodziewał (jeśli kompilator ich nie połączy), ponieważ każdy ciąg ma długość dwóch bajtów, łącznie z terminatorem null.
Siergiej Tachenov
Pewien stopień dopasowania może na przykład pozwolić strcmpna uruchamianie kilku bajtów jednocześnie. Niektórzy kompilatorzy to robią, niektórzy nie, niektórzy robią to tylko dla stringów dłuższych niż jakieś minimum ...
zwolnij
@Zack: skąd mieliby znać długość łańcucha, zanim faktycznie je porównają?
Joachim Sauer
Miałem na myśli, że niektóre kompilatory wyrównują ciągi dłuższe niż jakieś minimum.
zwol
1
Porównujesz dwa adresy pamięci, więc wynik nie zawsze będzie prawdziwy. Próbowałeś if('a' == 'a'){...}?
Znaki zajmują tylko 1 bajt, ale literały znaków, takie jak 'a', są w rzeczywistości liczbami całkowitymi.
Spidey
0
Niektóre kompilatory mają opcję „merge strings”, której można użyć do wymuszenia, aby wszystkie stałe ciągi miały ten sam adres. Gdybyś tego użył, "a" == "a"byłby true.
" i tak powinno być prawdą ” - Nie. Nie jest określone, czy literały łańcuchowe będą przechowywane w tej samej lokalizacji pamięci. Przeczytaj pozostałe odpowiedzi.
void main
??? Ew ...Odpowiedzi:
Porównujesz dwa adresy pamięci dla różnych ciągów, które są przechowywane w różnych lokalizacjach. Zasadniczo wygląda to następująco:
Użyj poniższego kodu, aby porównać dwie wartości ciągów:
Ponadto
"a" == "a"
może rzeczywiście zwrócić wartość true, w zależności od kompilatora, który może łączyć równe ciągi w czasie kompilacji w jeden, aby zaoszczędzić miejsce.Kiedy porównujesz dwie wartości znakowe (które nie są wskaźnikami), jest to porównanie liczbowe. Na przykład:
źródło
-fmerge-constants
i-fno-merge-constants
włączyć / wyłączyć ciąg i zmiennoprzecinkowej stałej łączących w poprzek jednostek tłumaczeniowych, choć na niektórych GCCs wydaje się, że stała łączenie jest zawsze włączony, niezależnie od wybranej opcji.int
typ. :-) Ponadto wskaźniki nie muszą być wartościami liczbowymi.int
jest też numeryczny, prawda? Ale myślałem, że znaki to bajty. Int to 4 bajty. Same wskaźniki również są liczbami całkowitymi. Zawierają adres zbioru danych (danych, które rzeczywiście nie muszą być numeryczne).'a' == 'A' // not true
... MySQL ma inne zdanie.Trochę spóźniłem się na przyjęcie, ale i tak odpowiem; technicznie te same bity, ale z nieco innej perspektywy (język C poniżej):
W języku C wyrażenie
"a"
oznacza literał łańcuchowy , który jest statyczną nienazwaną tablicą oconst char
długości dwóch - tablica składa się ze znaków'a'
i'\0'
- kończący znak null sygnalizuje koniec ciągu.Jednak w C w ten sam sposób nie można przekazywać tablic do funkcji według wartości - ani przypisywać do nich wartości ( po inicjalizacji ) - nie ma przeciążonego operatora
==
dla tablic, więc nie jest możliwe ich bezpośrednie porównanie. RozważaćJeśli narzędzie
==
nie porównuje tablic, to co właściwie robi? W C prawie we wszystkich kontekstach - w tym w tym - tablice rozpadają się na wskaźniki (które wskazują na pierwszy element tablicy) - a porównywanie wskaźników równości robi to, czego można się spodziewać. Tak skutecznie, kiedy to robiszfaktycznie porównujesz adresy pierwszych znaków w dwóch nienazwanych tablicach . Zgodnie ze standardem C, porównanie może dać prawdę lub fałsz (tj. 1 lub 0) -
"a"
s mogą w rzeczywistości oznaczać tę samą tablicę lub dwie zupełnie niepowiązane tablice. Z technicznego punktu widzenia wynikowa wartość jest nieokreślona , co oznacza, że porównanie jest dozwolone (tj. Nie jest to niezdefiniowane zachowanie ani błąd składniowy), ale żadna z wartości jest prawidłowa, a implementacja (Twój kompilator) nie jest wymagana do udokumentowania tego, co faktycznie się wydarzy.Jak zauważyli inni, aby porównać „łańcuchy c” (tj. Łańcuchy zakończone znakiem null), należy skorzystać z wygodnej funkcji
strcmp
znajdującej się w standardowym pliku nagłówkowymstring.h
. Funkcja zwraca wartość0
równych ciągów; za dobrą praktykę uważa się jawne porównywanie zwracanej wartości0
zamiast używania operatora `! ´, tjźródło
Zgodnie z C99 (sekcja 6.4.5 / 6)
W tym przypadku nie jest określone, czy oba
"a"
są różne. Zoptymalizowany kompilator może przechowywać pojedynczy plik"a"
w lokalizacji tylko do odczytu i oba odwołania mogą się do tego odnosić.Sprawdź wyjście na gcc tutaj
źródło
Ponieważ są to 2 oddzielne
const char*
wskaźniki, brak rzeczywistych wartości. Mówisz coś takiego,0x019181217 == 0x0089178216
co oczywiście zwraca NIEUżyj
strcmp()
zamiast==
źródło
Mówiąc najprościej, C nie ma wbudowanego operatora porównania ciągów. W ten sposób nie może porównywać łańcuchów.
Zamiast tego, łańcuchy są porównywane przy użyciu standardowych procedur bibliotecznych, takich jak strcmp (), lub przez pisanie kodu w celu wykonania pętli przez każdy znak w ciągu.
W języku C ciąg tekstu w cudzysłowach zwraca wskaźnik do ciągu. Twój przykład to porównanie wskaźników i najwyraźniej twoje dwie wersje ciągu istnieją pod różnymi adresami.
Ale nie jest to porównywanie samych strun, jak można się spodziewać.
źródło
Wskaźniki.
Pierwsza
"a"
to wskaźnik do łańcucha ASCII zakończonego znakiem null.Drugi
"a"
to wskaźnik do innego łańcucha ASCII zakończonego znakiem null.Jeśli używasz kompilatora 32-bitowego, spodziewałbym się
"a"=="a"-4
. Jednak właśnie wypróbowałem to z tcc / Win32 i otrzymałem"a"=="a"-2
. No cóż...źródło
strcmp
na uruchamianie kilku bajtów jednocześnie. Niektórzy kompilatorzy to robią, niektórzy nie, niektórzy robią to tylko dla stringów dłuższych niż jakieś minimum ...Porównujesz dwa adresy pamięci, więc wynik nie zawsze będzie prawdziwy. Próbowałeś
if('a' == 'a'){...}
?źródło
to pytanie wyznacza bardzo dobrą ścieżkę wyjaśnień dla wszystkich początkujących ...
pozwólcie, że się do tego przyczynię .....
jak wszyscy powyżej wyjaśniali, dlaczego otrzymujesz takie wyjście.
teraz, jeśli chcesz swojego prog. Aby wydrukować „tak równe”
albo użyj
lub
nie używaj „a” jako łańcuchów, użyj ich jako znaków ....
w znakach C to 1-bajtowa krótka liczba całkowita .......
źródło
'a'
, są w rzeczywistości liczbami całkowitymi.Niektóre kompilatory mają opcję „merge strings”, której można użyć do wymuszenia, aby wszystkie stałe ciągi miały ten sam adres. Gdybyś tego użył,
"a" == "a"
byłbytrue
.źródło
jeśli porównanie między znakami jest zawsze w pojedynczym cudzysłowie, np
a C nie obsługuje porównywania ciągów, takich jak
"abc" == "abc"
Zrobione
strcmp("abc","abc")
źródło
Ten facet nie używa zmiennych. Zamiast tego używa tymczasowo tablic tekstowych:
a
ia
. Powód dlaczegooczywiście nie działa, to że nie porównujesz zmiennych.
Jeśli tworzysz zmienne takie jak:
następnie można porównać
text
ztext2
, i powinno to być prawdąMoże nie powinieneś zapomnieć o użyciu
{
i}
=)źródło