1

So, I am trying to make a text based game to help people learn linux and I am trying to make it so, if your name is Linus Torvalds instead of your guide being Linus Torvalds it will be Richard Stallman, the problem is that with any name input the print screen allways says that the guide is Richard Stallman. (using C btw)

Code here:

<!-- language: c -->


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

//Global variables
char name[15];
char yesno[1];

//Main
int main(){
    system("clear");
    printf("???: Hello adventurer, are you here to learn Linux?\n");
    printf("y/n\n");

    scanf("%c", yesno);

    if (strcmp("n", yesno)){
        printf("???: Great!, What is your name?\n");
        
        scanf("%s", name);
        
        if("Linus Torvalds\n"){
            printf("Achievment complete: In God We Trust\n");
            printf("Nice to meet you!, my name is Richard Stallman.\n");
        }else {
            printf("Nice to meet you!, my name is Linus Torvalds.\n");
        }
    }
    else if (strcmp("y", yesno)){
        printf("Ok!, bye!");
    }else {
        printf("That's not an answer.\n");
    }
}

I have tried with strcmp, mallocs, plain conditions, but it doesn't work, if anyone has an answer, it is much apreciated.

P.S.

please try to include code in your answers and/or make them as detailed as possible, Thaks.

Eminion
  • 23
  • 6
  • 3
    `strcmp()` compares two strings (i.e. null-terminated arrays of characters). `yesno` is not a string. – dimich Jul 05 '23 at 04:02
  • Also note that `strcmp` is case-sensitive. The string `"foo"` is *not* equal to the strinbg `"Foo"`. For some reason C doesn't have a case-independent comparison function, but compilers and environments have their own implementations of them (e.g. `strcasecmp` or `stricmp`). – Some programmer dude Jul 05 '23 at 04:04
  • Side note: `system("clear");` is not the recommended way to clear the screen. Although it will probably work for you for now, once you are more advanced in programming, you will probably want to take a look at [the alternatives](https://cplusplus.com/articles/4z18T05o/). – Andreas Wenzel Jul 05 '23 at 04:12
  • What do you think `if("Linus Torvalds\n")` does? Hint: In this context, it compares the string pointer to `NULL`. Since it isn't, the result will be true. So this is equivalent to `if (1)`. – Tom Karzes Jul 05 '23 at 06:24
  • 1
    Also, since `yesno` is a single-character array, and not null-terminated, you can't treat it as a string. If you want it to be a single-character string, you need to declare it with two elements, and set the second element to the null character. – Tom Karzes Jul 05 '23 at 06:27

1 Answers1

2

Using scanf with the %s format specifier will only read a single word. If you want to read an entire line consisting of several words (e.g. "Linus Torvalds\n"), then I suggest that you use fgets instead. However, beware of this problem regarding mixing fgets and scanf. Also, see this question on how to remove the newline character from the fgets input. I suggest that you don't use scanf at all for user input, but instead always use fgets.

The condition if("Linus Torvalds\n") does not make sense, as that condition will always be true. If you want to compare the content of name with "Linus Torvalds\n", then you need to use the strcmp function.

Also, the line

if (strcmp("n", yesno)){

is wrong, because the function strcmp requires both of its arguments to be a pointer that each point to a string, i.e. to a sequence of characters terminated by a null character. However, yesno is not a pointer. &yesno would also be wrong, because such a pointer would only point to a single character, not to a sequence of characters terminated by a null character.

The function strcmp will return zero if the two strings match, and non-zero if they don't. Therefore, you probably want to compare the return value of strcmp with zero.

I suggest that you rewrite your program like this:

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

void get_line_from_user( const char prompt[], char buffer[], int buffer_size );

int main( void )
{
    char input[200];

    get_line_from_user(
        "Hello adventurer, are you here to learn Linux? (y/n) ",
        input, sizeof input
    );

    if ( strcmp( input, "y" ) == 0 )
    {
        get_line_from_user(
            "Great! What is your name? ",
            input, sizeof input
        );
        
        if ( strcmp( input, "Linus Torvalds" ) == 0 )
        {
            printf( "Achievement complete: In God We Trust\n" );
            printf( "Nice to meet you! My name is Richard Stallman.\n" );
        }
        else
        {
            printf( "Nice to meet you! My name is Linus Torvalds.\n" );
        }
    }
    else if ( strcmp( input, "n" ) == 0 )
    {
        printf( "Ok! Bye!" );
    }
    else 
    {
        printf( "That's not an answer.\n" );
    }
}

//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
    for (;;) //infinite loop, equivalent to while(1)
    {
        char *p;

        //prompt user for input
        fputs( prompt, stdout );

        //attempt to read one line of input
        if ( fgets( buffer, buffer_size, stdin ) == NULL )
        {
            printf( "Error reading from input!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to find newline character
        p = strchr( buffer, '\n' );

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small to store the entire line)
        if ( p == NULL )
        {
            int c;

            //a missing newline character is ok if the next
            //character is a newline character or if we have
            //reached end-of-file (for example if the input is
            //being piped from a file or if the user enters
            //end-of-file in the terminal itself)
            if ( (c=getchar()) != '\n' && !feof(stdin) )
            {
                if ( c == EOF )
                {
                    printf( "Error reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

                printf( "Input was too long to fit in buffer!\n" );

                //discard remainder of line
                do
                {
                    c = getchar();

                    if ( c == EOF )
                    {
                        //this error message will be printed if either
                        //a stream error or an unexpected end-of-file
                        //is encountered
                        printf( "Error reading from input!\n" );
                        exit( EXIT_FAILURE );
                    }

                } while ( c != '\n' );

                //reprompt user for input by restarting loop
                continue;
            }
        }
        else
        {
            //remove newline character by overwriting it with
            //null character
            *p = '\0';
        }

        //input was ok, so break out of loop
        break;
    }
}

This program has the following behavior:

Hello adventurer, are you here to learn Linux? (y/n) y
Great! What is your name? Jimmy
Nice to meet you! My name is Linus Torvalds.
Hello adventurer, are you here to learn Linux? (y/n) y
Great! What is your name? Linus Torvalds
Achievement complete: In God We Trust
Nice to meet you! My name is Richard Stallman.
Hello adventurer, are you here to learn Linux? (y/n) n
Ok! Bye!
Hello adventurer, are you here to learn Linux? (y/n) sdfsdgf
That's not an answer.
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • Just a question, what is the last part of the code do? – Eminion Jul 06 '23 at 01:19
  • I mean the part that starts with the for(;;){ – Eminion Jul 06 '23 at 01:19
  • @Eminion: There are many comments in my code for the function `get_line_from_user`. Is there something specific that you do not understand? The `for (;;)` loop is an infinite loop which will loop forever until the input is valid. In that case, the `break` statement is executed, which will break out of the loop. As far as the function `get_line_from_user` is concerned, the input is valid if it was short enough to fit into the memory buffer. If it was too long to fit into the buffer, then the loop will not terminate and the user will be reprompted for input. – Andreas Wenzel Jul 06 '23 at 06:39
  • Ah thanks, I apreciate yout help and the time you took to re-write my code. – Eminion Jul 07 '23 at 03:25
  • @Eminion: You can test the behavior of the loop of my function `get_line_from_user` with [this](https://onlinegdb.com/ZTSl7MMcJ) short test program. In that short test program, I have reduced the buffer size to only 5 characters, so that it can only store 4 input characters (plus the terminating null character). All you have to do is press the green "Run" button to test it. If the input you enter is too long, then the function will automatically reprompt you for user input. If all you wanted was an error message and for the program to quit in that case, the loop would not be necessary. – Andreas Wenzel Jul 07 '23 at 16:48