0

My teacher gave us code that Write a function declared as "int categorize(char *str)" which accepts a string as an input parameter and categorize the string. The function should return the category number as decribed below:

Category 1: If the string contains only capital letters (e.g. ABCDEF), the function should return 1.

Category 2: If the string contains only small letters (e.g. abcdef), the function should return 2.

Category 3: If the string contains only letters but no other symbols (e.g. ABCabc), the function should return 3.

Category 4: If the string contains only digits (e.g. 12345), the function should return 4.

Category 5: If the string contains both letters and digits but no other symbols (e.g. Hello123), the function should return 5.

Category 6: Otherwise, the function should return 6.

I write this but not working

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

// Write your categorize function here
int categorize(char *str) {
int x=0;
while(str[x]!= '\0'){
     if((*str>='A'&&*str<='Z')  && (*str>='a'&&*str<='z') && (*str>='0'&&*str<='9'))
    return 5;
    else if((*str>='A'&&*str<='Z') && (*str>='a'&&*str<='z'))
    return 3;
    if((*str>='A') && (*str<='Z'))
    return 1;
    else if((*str>='a')&&(*str<='z'))
    return 2;
    else if((*str>='0')&&(*str<='9'))
    return 4;
    x++;
}
return 6;
}

///////////////////////////////////////
// Test main()
  // DO NOT MODIFY main()
  // or your code will not be evaluated
  int main() {
  char str[100];
  scanf("%s",str);
  int c = categorize(str);
  printf("%d\n",c);
  return 0;
 }
///////////////////////////////////////
DarkSpy
  • 15
  • 1
  • 5

4 Answers4

2

*str this is a pointer to the first character of the string so along your cycle it only checks this first character.

Furthermore you are returning values before checking the entire string, you need to use flags and set them along the cycle for digits caps and small letters, and in the end return the values according to those flags.

There is the <ctype.h> library which has functions like isalpha and isdigit and can make your job easier, for that I refer you to @DevSolar answer as a better method.

If you can't use it this is the way to go:

Live demo

int categorize(char *str) {
    
    int x = 0;
    int is_digit, is_cap, is_small;
    is_cap = is_digit = is_small = 0;

    while (str[x] != '\0') {
        
        if (!(str[x] >= 'a' && str[x] <= 'z') && !(str[x] >= 'A' && str[x] <= 'Z') && !(str[x] >= '0' && str[x] <= '9'))
             return 6;        
        if (str[x] >= 'A' && str[x] <= 'Z' && !is_cap)  //if there are caps
            is_cap = 1;
        if (str[x] >= '0' && str[x] <= '9' && !is_digit) //if there are digits
            is_digit = 1;
        if (str[x] >= 'a' && str[x] <= 'z' && !is_small) //if there are smalls
            is_small = 1;      
        x++;
    }
    if ((is_small || is_cap) && is_digit){
        return 5;
    }
    if(is_small && is_cap){
        return 3;
    }
    if(is_digit){
        return 4;
    }
    if(is_small){
        return 2;
    }
    if(is_cap){
        return 1;
    }
    return 6;
}

Note that this kind of character arithmetic works well in ASCII but fails in other character encodings like EBCDIC which don't have sequencial order for alphabetic characters.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • I see character arithmetic, I weep. – DevSolar Jun 22 '20 at 14:32
  • @DevSolar, it's an assingment, it's likely the OP can't use the library functions. – anastaciu Jun 22 '20 at 14:34
  • Aside from me steadfastly refusing to accept such braindead limitation when the instructor should actually **teach** and **encourage** use of the standard library, `>= 'a'` / `<= 'z'` is actually not well-formed as far as the language standard is concerned even *before* non-basic character set comes into play (because EBCDIC exists). And OP is *using* `` and ``, so... let us not begin to *assume* hamstrung environments but showcase the best we can. – DevSolar Jun 22 '20 at 14:37
  • @DevSolar, I had many questions, including in exams, using character arithmetic, the point is to teach how it's done, I added a disclaimer to clarify the encoding issue. – anastaciu Jun 22 '20 at 14:42
  • Well, that's exactly where I disagree (rather strongly). Character arithmetic should **never** be done, it simply shouldn't be taught, because it's wrong even in the simplest of cases, says my friend José. – DevSolar Jun 22 '20 at 14:46
  • @DevSolar, I agree with you in principle but this is not the point, I can't talk to the teacher an try to convince him not to use it. I can however tell the OP what are the flaws and constraints of the method being used. – anastaciu Jun 22 '20 at 14:50
  • I don't see any mention of restraints imposed by the teacher, I just saw coding practices in the example and this answer that could be improved upon. – DevSolar Jun 22 '20 at 15:00
  • @DevSolar, that may be and I reference the use of ctype.h if possible, the OP is using character arithmetic for a reason, I doubt that he doesn't know about these functions. – anastaciu Jun 22 '20 at 15:11
  • 1
    Retracted the downvote for that. Though I still think it unfortunate that "ASCII' is mentioned in a way of "what most people use", when what we actually use (even if we don't go full Unicode) is ISO-8859-15, CP-1252 or similar, for which the A-Z range also fails to tell the whole truth. – DevSolar Jun 22 '20 at 15:15
2

You can do this in O(n) as follows:

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

int check_str(char* str)
{
    int category = 0;   // 0b001 -> Uper | 0b010 -> Lower | 0b100 -> Number

    for ( ; *str != 0; str++) {
        if (isupper(*str)) {
            category |= 1;
        }
        else if (islower(*str)) {
            category |= 2;
        }
        else if (isdigit(*str)) {
            category |= 4;
        }
        else
            return 6;
    }

    if (category == 1)
        return 1;

    if (category == 2)
        return 2;

    if (category == 3)
        return 3;

    if (category == 4)
        return 4;

    if (category == 7)
        return 5;

    return 6;
}

