1

I am stuck on the n0 v0w3ls exercise from CS50. I can´t figure out how to have an non-blank output. I am getting completely lost in the data types transformation between string/char and assigning new values to the output char. I have tried so many combinations, I don´t understand the differences anymore. Right now, my program works in the debugger but the output is blank. Any help greatly appreciated ;)

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

char replace(string input);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Incorrect number of arguments\n");
        return 1;
    }
    else
    {
        printf("%c \n", replace(argv[1]));
    }

}

char replace(string input)
{
    int n = strlen(input);
    //n+1 as I read the last char should be a '\0' to be recognised as a string
    char s[n+1];

    for (int i = 0; i < n; i++)
    {
        //printf("%c\n", input[i]);
        switch (input[i])
        {
            case 97:
                s[i] = '6' ;
                break;
            case 101:
                s[i] = '3';
                break;
            case 105:
                s[i] = '1';
                break;
            case 111:
                s[i] = '0';
                break;
            default:
                s[i] = input[i];
                break;
        }
    }
    return s[n];
}

The aim is to replace vowels by numbers. I have tried

  • taking the input as a string
  • looping on each character of that string
  • if the character is a vowel > replaces it in my output string else keep as is
  • return my output char array/string ?
// Write a function to replace vowels with numbers
// Get practice with strings
// Get practice with command line
// Get practice with switch

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

string replace(string input);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Incorrect number of arguments\n");
        return 1;
    }
    else
    {
        printf("%s \n", replace(argv[1]));
    }

}

string replace(string input)
{
    int n = strlen(input);
    string s[n+1];

    for (int i = 0; i < n; i++)
    {
        //printf("%c\n", input[i]);
        switch (input[i])
        {
            case 'a':
                s[i] = "6" ;
                break;
            case 'e':
                s[i] = "3";
                break;
            case 'i':
                s[i] = "1";
                break;
            case 'o':
                s[i] = "0";
                break;
            default:
                s[i] = &input[i];
                break;
        }
    }
    s[n+1] = "\0";
    return s[n];
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
soge king
  • 15
  • 5

2 Answers2

2

This function declaration

char replace(string input);

is incorrect because the function having the return type char tries to return a single character.

This function declaration

string replace(string input);

is correct. However the function implementation is wrong.

For starters you declared a variable length array of the type string

string s[n+1];

where the name string denotes an alias for the type char *. Instead of an array of pointers you should declare at least a character array like

char s[n+1];

However you may not return an array with automatic storage duration from a function. It will not be alive after exiting the function.

Secondly, you are returning only the last pointer of the array

return s[n];

that was not even initialized and has an indeterminate value.

Also this statement

s[n+1] = "\0";

writes outside the array. because the valid range of indices for the declared array is [0, n + 1).

And in statements like that

s[i] = "6" ;

you are trying to assign pointers to string literals instead of forming a character array.

If you need to replace characters in a character array then there is no need to create a new character array. Just write

string replace( string input )
{
    for ( string s = input; *s != '\0'; ++s )
    {
        switch ( *s )
        {
            case 'a':
                *s = '6';
                break;

            case 'e':
                *s = '3';
                break;

            case 'i':
                *s = '1';
                break;

            case 'o':
                *s = '0';
                break;
        }
    }

    return input;
}

If you want to use the subscript operator then the function can look the following way

string replace( string input )
{
    for ( size_t i = 0; input[i] != '\0'; ++i )
    {
        switch ( input[i] )
        {
            case 'a':
                input[i] = '6';
                break;

            case 'e':
                input[i] = '3';
                break;

            case 'i':
                input[i] = '1';
                break;

            case 'o':
                input[i] = '0';
                break;
        }
    }

    return input;
}

As you can see there is no need to use the function strlen.

But in any case bear in mind that the return type of the function strlen is the unsigned integer type size_t that usually is declared as an alias for the type unsigned long. So not use the signed type int. And you should declare variables in minimum scopes where they are used. So the variable n which is used within the for loop in your function should be declared in the for statement at least like

for ( size_t i = 0, n = strlen( input); i < n; i++)

Pay attention to that the letter 'u' is also a vowel. However it is not processed in your function.

If you need to replace also upper case vowels then rewrite the case labels like for example

case 'a': case 'A':
    *s = '6';
    break;
    //...

 

or

case 'a': 
case 'A':
    *s = '6';
    break;
    //...
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • @ikegami It is unclear whether he needs to replace also upper case vowels. – Vlad from Moscow Jun 13 '23 at 16:42
  • Pointers are only taught in [week 4 of the CS50 course](https://cs50.harvard.edu/x/2023/weeks/4/). However, this exercise is from week 2 of the CS50 course. Therefore, I'm afraid that OP won't be able to understand your solution which uses a pointer, because OP probably has not learnt that yet. – Andreas Wenzel Jun 13 '23 at 18:26
  • Thanks for the help. We haven´t seen pointers yet so I´ll have to come back to this solution when it´s clearer for me - slowly getting there ;) – soge king Jun 14 '23 at 07:52
  • 1
    @AndreasWenzel You are right. I used the variable n because in the original code there is used the function strlen. I have updated the code. – Vlad from Moscow Jun 14 '23 at 13:58
1

The text of the assignment states the following:

Your program must contain a function called replace which takes a string input and returns a string output.

It also states:

The input parameter for the replace function will be argv[1] and the return value is the converted word.

However, you declared the function replace like this:

char replace(string input);

This is wrong. According to the instructions, the function should return a string instead of a single char, like this:

string replace(string input);

Another issue is that the line

return s[n];

is wrong, because s[n] is a character, but you need to return a string (i.e. several characters).

You could write

return s;

instead, which will return a reference to the string s. However, this will also not work, for the following reason:

In contrast to data types such as int, char, float and double, the CS50 data type string is special. A variable of type string does not actually represent several characters. It rather represents a reference to a character array. It is not a character array itself. The technical term for such a reference is a "pointer". You will learn all about pointers and their relationship to the data type string in week 4 of CS50.

When you write

return s;

you are not returning the values of the characters in the array s, but rather a reference to the array s.

However, once the function replace returns, the local array s will cease to exist. Therefore, it does not make sense to return a reference to that non-existant array.

There are several possible solutions to this problem, such as

  1. use a global array instead of a local array, so that the lifetime of the array does not end when the function returns, or

  2. create a new array using dynamically allocated memory, so that you have full control of the lifetime of the array, or

  3. instead of writing to a separate array, simply overwrite the input array argv[1] and return a reference to that array.

I do not recommend that you use solution #1, because that solution is rather ugly.

Solution #2 would generally be a good solution, but this would require knowledge that you will only acquire in week 4 of CS50. Since you probably still are in week 2, I do not recommend that you attempt this until after you completed week 4 of the course.

Therefore, I recommend that you use solution #3 for now. Here is an example:

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

string replace(string input);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Incorrect number of arguments\n");
        return 1;
    }
    else
    {
        printf("%s\n", replace(argv[1]));
    }
}

string replace(string input)
{
    int n = strlen(input);

    for (int i = 0; i < n; i++)
    {
        switch (input[i])
        {
            case 'a':
                input[i] = '6';
                break;
            case 'e':
                input[i] = '3';
                break;
            case 'i':
                input[i] = '1';
                break;
            case 'o':
                input[i] = '0';
                break;
        }
    }

    return input;
}

For the input

testinput

this program has the following output:

t3st1nput
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39