The aim of this program is to remove all vowels from an input. The function is working fine until I add a space to the string, what can I do?

Viewed 54
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {

        char array[1000];
        int x, y, len = 0;
        scanf("%s", array);
        len = strlen(array);
        
    for (x = 0; x < len; x++) {
    
    if (array[x] == 'a' || array[x] == 'e' || array[x] == 'i' || array[x] == 'o' || array[x] == 'u' || array[x] == 'A' || array[x] == 'E' || array[x] == 'I' || array[x] == 'O' || array[x] == 'U') {

    for (y = x; y < len; y++) {
        array[y] = array[y+1]; // Moving the non-vowels to a higher position to fill up the array.
    }
    x--; // Deleting those particular x's (The vowels in place).
    len--; // Deleting the length list.
    }
    
    array[len + 1] = '\0';
}
    printf("%s", array);
    return 0;
}

The program is working fine until it uses an input that contains a space in the string, what can I do?

For example, "Hello World" prints "Hll" instead of "Hll Wrld".

5 Answers

For starters the code is bad formatted.

And as any bad formatted code it has a bug.

This statement

array[len + 1] = '\0';

can write outside the character array if the contained string does not contain a vowel.

For example consider the array

char array[] = "H";

The length of the stored string is equal to 1. So this statement

array[len + 1] = '\0';

is equivalent to

array[2] = '\0';

while the valid range of indices for this array is [0, 2).

The statement is just redundant and shall be removed because in this for loop

for (y = x; y < len; y++) {
    array[y] = array[y+1]; // Moving the non-vowels to a higher position to fill up the array.
}

the terminating zero character '\0' is moved to the left as it is required.

Also instead of this long if statement

if (array[x] == 'a' || array[x] == 'e' || array[x] == 'i' || array[x] == 'o' || array[x] == 'u' || array[x] == 'A' || array[x] == 'E' || array[x] == 'I' || array[x] == 'O' || array[x] == 'U') {

you could use the standard function strchr as for example

unsigned char c = array[x];
c = tolower( c );

uf ( strchr( "aeiou", c ) != NULL ) {
//...

Pay attention to that it is an inefficient approach to move a whole sub-string to the left when a vowel is encountered.

As for your question then the conversion specifier s "matches a sequence of non-white-space characters.". That is as soon as a white space character after a sequence of non-white space characters is encountered the input is interrupted.

You should write

scanf( "%999[^\n]", array);

You could write a separate function that removes vowels from a string.

Here is a demonstration program.

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

char * remove_vowels( char *s )
{
    const char *vowels = "aeiou";
    char *start = s;

    char *p = s;
    do
    {
        unsigned char c = *s;
        c = tolower( c );

        if ( c == '\0' || strchr( vowels, c ) == NULL )
        {
            if ( p != s ) *p = *s;
            ++p;
        }
    } while ( *s++ );

    return start;
}

int main( void ) 
{
    char s[] = "Hello World";
    puts( s );
    puts( remove_vowels( s ) );
}

The program output is

Hello World
Hll Wrld

The problem is that by default scanf accepts a space character as an input terminator, you can try using another function like fgets

Or set the conditions for the function using scanf("%[\n]", array);

The scanf("%s", array); takes input till white space character. To take input till newline char can use scanf("%[^\n]", array);

And proper indentation is useful to understand code.

Just after this, the edited code works fine

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

int main(void) {

    char array[1000];
    int x, y, len = 0;
    scanf("%[^\n]", array);
    len = strlen(array);
        
    for (x = 0; x < len; x++) {
        if (array[x] == 'a' || array[x] == 'e' || array[x] == 'i' || array[x] == 'o' || array[x] == 'u' || array[x] == 'A' || array[x] == 'E' || array[x] == 'I' || array[x] == 'O' || array[x] == 'U') {
            for (y = x; y < len; y++) {
                array[y] = array[y+1]; // Moving the non-vowels to a higher position to fill up the array.
            }
            x--; // Deleting those particular x's (The vowels in place).
            len--; // Deleting the length list.
        }
        array[len + 1] = '\0';
    }
    printf("%s", array);
    return 0;
}

You can use scanf("%[^\n]", array); to read a line from input.
However, as pointed out by Gerhardh in the comment section, a even better solution would be to limit the characters read from input to 999 (since the size of your array is 1000, and the last element will be occupied by '\0'):

scanf("%999[^\n]", array);
  • %999 means "read at most 999 characters";
  • [^\n] means "read the entire line (up to '\n' but not including it)".

Which overall means: read at most 999 characters from standard input stream (stdin), or until the user enters a new line.


From the C11 Standard you can read the following (notice that the scanf() function behaves exactly the same as fscanf(), but always reads from the standard input stream stdin - so you can refer to that):

The fscanf function reads input from the stream pointed to by stream,

(In this case stdin)

under control of the string pointed to by format that specifies the admissible input sequences and how they are to be converted for assignment, using subsequent arguments as pointers to the objects to receive the converted input. If there are insufficient arguments for the format, the behavior is undefined. If the format is exhausted while arguments remain, the excess arguments are evaluated (as always) but are otherwise ignored.

And

The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The format is composed of zero or more directives: one or more white-space characters, an ordinary multibyte character (neither % nor a white-space character), or a conversion specification. Each conversion specification is introduced by the character %. After the %, the following appear in sequence:
-An optional assignment-suppressing character *.
-An optional decimal integer greater than zero that specifies the maximum field width (in characters).
-An optional length modifier that specifies the size of the receiving object.
-A conversion specifier character that specifies the type of conversion to be applied.

Then there is a list of the format specifiers with some example which I suggest you to have a look at, but the part you're interested in is the following:

[
Matches a nonempty sequence of characters from a set of expected characters (the scanset).
[...]
The conversion specifier includes all subsequent characters in the format string, up to and including the matching right bracket (]). The characters between the brackets (the scanlist) compose the scanset, unless the character after the left bracket is a circumflex (^), in which case the scanset contains all characters that do not appear in the scanlist between the circumflex and the right bracket.

A snippet of your code

char array[1000];
int x, y, len = 0;
scanf("%s", array);
len = strlen(array);

for (x = 0; x < len; x++) {

And the same thing that would save you having to ask for help on this occasion.

char array[1000];
int x, y, len = 0;
x = scanf("%s", array);
printf( "scanf satisfied %d variable(s)\n", x );

len = strlen(array);
printf( "working with %d characters as '%s'\n", len, array );

for (x = 0; x < len; x++) {

Learn to print out values (and strings) to get feedback from what the code you've written is actually doing. Then, you go study the scanf() documentation and learn that "%s" will stop when a whitespace character is encountered.

Related