0

I'm a beginner in C. I'm trying to make a program that changes the vowels with the next letter in the alphabet, and the consonants with the previous letter. I would be happy if you could help me. Here is my code:

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

void modifyString( char vovels[], char string[]){
    for(int i = 0; i < strlen(string); i++){
        for(int j = 0; j < strlen(vovels); j++){
            if(string[i] == vovels[j]){
                (char)(string[i] += 1);
            } else if((string[i] >= 'a' && string[i] <= 'z')){
                (char)(string[i]-= 1);
            }
        }
    }
    printf("%s ",string);
}

int main() {

    char vov[]="aeiou",str[100];

    printf("String is : ");
    gets(str);
    strlwr(str);
    modifyString(vov,str);
    return 0;
}

BZKN
  • 1,499
  • 2
  • 10
  • 25
kammy
  • 93
  • 8

2 Answers2

1

You are not far off. You can just loop over the strings without calling strlen(), for example iterating with for (int i = 0; string[i]; i++) which will increment i until it points to the nul-terminating character at the end of string which is ASCII '\0' and has the value of plain-old 0. The loop in str2lower() (below) does the exact same thing except it iterates with a pointer instead of an index.

Your logic in modifyString() looks fine, but you should not cast (char) when incrementing the values. There is no need. You can simplify your logic by letting strchr() check if the current char is one of the characters in vowles with if (strchr (vowels, string[i])) eliminating the j loop altogether.

It's unclear where strlwr(str); is defined, but you can write a simple string to lower easy enough.

Also in my comment, you never, ever, ever use gets() or use scanf() with "%s" without using the field-width modifier (e.g. "%99s") to prevent a string longer than your array from writing beyond the end of your array creating a buffer-overrun.

If you put that together, you can do something like:

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

#define MAXC 1024   /* if you need a constant, #define one (or more) */

/** convert string to lowercase.
 *  returns string with all chars converted to lowercase.
 */
char *str2lower (char *str)
{
    if (!str || !*str)    /* check string not NULL or empty */
        return NULL;

    char *p = str;        /* user pointer enabling return of str */

    for (; *p; p++) {     /* loop over each char */
        if ('A' <= *p && *p <= 'Z')   /* if upper case */
            *p ^= ('A' ^ 'a');        /* make lower case */
    }
    
    return str;           /* return modified string */
}

/* modify vowels +1 and consonants -1 */
void modifystr (const char *vowels, char *string)
{
    for (int i = 0; string[i]; i++) {       /* loop over each char */
        if (strchr (vowels, string[i])) {   /* is char in vowels? */
            string[i] += 1;                 /* if so, increment */
        }
        else if ('a' <= string[i] && string[i] <= 'z') {
            string[i] -= 1;                 /* decrement */
        }
    }
}

int main (void) {
  
  const char *vowels = "aeiou";
  char str[MAXC];
  
  fputs ("enter a string : ", stdout);
  
  if (!fgets (str, MAXC, stdin)) {
      puts ("(user canceled input)");
      return 0;
  }
  
  modifystr (vowels, str2lower(str));
  
  printf ("modified string: %s\n", str);
}

Example Use/Output

$ ./bin/modifystr
enter a string : My DOG has fLEAS and My Cat has nONE!
modified string: lx cpf gbr ekfbr bmc lx bbs gbr mpmf!

Look things over and let me know if you have questions.


Eliminating strchr() and Using a Loop

You can replace strchr(vowels, string[i]) by adding back your j loop and looping over each vowel. You need to keep a flag variable (like found and if a vowel is found, set found = 1. You want to break; the loop as soon as a vowel is found.

After the loop you will test if (!found && 'a' <= string[i] && string[i] <= 'z') to know you need to update a consonant value.

Putting it together, you could rewrite modifystr() as:

/* modify vowels +1 and consonants -1 */
void modifystr (const char *vowels, char *string)
{
    for (int i = 0; string[i]; i++) {       /* loop over each char */
        int found = 0;                      /* flag tells if vowel found */
        for (int j = 0; vowels[j]; j++) {   /* loop over each vowel */
            if (vowels[j] == string[i]) {   /* if string[i] matches */
                string[i] += 1;             /* increment string[i] */
                found = 1;                  /* set found flag true */
                break;                      /* break vowel loop */
            }
        }
        /* after loop, if vowel !found and [a-z] */
        if (!found && 'a' <= string[i] && string[i] <= 'z') {
            string[i] -= 1;                 /* decrement consonant */
        } 
    }
}

It does the same thing, without strchr().

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • An extraordinary and explicit solution. I have one more question : how to modify this code so as not to use string processing functions but only array operations ? – kammy Mar 05 '22 at 09:43
  • See update to answer: – David C. Rankin Mar 05 '22 at 09:54
  • Omg, you are great, thank you very much – kammy Mar 05 '22 at 10:05
  • Glad it helped. Good luck with your coding! Always compile with full-warnings enabled and do not accept code until it compiles cleanly without warning. Compilers have gotten very good at identifying the exact line and column where problem code is found. You can learn a lot of C just by listening to what your compiler is telling you `:)` – David C. Rankin Mar 06 '22 at 00:45
0

The main problem with your code is that the inner loop is repeated 5 times (once for each vowel in vov, and for every consonant the value is incremented 5 times.

Here is a better way to do this:

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

const char *VOWELS = "aeiou";

#define isvowel(chr) strchr(VOWELS,chr)

void modifyString(char *str)
{
    for(int i = 0; str[i]; i++) {
        if (isvowel(str[i]))
            str[i]++;
        else if (isalpha(str[i]))
            str[i]--;
    }
    printf("%s\n",str);
}

int main(void)
{
    char str[100];

    printf("Enter a String: ");
    fgets(str,sizeof str,stdin);
    strlwr(str);
    modifyString(str);

    return 0;
}

Note that strlwr is not standard C, and gets is deprecated.

SGeorgiades
  • 1,771
  • 1
  • 11
  • 11