2015-10-12 22 views
20

Chociaż byłem łącząc funkcję do-wielkie litery w C++ I zauważyłem, że nie otrzymał oczekiwanego wyjście w CC ciąg na duże litery w C i C++

funkcję

C++

#include <iostream> 
#include <cctype> 
#include <cstdio> 

void strupp(char* beg) 
{ 
    while (*beg++ = std::toupper(*beg)); 
} 

int main(int charc, char* argv[]) 
{ 
    char a[] = "foobar"; 
    strupp(a); 
    printf("%s\n", a); 
    return 0; 
} 

wyjściowe, jak oczekiwano

FOOBAR 


C funkcja

#include <ctype.h> 
#include <stdio.h> 
#include <string.h> 

void strupp(char* beg) 
{ 
    while (*beg++ = toupper(*beg)); 
} 

int main(int charc, char* argv[]) 
{ 
    char a[] = "foobar"; 
    strupp(a); 
    printf("%s\n", a); 
    return 0; 
} 

Wyjście jest oczekiwany wynik z pierwszego znaku brakującego

OOBAR 

Czy ktoś wie dlaczego wynik zostanie obcięty podczas kompilacji w C?

+5

A jeśli naprawdę chciałeś to zrobić w 'C++': 'std :: transform (a, a + strlen (a), a, std :: toupper); ' – PaulMcKenzie

+0

Czy możesz wyjaśnić, dlaczego spodziewałeś się przekształcenia ciągu w wielkie litery? W szczególności, dlaczego spodziewałeś się, że prawy bok '=' zostanie oceniony przed lewym? –

+0

Jestem wdzięczny wszystkim, którzy przekazali informacje zwrotne i za cenne informacje dostarczone –

Odpowiedz

29

Problemem jest to, że nie ma sensu sekwencja w

while (*beg++ = toupper(*beg)); 

Mamy więc niezdefiniowane zachowanie. W tym przypadku kompilator dokonuje oceny beg++ przed toupper(*beg) w C, gdzie w C++ robi to w inny sposób.

+0

Czy to oznacza, że ​​klasyczne kopiowanie jednolinijkowego 'while (* s ++ = * t ++);' ma niezdefiniowane zachowanie? –

+3

@markh Nie, ponieważ są to dwie różne zmienne. To jest synonimem 'while (* s ++ = * s ++)' – NathanOliver

+0

@SteveJessop Właściwie 'while (* s ++ = * t ++);' ma zdefiniowane zachowanie, nawet jeśli 's == t'. Powód 'strcpy' jest niezdefiniowany z nakładającymi się regionami, że' strcpy' niekoniecznie jest implementowany z 'while (* s ++ = * t ++);'. – immibis

15
while (*beg++ = std::toupper(*beg)); 

prowadzi do niezdefiniowanego zachowania.

To, czy *beg++ jest sekwencjonowany przed czy po std::toupper(*beg), jest nieokreślone.

Prostym rozwiązaniem jest użyć:

while (*beg = std::toupper(*beg)) 
    ++beg; 
10

Linia

while (*beg++ = toupper(*beg)); 

zawiera efekt uboczny na podmiot, który jest używany dwa razy. Nie możesz wiedzieć, czy ++ jest wykonywane przed czy po * beg (wewnątrz toupera). Masz szczęście, że obie implementacje pokazują oba zachowania, ponieważ jestem prawie pewien, że jest taki sam dla C++. (Jednak istniały pewne zmiany przepisów dla C++ 11, których nie jestem pewny - nadal jest to zły styl.)

Wystarczy przesunąć BEG ++ z warunku:

while (*beg = toupper(*beg)) beg++; 
3

z w odniesieniu do powyższej odpowiedzi, "f" nigdy nie jest przekazywane do funkcji, powinieneś spróbować użyć tego:

 while ((*beg = (char) toupper(*beg))) beg++; 
+0

Rzucanie na char było ważne, ponieważ wartość typu int może nie pasować do typu odbiornika char – vishal

+1

Ten rzut nie osiąga niczego, co nie byłoby możliwe bez tego. – Flexo