1

So this is the program I have used to Convert Lowercase, to Uppercase can you tell me why do we use this thing?[(str[i]>=97 && str[i]<=122)] in the following code section?

#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{
    clrscr();
    char str[20];
    int i;
    cout << "Enter the String (Enter First Name) : ";
    cin >> str;
    for (i = 0; i <= strlen(str); i++) {
        if (str[i] >= 97 && str[i] <= 122) //Why do we use this???
        {
            str[i] = str[i] - 32;
        }
    }
    cout << "\nThe String in Uppercase = " << str;
    getch();
}
drescherjm
  • 10,365
  • 5
  • 44
  • 64
Veritasium
  • 49
  • 9
  • 3
    An [ASCII table](http://en.cppreference.com/w/cpp/language/ascii) might help you. – Some programmer dude Jan 31 '17 at 14:50
  • 97 is the ASCII code of `'a'`, 122 is the ASCII code of `'z'`. All the characters between (and including) them are usually known as "lowercase letters" aren't they? – axiac Jan 31 '17 at 14:51
  • 9
    And please, don't learn anything from this program as it is awful. It uses [*magic numbers*](https://en.wikipedia.org/wiki/Magic_number_(programming)) which should be avoided. Doesn't use the perfectly fine [`std::toupper`](http://en.cppreference.com/w/cpp/string/byte/toupper) function. It relies on ASCII encoding and is therefore not portable. And it doesn't use [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) and is prone to buffer overflows. – Some programmer dude Jan 31 '17 at 14:52
  • 1
    Also, `#include` is deprecated since the 90s and `#include` as well as `void main` never was legal standard C++. You should get better and more up-tp-date code to learn from. – Baum mit Augen Jan 31 '17 at 14:55
  • 1
    _if(str[i]>=97 && str[i]<=122) //Why do we use this???_ Typically we use (if we **really** need it, which in modern C++ is rarely the case) `if(str[i]>='a' && str[i]<='z')`, since that is much more readable. – Algirdas Preidžius Jan 31 '17 at 14:55
  • @AlgirdasPreidžius if i use if(str[i]>='a' && str[i]<='z') then an error is popping like~cannot convert "char" to char* – Veritasium Jan 31 '17 at 14:59
  • 1
    @Veritasian I fail to see how it is possible. Did you use double-quotes (`"`) instead of single-quotes (`'`) by any chance? – Algirdas Preidžius Jan 31 '17 at 15:01
  • @Veritasian Yet you post the correct code in the comment. Interesting. – LogicStuff Jan 31 '17 at 15:01
  • ** if(str[i]>="a" && str[i]<="z") { str[i]=str[i]-32; } @AlgirdasPreidžius this is what i did – Veritasium Jan 31 '17 at 15:04
  • 1
    This is wrong because you used `"` instead of `'` `"` is used for strings. `'` is used for a character. – drescherjm Jan 31 '17 at 15:05
  • @Veritasian Then you **didn't** use my example. Have a look at it again. – Algirdas Preidžius Jan 31 '17 at 15:08
  • @AlgirdasPreidžius i got the code now!!! Thanks to all :) – Veritasium Jan 31 '17 at 15:15
  • @AlgirdasPreidžius: `if(str[i]>='a' && str[i]<='z')` is still not portable. This trick does work for `'0'` to `'9'` because C++ makes a special guarantee for digits to have consecutive numeric representations, but not for letters. – Christian Hackl Jan 31 '17 at 16:45
  • @ChristianHackl Yes, I know that. My point was, that it is a lot more readable (and intention is a lot more clear) than OPs original version, using magic numbers. – Algirdas Preidžius Jan 31 '17 at 16:46
  • 1
    Even if written in "portable" code, this algorithm is inadequate to convert characters to uppercase. Casing rules depend on the writing system and language (see setlocale()). (Even if your problem domain has only English text, there are more letter characters used than a-z and A-Z.) That's why there are libraries. – Tom Blodget Jan 31 '17 at 17:25

5 Answers5

7

This part of the code is very badly written:

if(str[i]>=97 && str[i]<=122)
{
 str[i]=str[i]-32;
}

It would be much more portable and more readable as:

if(str[i]>='a' && str[i]<='z')
{
 str[i]=str[i]-'a'+'A';
}

or better still, use standard C library macros/functions (from <ctype.h>):

if(islower(str[i]))
{
 str[i]=toupper((unsigned char)str[i]);
}

or even better yet, you can just skip the test completely and write:

str[i]=toupper((unsigned char)str[i]);

(since toupper will return the char unchanged if it's not a lower case letter).

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 1
    Even better would be to simply say `str[i] = toupper((unsigned char)str[i])`. – John Zwinck Jan 31 '17 at 14:54
  • @JohnZwinck: yes, thanks, still working on refining the answer... ;-) – Paul R Jan 31 '17 at 14:55
  • "more readable" of course. "much more portable" yes, but still not completely, because there is no guarantee that `'a'` to `'z'` have consecutive numerical representations. – Christian Hackl Jan 31 '17 at 16:46
  • @ChristianHackl: true, the original implementation and my first version fail for EBCDIC, hence the further improvements using `` that I gave further down in the answer. – Paul R Jan 31 '17 at 17:08
  • `toupper()` without a cast to `unsigned char` may lead to undefined behavior if a "negative" char is encountered. – John Zwinck Feb 01 '17 at 03:03
  • @JohnZwinck: good point - got to make sure we handle "extended ASCII" et al properly. – Paul R Feb 01 '17 at 06:12
3

97 is the decimal representation of the ascii character a, while 122 is z.

So if your character (which is simply a byte) is inside this interval, it is a lowercase letter. Substracting 32 will make it uppercase.

Note that in this case, writing str[i] <= 122 or str[i] <= 'z' are equivalent.

ascii table

Derlin
  • 9,572
  • 2
  • 32
  • 53
  • @axiac: When was the last time you checked? They might have changed it. – Benjamin Lindley Jan 31 '17 at 14:55
  • @BenjaminLindley 5 minutes ago :-) – axiac Jan 31 '17 at 14:59
  • *"Note that in C, str[i] <= 122 and str[i] <= 'z' are equivalent."* - No, they are not. `'z'` may or may not be 122. In practice, you may never encounter a system on which it's not 122, but there is no guarantee. See http://stackoverflow.com/a/29381142/3313064 – Christian Hackl Jan 31 '17 at 16:51
2

This would be more appropriate code:

if(str[i]>='a' && str[i]<='z')
 {
 str[i]=str[i] + 'A' - 'a';
 }
}

No numbers, and if a letter is between lowercase 'a' and lowercase 'z', it gets transposed by the difference between 'A' and 'a', and as such becoming its uppercase version.

coyotte508
  • 9,175
  • 6
  • 44
  • 63
2

That is specific to ASCII, where the lowercase letters have the numeric values 97-122. This has the useful property that the uppercase characters (which are mapped from 65-90) can be converted to lower case with a constant subtraction or a bitwise operation (and vice versa).

However, it's bad in general to assume that every system out there uses ASCII; there are other character sets out there. You should be using the library functions toupper and tolower from the header <cctype>.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
1

Because that's the range of lower-case characters in ASCII.

Rob K
  • 8,757
  • 2
  • 32
  • 36