int main()
{
    printf("%d\n", check_str("ABCDEF"));
    printf("%d\n", check_str("abcdef"));
    printf("%d\n", check_str("ABCabc"));
    printf("%d\n", check_str("12345"));
    printf("%d\n", check_str("Hello123"));
    printf("%d\n", check_str("Hello World 123"));

    return 0;

}

OUTPUT

1
2
3
4
5
6

EDIT

Since 0b... is not portable, binary numbers are changed to their decimal equivalents

m0hithreddy
  • 1,752
  • 1
  • 10
  • 17
1

The standard header <ctype.h> literally has everything you are looking for:

  • Category 1 is if isupper() is true for all characters.

  • Category 2 is if islower() is true for all characters.

  • Category 3 is if isalpha() is true for all characters.

  • Category 4 is if isdigit() is true for all characters.

  • Category 5 is if isalnum() is true for all characters.

A quick-and-dirty approach could just iterate through the input once for each of the above:

int categorize( char * str )
{
    char * s;
    
    for ( s = str; *s; ++s )
    {
        /* Need the cast to unsigned char here; negative values
           are reserved for EOF!
        */
        if ( ! isupper( (unsigned char)*s ) )
        {
            break;
        }
    }

    if ( ! *s )
    {
        /* True if the loop ran its full course without breaking */
        return 1;
    }

    /* Same for the other categories */

    return 6;
}

Once you got this done, you could start getting funny with the logic, putting all the checks into one loop and keeping track of conditions met.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
DevSolar
  • 67,862
  • 21
  • 134
  • 209
-2

You seem to have a pretty good start for your project. You capture a String, and then categorize it.

Where you need to improve is the logic for categorization. I would start by making each of your categories into a function.

int isOnlyCapital(char* string)

might return 1 if the string is only comprised of capital letters, and 0 otherwise. The logic might look like

    char* position = string;
    while (position != '\0') {
      if (*position < 'A' || *position > 'Z') {
        return false;
      }
      position++;
    }
    return true;

Note that you can only return true if you managed to check all charaters with the above code, as you have looped over all characters until you hit the NULL character \0.

With some work, you can modify the above loop to handle your other cases. That would make your logic for the overall top level look like.

 if (isOnlyCapital(string)) return 1;
 if (isOnlyLowercase(string)) return 2;
 ... and so on...
Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • This would scan the string multiple times, which is not a good practice. I would recommend scanning the string once, counting the number of characters that fit into each of the categories. I also think the isalpha(3) library routines would be of good use. – mpez0 Jun 22 '20 at 14:26
  • @mpez0 if by "scanning" you mean capturing the line, no it would only capture onece. If by "scanning" you mean parsing the line, yes, it would do multiple passes. Note that CPUs are very fast compared to disks, and IO in general. So a simple approach is often easier to deal with than a complex, one pass, approach. Yes, I could have returned a bitset of {captial, numeric, lowercase, space, etc} but this is a new programmer of C, and odds are they wouldn't do well with such an approach until they gained some experience. – Edwin Buck Jun 22 '20 at 14:31
  • I see character arithmetic, I weep. – DevSolar Jun 22 '20 at 14:31
  • @DevSolar I agree, it's not even close to UTF(anything) compliant. But, when learning C, as this person is doing, UTF needs to take a backseat until the person learns the language. – Edwin Buck Jun 22 '20 at 14:37
  • EDCDIC exists, as do non-ASCII-7 characters. "ö" is lowercase, as is "ß", or "å". – DevSolar Jun 22 '20 at 14:39
  • @DevSolar Do you really think a person who's in a class, learning C, is going to be writing portable C programs designed to work on IBM 360 systems? Odds are they're just getting introduced to ASCII at this point. – Edwin Buck Jun 22 '20 at 14:42
  • @EdwinBuck Yes, I meant parsing multiple passes. I understand OP's novice programmer status and agree that there's a large grey area on "what's easier to understand for OP". I repeat my isalpha(3) comment, as I think that would be easier for OP -- or anyone -- to understand, even with multiple passes. Also, thank you for taking the time to write your answer, and even respond to some of these comments. – mpez0 Jun 22 '20 at 14:42
  • Yes, I **really** think a person who's in a class should write code that's using existing standard functionality wherever possible instead of assuming all the world is ASCII-7 and having to re-learn later. ISO-8859 isn't great, but it's better than hand-crafting ASCII-7 arithmetics. – DevSolar Jun 22 '20 at 14:44
  • @DevSolar Well, after you give them the rundown on UTF, including encodings covering EBCDIC, UTF-8, UTF-16, etc, then you can introduce them to functions and parameter passing. Or, since you're not their professor, you can bend your opinions into what their class is asking for. – Edwin Buck Jun 22 '20 at 14:45
  • At no point was it stated that the standard library is off-limits or that assuming ASCII-7 was OK. *For all you and I know, that class is **not** asking for that.* That assumption was made in two answers here simply based on already-existing bad habit by the OP. – DevSolar Jun 22 '20 at 14:49
  • @DevSolar Yeah, I don't know why any of the comments were deleted either. I certainly didn't delete them. That said, I'm pretty ok with civil discourse, the main point being, I'm all for portable C, and I agree with your approach of making C programs more portable; however, I think it's the wrong audience. A person who's "just learning C" can benefit form knowing how to write C in a portable fashion; but, if they don't know what "a portable fashion" means, they miss other lessons, equally valuable. No hard feelings, and if you want ot consider me a "what I said", do so, shoud you wish. – Edwin Buck Jun 22 '20 at 18:06