How do I use the ctype.h library in a conditional statement?

124 Views Asked by At

I am trying to write a function that capitalizes all words in a string using the ctype.h library. I used the isalpha(), isspace() and ispunct() functions in a conditional statement to check if the first letter of a word is an alphabet and if the character before it was whitespace or punctuation. If those conditions are met then the program converts the letter to uppercase using the toupper() function.

I ran the program and it doesn't seem to be working, it actually returned the same string input. I need someone to help me out so that I can learn and improve my C programming skills. I am learning C Programming online and I'm loving it.

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

/**
 * *cap_string - Capitalize the first words of a string
 * @s: Argument pointer to char
 * Return: Pointer to s variable
 */

char *cap_string(char *s)
{
        int i;

        for (i = 0; s[i] != '\0'; i++)
        {
                if (isalpha(s[i]) && (i == 0 || (isspace(s[i - 1]) || ispunct(s[i - 1]))))
                {
                        *s = toupper(s[i]);
                }
        }
        return (s);
}

/**
 * main - Check the code
 * Return: Always 0
 */

int main(void)
{
        char str[] = "Expect the best. Prepare for the worst. Capitalize on what comes.\nhello world! hello-world 012345
6hello world\thello world.hello world\n";
        char *ptr;

        ptr = cap_string(str);
        printf("%s", ptr);
        printf("%s", str);
        return (0);
}
2

There are 2 best solutions below

0
Zwy On
  1. *s + i is not s[i], it's s[0] + i.
  2. Even if you correct all occurrence of *s + i and *s + i - 1 with s[i] and s[i - 1]. If i is 0, the s[i - 1] will turn into s[-1], which is undefined.
8
Jabberwocky On

As you have already understood, *s + i is different from *(s + i) and you should write s[i] rather than *(s + i) for readability reasons (and readability is very important).

So a first correction would be this:

char* cap_string(char* s)
{
  int i;
  char* ps = s;

  for (i = 0; s[i] != '\0'; i++)
  {
    if (isalpha(s[i]) && (isspace(s[i - 1]) || ispunct(s[i - 1])))
    {
      s[i] = toupper(s[i]);
    }
  }
  return (ps);
}

int main()
{
  char test[] = "hello world, abc";
  cap_string(test);
  printf("%s", cap_string(test));
}

But there is still a problem in this code. If the sentence starts with a letter (IOW isalpha returns true), you try to access the letter before the first letter which is at the index -1 and accessing an array out of bounds yields is undefined behaviour.

Therefore the condition should be

isalpha(s[i]) && (i == 0 || (isspace(s[i - 1]) || ispunct(s[i - 1])))

so you never access s[-1].

IOW: if the first character is a letter, we don't need (and we don't want) to check if the preceeding character is a space of a punctuation character.

BTW: char* ps = s; is useless, you can just return s; because you don't change s.