0

It seems like the %s in the final printf is entirely being skipped.

This is the entire code:

#include <stdio.h>

int main(void){
    char address[100];
    char city[100];
    char state[2];
    char zip[15];

    printf("Enter street address: ");
    scanf(" %[^\n]",&address);

    printf("Enter city: ");
    scanf(" %[^\n]",&city);

    printf("Enter state: ");
    scanf(" %s",&state);

    printf("Enter ZIP Code: ");
    scanf(" %s",&zip);

    printf("%s\n%s, %s %s",address,city,state,zip);

    return 0;
}

When this address is entered:

1 Main Street
New York City, NY 12345

The program prints:

1 Main Street
, NY 12345

I can't figure out the cause of this issue.
Any help would be greatly appreciated because I'm out of ideas.

Azeem
  • 11,148
  • 4
  • 27
  • 40
Ben R.
  • 7
  • 2
  • 1
    Start by checking the return values of `scanf()`. – Sourav Ghosh Feb 12 '19 at 05:09
  • The "city" is `New York City, NY 12345`, what is wrong with considering the code supplied `scanf(" %[^\n]",&city);`? Rather than stopping as `'\n`, stop at `','`? – chux - Reinstate Monica Feb 12 '19 at 05:14
  • Since the arguments to `scanf()` are all arrays, the `&` in front of the name is inappropriate — though you get away with it in this context, there are others where you wouldn't (such as when the 'arrays' are arguments to a function containing the `scanf()` calls). – Jonathan Leffler Feb 12 '19 at 06:04
  • Is there any possibility that you're on a Windows machine, and the CRLF line ending is screwing things up? Have you tried checking the return value from each `scanf()` call; that's important. You should also print each variable so it is clear what's in it. For example, `printf("[[%s]]\n", address);` where the square brackets are simply a marker that helps spot problems. If I'm on track, you might see `]]1 Main Street` for the address. (Are you typing the address, or are you feeding it from a file?) – Jonathan Leffler Feb 12 '19 at 06:13
  • @Vagish: This is somewhat similar to your suggested duplicate [scanf: `“%[^\n]”` skips the 2nd input but `“ %[^\n]”` does not. why?](https://stackoverflow.com/questions/6083045/scanf-n-skips-the-2nd-input-but-n-does-not-why), but this code already uses a leading blank in all the `scanf()` formats to avoid the main problems that the other question is dealing with. – Jonathan Leffler Feb 12 '19 at 06:18
  • 3
    You have a number of problems. First you invoke *Undefined Behavior* attempting to read `NY` into `char state[2];`. `state` can only hold a string of 1-character (plus the *nul-terminator*). Next, unless you provide the conditional checks (and the appropriate input setup) to read more than one (addr, city, state, zip) as a single input -- you can't just enter `"New York City, NY 12345"` and hope it gets separated and stored in separate variables. You can provide conversion specifiers for every part in a single `scanf` call and check the return to see how many succeeded. – David C. Rankin Feb 12 '19 at 06:28
  • 1
    @DavidC.Rankin: Ah — that point about NY into `char state[2];` is good! It explains the problem, assuming that `state` comes just before `city` in memory, then the null after `NY` overflows into `city[0]`, effectively zapping the city name completely. It also means that the input was not entered as claimed — it was entered on 4 lines, probably without a comma after the city. – Jonathan Leffler Feb 12 '19 at 06:34
  • 2
    Yes, and quite by happy accident, I was just concentrating on the storage requirement and you picked up on the *nul-character* pushing into `city` (a thought that had not yet fluttered through my mind `:)` – David C. Rankin Feb 12 '19 at 06:40
  • Ben: please note that one of the problems for those trying to assist you was that you (unintentionally, I'm sure) misled us about what was typed into the program. I now think you typed 4 lines of input — `1 Main Street` — `New York City` — `NY` — `12345` — and the output was supposed to look like the two lines that are claimed to be the input. Please be very careful to describe exactly what you type, or show us what the input and output looks like (text — not a screen shot!) so that we know what you're doing. There's a chance I'm wrong; if so, please shout. But it makes sense of your problem. – Jonathan Leffler Feb 12 '19 at 06:51

3 Answers3

0
#include <stdio.h>

int main(void){
    char address[100];
    char city[100];
    char state[2];
    char zip[15];

    printf("Enter street address: ");
    scanf(" %[^\n]",&address);

    printf("Enter city: ");
    scanf(" %[^\n]",&city);

    printf("Enter state: ");
    scanf(" %s",&state);

    printf("Enter ZIP Code: ");
    scanf(" %s",&zip);

    printf("\nONE: %s\n",address);
    printf("TWO: %s\n",city);
    printf("THREE: %s\n",state);
    printf("FOUR: %s\n",zip);

    return 0;
}

Copy paste this into https://www.codechef.com/ide and you will see the following output:

Enter street address: Enter city: Enter state: Enter ZIP Code: 
ONE: 1 Main Street
TWO: New York City, NY 12345
THREE: 
FOUR: @

You are storing everything in city, instead of stopping at the comma. What do you think your scanf for city is doing?

Bwebb
  • 675
  • 4
  • 14
  • I agree with your analysis that `city` should end up with all the second line of the address if it is entered as a single line. There are at least two issues with that, though: (1) if the information is entered at the keyboard, the code would be prompting for `Enter state:` and the user would have to indicate EOF (control-D on Unix, control-Z on Windows); and (2) that doesn't really explain why `New York City` is missing. I don't have a good explanation either — I think we probably aren't being given the whole story by the OP. – Jonathan Leffler Feb 12 '19 at 06:26
  • good point, my choice of online IDE has a box for "input" but it is not like terminal/console input would be in linux/windows. Actually im not sure about that though, i think i could have tweeked the input with forced carriage returns and line feeds to mimic the staggered console input. I think we need more info from the OP – Bwebb Feb 12 '19 at 06:33
  • dang I overlooked the buffer overflow that David mentioned too. That seems like its the issue, although i still dont see how he gets the comma. Seems like city is printing " , " even though it would start with '/0' from the overflow. – Bwebb Feb 12 '19 at 06:41
  • I think that we've been misled about what was typed into the program. I think the user typed 4 lines of input — `1 Main Street` — `New York City` — `NY` — `12345` — and the output was supposed to look like the two lines that are claimed to be the input. This is more reasonable than that the user magically typed EOF, or redirected from a file, or … . Yes, the buffer overflow explains the output, but the misleading information in the question about what was typed as the input didn't help anybody. – Jonathan Leffler Feb 12 '19 at 06:43
0

The follow code is run well on my workstation.

#include <stdio.h>
int main(void){
    char address[100];
    char city[100];
    char state[2];
    char zip[15];
    printf("Enter street address: ");
    scanf(" %[^\n]",address);
    printf("Enter city: ");
    scanf(" %[^\n]",city);
    printf("Enter state: ");
    scanf(" %s",state);
    printf("Enter ZIP Code: ");
    scanf(" %s",zip);
    printf("%s\n%s, %s %s",address,city,state,zip);
    return 0;
}
Vineeth Sai
  • 3,389
  • 7
  • 23
  • 34
  • Welcome to Stack Overflow. I think you need to show a run of the program to explain what you type and the output you get. Notice that the question shows the city/state/zip input all entered on a single line. It would also be worth pointing out the important change you made to the `scanf()` calls, dropping the `&` that's used in the question. – Jonathan Leffler Feb 12 '19 at 06:08
  • 2
    You may also want to explain how the 2-character `"NY"` is read as a string into `char state[2];` along with the *nul-terminating* character. – David C. Rankin Feb 12 '19 at 06:32
0

As noted in the comments and in the other answers, you have a number of problems. The first two that immediately invoke Undefined Behavior are:

  1. Attempting to read the state "NY" as a string into char state[2];. To be a valid string in C, the characters must be terminated by a nul-terminating character. Meaning to store a 2-character state abbreviation, you need 3-characters of storage (minimum). E.g. {'N', 'Y', '\0'}. (Master @JonathanLeffler deduced how the immediate consequence of the short storage for state could cause the '\0' character to be stored as the first character in city causing city to be an empty-string);
  2. When reading strings with scanf you must provide a pointer to sufficient storage for the string you are reading. Since address, city, state, zip are character arrays, on access, they are converted to a pointer to the first character (see: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)) So each is already a pointer when used as a argument for scanf and no '&' (address of) operator need precede them in the argument list.

Additional notes, avoid using magic-numbers in your code unless absolutely necessary. 100, 2, 15 are magic-numbers below.

    char address[100];
    char city[100];
    char state[2];
    char zip[15];

If you need a constant for the number of characters in address, city, state, zip, #define one for each or use a global enum to do the same thing, e.g.

enum { STSZ = 3, ZIPSZ = 15, CIADDR = 100 };    /* constants */

(note city and address are both 100, so a single CIADDR constant will do)

When are number absolutely required in your code? When providing a field-width modifier to protect your array bounds when reading with the scanf family of functions. Additionally, when using the scanf family, you must check the return, every time. Otherwise a matching or input failure can occur (or the user could generate a manual EOF to cancel input) and you blindly push forward using the variable that wasn't filled and likely left indeterminate invoking Undefined Behavior.

Putting those pieces together, and thinking forward that you just may find yourself dealing with more than 1 address in your code, the following is an example that can read city, state zip values in a single line of text and the values are stored in a structure. (which allows you to declare an array of struct, or a pointer and allocate as needed when dealing with more than one address later on)

#include <stdio.h>

enum { STSZ = 3, ZIPSZ = 15, CIADDR = 100 };    /* constants */

typedef struct {            /* simple struct presuming in the future */
    char address[CIADDR],   /* you may have more than 1 address */
        city[CIADDR],
        state[STSZ],        /* STSZ must be 3 to read a string of 2-char */
        zip[ZIPSZ];
} loc_t;

int main (void) {

    loc_t location1 = { .address = "" };    /* declare/initialize struct */

    printf ("enter street address: ");      /* prompt/read/validate address */
    if (scanf (" %99[^\n]", location1.address) != 1) {
        fputs ("sscanf() error: invalid address.\n", stderr);
        return 1;
    }

    printf ("enter city: ");                /* prompt/read/validate city */
    if (scanf (" %99[^,],", location1.city) != 1) {
        fputs ("sscanf() error: invalid city.\n", stderr);
        return 1;
    }

    printf ("enter state: ");               /* prompt/read/validate state */
    if (scanf (" %2s", location1.state) != 1) {
        fputs ("sscanf() error: invalid state.\n", stderr);
        return 1;
    }

    printf ("enter zip: ");                 /* prompt/read/validate zip */
    if (scanf (" %14s,", location1.zip) != 1) {
        fputs ("sscanf() error: invalid zip.\n", stderr);
        return 1;
    }

    /* output results preceeded by 2-newlines */
    printf ("\n\n%s\n%s, %s %s\n", location1.address, location1.city,
            location1.state, location1.zip);
}

(note: numbers for the field-width modifiers are included in each scanf call to protect your array bounds. additionally the multiple '\n' before the output compensates for the unused prompts when city, state zip is all entered at the "city: " prompt)

Example Use/Output

Entering "New York City, NY 12345" as one string at the "enter city: " prompt:

$ ./bin/readaddr
enter street address: 1 Main Street
enter city: New York City, NY 12345
enter state: enter zip:

1 Main Street
New York City, NY 12345

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

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85