Zamiana małej litery na wielką i na odwrót

0

Cześć Wszystkim! :)

Żeby nie było, na starcie informuje, że jestem dopiero początkującym :p
Otóż dla zabawy zrobiłem program, który tak jak temat wskazuje zamienia małe litery na wielkie i na odwrót. Do tego jeżeli spotka liczbę to ją ignoruje i wstawia pusty znak w to miejsce. Program wygląda tak:

#include <iostream>
#include <cctype>

using namespace std;

int main()
{
    char ch;
    cout << "Wprowadz zdanie, @ konczy program." << endl;
    cin.get(ch);

    while (ch!='@')
    {
    if (isdigit(ch) == true)
      ch = NULL;
    else if (isupper(ch) == true)
      ch = tolower(ch);
    else if (islower(ch) != false)
      ch = toupper(ch);

       cout << ch;
       cin.get(ch);
    }

    return 0;
}
 

Oczywiście cała zabawa zawarta jest w pętli. Otóż nie wiem dlaczego, ale w trzecim if:

 else if (islower(ch) != false)
      ch = toupper(ch); 

jak dałem warunek (islower(ch) == true), to program źle działał, tzn. nie zamieniał z mniejszych na większe. Dlaczego? Czym się różni != false od == true? Przecież jak coś jest różne od false, to oznacza, że jest to true, tak? :P Przynajmniej tak mi się wydaje.

0

@up
Wątpię aby C++ generował błędy. To raczej moja wina, a nie C++ :P

Już to chyba rozumiem, tzn.
if(funkcja()==true) nie oznacza to samo, co if(funkcja()!=false).

Oraz

islower
Return Value
A value different from zero (i.e., true) if indeed c is a

Program nie działał z == true, bo w tym przypadku funkcja zwracała 2, a nie true (1), jednak jest to nadal zgodne z "different from zero".
To chyba tyle :)

Aha i co do:

Używanie C++ w przypadku swapcase to jak strzelanie z armaty do muchy.
,
To nie było tak, że zobaczyłem to zadanie i postanowiłem, że zrobię je w C++, tylko to jedyny język którego się uczę :D Zostałem skazany na niego :)

2

Do tego zadania możesz wykorzystać popularny idiom !!: http://ideone.com/ysKnpK
Plus nie warto pisać if (funkcja() == true), ponieważ to jest to samo, co if (funkcja()) (podobnie jak if (funkcja() == false) jest tym samym co if (!funkcja())).

3
  1. Nie jest gwarantowane że islower() zwróci 1 w przypadku małej litery, może zwrócić np 17.
  2. Poczytaj czym jest NULL, w znak wpisujesz wskaźnik, WTF?
  3. isdigit(ch) zwraca typ logiczny, ale nie możemy napisać if(isdigit(ch)) ponieważ trzeba sprawdzić czy to jest prawda, więc: isdigit(ch)==true ale to z kolei znowu ma typ logiczny więc również nie możemy napisać if(isdigit(ch)==true) ponieważ trzeba sprawdzić czy to jest prawda, więc: (isdigit(ch)==true)==true ale to z kolei znowu ma typ logiczny więc również nie możemy napisać if((isdigit(ch)==true)==true) ponieważ trzeba sprawdzić czy to jest prawda, więc: ((isdigit(ch)==true)==true)==true ... mniej niż 16 niezagnieżdżeń jest zbyt mainstream'owo.
  4. Powinno być coś w stylu:
#include <iostream>
#include <cctype>
using namespace std;
 
int main()
  {
   cout<<"Wprowadz zdanie, @ konczy program."<<endl;
   for(int ch;(ch=cin.get())!='@';) if(!isdigit(ch)) cout<<(char)(isupper(ch)?tolower(ch):toupper(ch));
   return 0;
  }
0

Ooo, bardzo fajny skrót, na pewno się przyda. A czy jest skrót na (funkcja() != false)? :) Bo ja coś takiego używam. Zadanie już pomimo wykonania chyba zrozumiałem...

PS. Ja również z Tych, pozdrawiam ;)

@_13th_Dragon
Mało co rozumiem z twojego kodu i nie wiem jakim cudem, ale o dziwo to działa.
Wiem, że ten sposób na liczbę to strasznie karkołomny wymyśliłem...
Co do 3ciego punktu to właśnie analizuje :D

0
fearlay napisał(a):

A czy jest skrót na (funkcja() != false)? :)

O ile funkcja() zwraca stricte typ logiczny to zapis if(funkcja()!=false) jest bezsensem, ponmieważ wystarczy if(funkcja()).
Natomiast jeżeli funkcja() nie zwraca typ logiczny to zapis if(funkcja()!=false) jest kompletnym bezsensem ponieważ w zależności od typu zwracanego przez funkcja() będzie zwracać dziwaczne rzeczy.

