1

Here is my assignment:

Ask the user to input their name.

If their name ends with a vowel, ask them to input their age as well.

If their age is even, print Wow, you're special!. Otherwise, if their age is odd, ask them to input their birth year.

If their birth year is even, print Oh, you're still special!. Otherwise, print You will be special next year..

If their name ends with a consonant though, print You're awesome!

Here is my code:

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

int main() {
    // variables
    char name[100];
    int age, birth;

    printf("Enter name: ");
    scanf("%[^\n]s", &name);
    
    // formula for getting last letter of the name
    int size = strlen(name);
    int last = size - 1;
    
    if (name[last] == 'a' || name[last] == 'e' || name[last] == 'i' ||
        name[last] == 'o' || name[last] == 'u') {
        printf("Enter age: ");
        scanf("%d", &age); 
        
        if (age %2 == 0) {
            printf("Wow, you're special!\n");
        } else {
            printf("Enter birth year: ");
            scanf("%d", &birth);
        }
        
        if (birth % 2 != 0) {
            printf("You will be special next year.\n");
        } else {
           printf("Oh, you're still special!\n");
        }
    } else {
        printf("You're awesome!\n");
    } // end of nested if

    return 0;
}

The problem is with the birth variable: the age and birth variables seems to be connected, because when the condition of age executes the condition of birth executes as well leading to a multiple executions of conditions.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Reece
  • 31
  • 4
  • 3
    [Why should I not upload images of code/data/errors?](https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors) – Some programmer dude Feb 18 '23 at 14:55
  • Welsome to StackOverflow. Please take a [tour] and see [ask]. Specifically post all your code, error messages etc. as copy-pasted text, **not** images/links. – wohlstad Feb 18 '23 at 14:55
  • Also please take some time to read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Feb 18 '23 at 14:55
  • 2
    @TomKarzes: Testing `birth` yields an indeterminate value, not undefined behavior. Its address is taken, so it could not have been declared `register`, so C 2018 6.3.2.1 2 does not apply, just 6.2.4 6. – Eric Postpischil Feb 18 '23 at 15:15
  • 2
    Please post a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) that includes the definition of `main`, all appropriate `#include` directives, and generally compiles without obvious error. Miscellaneous or incomplete code snippets are frustrating to offer advice on because it requires speculating about what is missing from the example. Post the exact, complete code you want help with. – Oka Feb 18 '23 at 15:20
  • What is the exact error message? What problem is there with the birth variable? – AbdurRehman Khan Feb 18 '23 at 15:26
  • Initialize your variables `char name[100] = {0}; int age = 0, birth = 0;` in your working code. Please stop editing your posted code. It confuses the comments. – ryyker Feb 18 '23 at 15:31
  • Thanks! Sorry for the inconvenience. I'll fix my future questions. – Reece Feb 18 '23 at 15:38
  • @EricPostpischil: You are correct that reading the uninitialized value of `birth` does not necessarily invoke undefined behavior. However, if `birth` happens to have a trap representation, then, according to [§6.2.6.1 ¶5 of the ISO C11 standard](http://port70.net/~nsz/c/c11/n1570.html#6.2.6.1p5), the behavior is undefined. – Andreas Wenzel Feb 18 '23 at 15:41
  • @AndreasWenzel: It cannot have a trap representation in C implementations in which the `int` type does not have a trap representation, which is most common C implementations. – Eric Postpischil Feb 18 '23 at 19:45

3 Answers3

3

"%[^\n]s" is a typo. %[ and %s are two separate scanf specifiers - you do not combine them as such. What you have is a %[ specifier that reads characters until a newline, and then the format string attempts to match a literal s character.

An unbound %[ is as dangerous as gets. You most provide a maximum field-width specifier that is at most the size of your array minus one (e.g., %99[^\n]) to limit the amount of data scanf reads, and prevent a buffer overflow.

&name would be of type char (*)[100], that is a pointer to an array. %[ expects a char *, simply a pointer to char. Passing an array to a function causes it to decay to a pointer to its first element - you do not need the & operator here.

You must test the return value of scanf is the expected number of conversions, otherwise you are operating blindly, and may utilize uninitialized or otherwise indeterminate values.

You should initialize birth, otherwise its value is indeterminate. In the event that age is even, you would attempt to use this indeterminate value in birth % 2 != 0.

Failing to correct most of the above issues will lead to problems, including Undefined Behaviour.

A safer example program to study:

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

int main(void)
{
    char name[100];
    int age;
    int birth = 0;

    printf("Enter name: ");
    if (1 != scanf("%99[^\n]", name)) {
        fprintf(stderr, "Could not read <name>.\n");
        return EXIT_FAILURE;
    }

    size_t length = strlen(name);

    if (!length) {
        fprintf(stderr, "<name> is empty!\n");
        return EXIT_FAILURE;
    }

    if (!strchr("aeiou", name[length - 1])) {
        puts("Name does not end in a vowel.");
        return EXIT_SUCCESS;
    }

    printf("Enter age: ");

    if (1 != scanf("%d", &age)) {
        fprintf(stderr, "Could not read <age>.\n");
        return EXIT_FAILURE;
    }

    if (age % 2 != 0) {
        printf("Enter birth: ");

        if (1 != scanf("%d", &birth)) {
            fprintf(stderr, "Could not read <birth>.\n");
            return EXIT_FAILURE;
        }
    }

    printf("NAME: <%s> AGE: <%d> BIRTH: <%d>\n", name, age, birth);
}
Oka
  • 23,367
  • 6
  • 42
  • 53
  • We are on the same page :) your program does not implement the expected behavior but should be interesting for the OP to study. – chqrlie Feb 18 '23 at 16:01
2

The conditions expressed in the assignment imply that you only test the birth year if the age is even... otherwise you do not even ask for the birth age. Your tests are not properly nested.

Note that scanf("%[^\n]s", &name); is incorrect:

  • you must tell scanf() the maximum number of characters to store to the destination array to avoid a potential buffer overflow;
  • &name is not the expected type, you should just pass name, which is an array that is converted automatically to a pointer to its first element when passed as an argument or used in an expression (except as an argument to sizeof or alignof);
  • the s in the format is meaningless. Use scanf(" %99[^\n]", name) instead;
  • test the return value to detect invalid or missing input and avoid undefined behavior later in the program.

Also note that letters can be uppercase and the last character may be neither a vowel nor a consonant (eg: X Æ A-12).

Here is a modified version, more consistent with the assignment:

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

int main() {
    // variables
    char name[100];
    int age, birth;

    printf("Enter name: ");
    // read up to 99 characters, skipping initial white space
    if (scanf(" %99[^\n]", name) != 1) {
        fprintf(stderr, "invalid or missing input for name\n");
        return 1;
    }
    
    // formula for getting last letter of the name
    size_t len = strlen(name);
    if (len == 0) {
        fprintf(stderr, "invalid empty name\n");
        return 1;
    }

    char last = name[len - 1];
    // test if last character is a vowel (trailing 'y' is a vowel)
    if (strchr("aeiouyAEIOUY", last)) {
        printf("Enter age: ");
        if (scanf("%d", &age) != 1) {
            fprintf(stderr, "invalid or missing input for age\n");
            return 1;
        }
        if (age % 2 == 0) {
            printf("Wow, you're special!\n");
        } else {
            printf("Enter birth year: ");
            if (scanf("%d", &birth) != 1) {
                fprintf(stderr, "invalid or missing input for birth\n");
                return 1;
            }
            if (birth % 2 == 0) {
                printf("Oh, you're still special!\n");
            } else {
                printf("You will be special next year.\n");
            }
        }
    } else {
        // the last character is not a vowel, test if it is a consonant
        if (strchr("bcdfghjklmnprstvwxzBCDFGHJKLMNPQRSTVWXZ", last) {
            printf("You're awesome!\n");
        }
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

of course you get two outputs, your if statements regarding age and birth are parallel. Shouldn't your birth block be nested inside of the else block for age?

ED818
  • 11
  • 2
  • ED818, this does not provide an answer to the question. Once you have sufficient [reputation](/help/whats-reputation) you will be able to [comment on any post](/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](//meta.stackexchange.com/q/214173). – Syscall Feb 18 '23 at 17:19
  • @Syscall I don't understand-- the problem was: two outputs. the question: why. and the answer is that OP didn't nest the second conditional. Is the format of my answer incorrect? I tested the solution and it worked. Or should I say something like: comment out line 26; change line 32 from } to }} – ED818 Feb 18 '23 at 19:00