Jak czegoś nie rozumiesz to pytaj.

0

O kurczaki, a myślałem, że zadanie dobrze wykonane...

Nie rozumiem pętli jaką zrobiłeś:

 for(int ch;(ch=cin.get())!='@';) if(!isdigit(ch)) cout<<(char)(isupper(ch)?tolower(ch):toupper(ch)); 

Dlaczego ta pętla nie jest w klamrach? Czy to nie jest tak, że jeżeli nie ma klamer to brana jest pod uwagę tylko pierwsza instrukcja?

  if(!isdigit(ch)) cout<<(char) 

isdigit() nie zwraca typu logicznego, a wartość różną od zera gdy argument, który został przekazany do funkcji jest cyfrą, tak? :)
typ logiczny to true oraz false?

oraz co to za twór:

(isupper(ch)?tolower(ch):toupper(ch));

? To nadal należy do pętli?

 for(int ch;(ch=cin.get())!='@';) 

Co to za warunek pętli...? Dlaczego ch jest typ int?

1

Dlaczego ta pętla nie jest w klamrach? Czy to nie jest tak, że jeżeli nie ma klamer to brana jest pod uwagę tylko pierwsza instrukcja?
Tak jest - w tym wypadku cały if, ponieważ jest to pierwsza instrukcja po forze.

typ logiczny to true oraz false?
Typ logiczny to bool, a wartość logiczna to true bądź false.

oraz co to za twór:
Operator trójargumentowy - ternary operator.

if (costam) {
  std::cout << "a";
} else {
  std::cout << "b";
}

Jest równoznaczne z:

std::cout << (costam ? "a" : "b");

Dlaczego ch jest typ int?
W C/C++ char jest wymienny z liczbą (tzn. możesz sobie zrobić np. char a = 98; i wyświetliłoby Ci to, zgodnie z ASCII, a), zatem nie ma to większego wpływu na program, ale stawiam, że napisane z rozpędu, jako że aż tak dużego typu jak int nie potrzeba ;)


Do kodów @{_13th_Dragon} podchodź z dozą ostrożności - wiele z nich wygląda jakby były pisane na IOCCC i nie powinny tak wyglądać w normalnych projektach :P
0

Kody @_13th_Dragon są w porządku, jedynie zamieniłbym rzutowanie na właściwe dla C++ - static_cast.
Poza tym formatowanie faktycznie nie przeszło by w kodzie produkcyjnym ale tutaj chyba chodzi o to aby nakierować na rozwiązanie a nie podać na tacy gotowy do przekopiowania kod.

0

To jeszcze jedna rzecz która mnie nurtuje:

for(int ch;(ch=cin.get())!='@';)

Czy czasem w pętli for nie trzeba dawać co się ma dziać ze zmienną ch po każdym kroku (tzn. po wykonaniu instrukcji)?

2

Z tego co @Patryk27 nie odpowiedział.

fearlay napisał(a):
if(!isdigit(ch)) cout<<(char)

isdigit() nie zwraca typu logicznego, a wartość różną od zera gdy argument, który został przekazany do funkcji jest cyfrą, tak?
Każda wartość liczbowa może być potraktowana jako wartość logiczna na zasadzie: 0 -> false; reszta -> true; to samo dotyczy wskaźników. Oraz na odwrót wartość logiczna może być potraktowana jako liczba na zasadzie: true -> 1; false -> 0; To umożliwia np:

int sgn(int v) { return (v>0)-(v<0); }
fearlay napisał(a):
(isupper(ch)?tolower(ch):toupper(ch));

To nadal należy do pętli?
Nie, to należy do if który z kolei należy do for

fearlay napisał(a):
 for(int ch;(ch=cin.get())!='@';) 

Co to za warunek pętli...?
najpierw jest przypisanie ch=cin.get(), którego wynikiem jest przypisana wartość, po czym tą przypisaną wartość porównujemy ze znakiem '@'.

fearlay napisał(a):

Dlaczego ch jest typ int?

Patryk27 napisał(a):

... ale stawiam, że napisane z rozpędu, jako że aż tak dużego typu jak int nie potrzeba ;)

cin.get() zwraca typ int http://www.cplusplus.com/reference/istream/istream/get/ więc żadnego rozpędu.
Umożliwi to pewną modyfikacje programu, kiedy okaże się że dane przekierowano z pliku, zaś plik nie zawiera znaku @, więc program zwyczajnie się zawiesza.
Modyfikacja:

for(int ch;((ch=cin.get())!='@')&&(ch!=EOF);)

EOF jest typu int, zaś jeżeli ch zrobimy typu char, to znak o kodzie 255 zostanie potraktowany jako EOF

Patryk27 napisał(a):

Do kodów @_13th_Dragon podchodź z dozą ostrożności - wiele z nich wygląda jakby były pisane na IOCCC i nie powinny tak wyglądać w normalnych projektach :P
Przemilczałeś dwie istotne rzeczy:

  1. W normalnych projektach nie ma takich pergoli https://pl.wikipedia.org/wiki/Pergola ;P
  2. Jeżeli przyzwyczaisz się takie bzdury pisać w 12 wierszy zamiast jednego to w normalnym projekcie będziesz mieć 12 tysięcy wierszy zamiast jednego tysiąca, zaś prawdopodobieństwo popełnienia błędu jest wprost proporcjonalne do ilości wierszy. Więc projekty w których ja rządzę praktycznie nie mają błędów w porównaniu do innych.
fearlay napisał(a):

To jeszcze jedna rzecz która mnie nurtuje:

for(int ch;(ch=cin.get())!='@';)

Czy czasem w pętli for nie trzeba dawać co się ma dziać ze zmienną ch po każdym kroku (tzn. po wykonaniu instrukcji)?
Możesz napisać np:

for(;;) // pętla bez końca, równoznaczna z while(true)
  {
  }
0

Podsumowując, ten kod:

 cout<<(char)(isupper(ch)?tolower(ch):toupper(ch)); 

jest instrukcją należącą do tego if'a:

if(!isdigit(ch))

a z kolei ten if jest instrukcją pętli for:

 for(int ch;(ch=cin.get())!='@';) 

Tak?
Dość skomplikowane, póki co raczej nie mogę sobie na takie skróty pozwolić ;-)
Dlaczego akurat taki warunek ifa:

if(!isdigit(ch))

W każdym razie dziękuję wszystkim za pomoc, sporo nowych rzeczy się dowiedziałem :p

0

Tak, masz for, w nim if, a w nim cout...

fearlay napisał(a):

Dość skomplikowane, póki co raczej nie mogę sobie na takie skróty pozwolić ;-)
Załóżmy że masz przed sobą dwie osoby:

  • Jeden od samego dzieciństwa nigdy nie biegał w obawie przed potknięciem się, na które nie mógł sobie pozwolić, analogiczny stosunek do każdego innego rodzaju sportu.
  • Drugi od dzieciństwa nigdy nie chodził, zawsze biegał oraz zawsze uprawiał i wciąż uprawia nawet ekstremalne sporty.
    ... potrzebujesz wynająć kogoś aby przeszedł bardzo duży dystans, którego z nich wybierzesz na to zadanie?

W twoim kodzie pomijasz cyfry zamieniając wartość ch na znak '\0' w zboczony sposób.

if(!isdigit(ch))

Tu się pomija w sposób jawny, wyświetlamy tylko nie cyfry.

0

Wybrałbym nr 2... chociaż żeby zacząć biegać najpierw trzeba nauczyć się chodzić :)
Ja tego ifa

 if(!isdigit(ch)) 

rozumiem tak:
jeżeli funkcja isdigit() zwróci false (czyli ch jest cyfrą), to ma się wykonać instrukcja cout.
Ale przecież ten warunek nie będzie spełniony dla zwykłych liter, a i tak te instrukcje (zawarte w if) są wykonywane? Dlaczego?

2

Czytaj to po ludzku. If not is digit ch then... Co można wręcz zamienić na normalne zdanie: If ch is not digit then...
Przecież po to te słowa kluczowe przypominają normalne słowa, a funkcje nazywa się tak, żeby było wiadomo co robią. Dlatego nazwy są ważne i po to piszę się czytelny, prosty kod.

1

isdigit() nie zwraca false, zwraca zero lub nie zero.
Dla cyfr zwraca nie zero, które jest traktowane jako wartość logiczna czyli true, po czym następuje negacja, wychodzi false, więc cout się nie wykona.
Dla liter i znaków specjalnych zwraca zero, które jest traktowane jako wartość logiczna czyli false, po czym następuje negacja, wychodzi true, więc cout się wykona.
Czytasz to if( -> "jeżeli"; ! -> "nie"; isdigit( -> "jest cyfrą", czyli razem "jeżeli nie jest cyfrą".

0

Dziękuję bardzo za pomoc. Jesteście wielcy, naprawdę :) Dopiero 2 tygodnie uczę się C++ jak znajdę czas... Raz jeszcze dziękuje. Temat tak przewałkowany, że chyba bardziej się nie da :p

1 użytkowników online, w tym zalogowanych: 0, gości: 1