-4

Can't figure out why my printf output won't print the int data.age or addr.zip correctly. They're defined as int, so %d should work...but it doesn't. I get gibberish numbers for the output. All other fields work perfectly.

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

typedef struct BillingAddress {
    char *street[50];
    char *city[25];
    char *state[3];
    int *zip[6];

}address;

address addr;

typedef struct ContactInfo {
    char *name[30];
    int *age[3];
    char *phone[15];
    struct BillingAddress PersonalData;
}personaldata;

personaldata data;

int main()
{
    printf("Enter your full name: ");
    scanf(" %49[^\n]", &data.name);
    printf("Enter your age: ");
    scanf("%d", &data.age);
    printf("Enter your Phone Number (xxx) xxx-xxxx: ");
    scanf(" %14[^\n]", &data.phone);
    printf("Enter your street address: ");
    scanf(" %49[^\n]", &addr.street);
    printf("Enter your city: ");
    scanf(" %24[^\n]", &addr.city);
    printf("Enter your state abbreviation: ");
    scanf("%s", &addr.state);
    printf("Enter your zip code: ");
    scanf("%d", &addr.zip);

    printf("Personal Data: \n %s\n %d\n %s\n %s\n %s\n %s\n %d\n", data.name, data.age, data.phone, addr.street, addr.city, addr.state, addr.zip);
}
dejjen
  • 1
  • 3
  • 1
    Explain why you need the `*`s like in `char *name[30];`. – Jabberwocky Nov 16 '21 at 08:15
  • 1
    Get rid of all those `*`. It should be `char street[50];` – Barmar Nov 16 '21 at 08:15
  • 1
    And you don't need `&` when you're scanning into a string. – Barmar Nov 16 '21 at 08:16
  • Doesn't the compiler show some warnings? `&data.age` is of type `int*[]` while `scanf` expects `int*`. – Gerhardh Nov 16 '21 at 08:17
  • @Jabberwocky, I have no clue. I'm learning, and the example I was given had the *'s in it so I went with that. – dejjen Nov 16 '21 at 08:19
  • @Barmar, I'll take those characters out. As mentioned, I'm just learning functions and the example I was given to go by had it that way. I'll remove the *'s and the &'s. – dejjen Nov 16 '21 at 08:20
  • @Gerhardh, No, gcc gave no errors at all. – dejjen Nov 16 '21 at 08:21
  • 4
    You can't learn C by trying random stuff found somewhere on the internet. Get a book. – Jabberwocky Nov 16 '21 at 08:21
  • Make sure you use the `-Wall` option when compiling, it will give warnings. – Barmar Nov 16 '21 at 08:21
  • 2
    Then you need to turn up warning level. For GCC use `-Wall -Wextra`. – Gerhardh Nov 16 '21 at 08:22
  • You misunderstood the examples. You need `&` when scanning into int and float variables, but not strings. – Barmar Nov 16 '21 at 08:22
  • As a general rule, don't write code that you don't understand, and don't ignore any warnings from the compiler… – Arkku Nov 16 '21 at 08:24
  • @Jabberwocky, I'm not really trying to learn C. I'm doing a class on Cyber Forensics, and I guess it was expected that we know C for a reverse engineering project, though that was not on the list of prerequisites. I'm stumbling my way through this the best way I can. – dejjen Nov 16 '21 at 08:27
  • Also, a single `int` can store integers greater than just one digit, you don't need 3 or 6 for age and zip. (However, I think storing zip as an integer is a bad idea, I would store it as a string.) – Arkku Nov 16 '21 at 08:27
  • @Arkku, see my explanation to Jabberwocky. – dejjen Nov 16 '21 at 08:28
  • 1
    Well, good luck with the random stuff, then. =) – Arkku Nov 16 '21 at 08:28
  • @Arkku, I set the lengths as kind of an input validation. I didn't want it to accept more than two numbers for age, and 5 for the zip. – dejjen Nov 16 '21 at 08:29
  • That idea makes no sense at all for multiple reasons you would know if you spent an hour actually learning C. (edit: from a proper source, rather than by copypasting random stuff from the internet) – Arkku Nov 16 '21 at 08:30
  • @Arkku, I've spent almost 40 hours now trying to learn. But thanks. – dejjen Nov 16 '21 at 08:32
  • @dejjen, that's a lot of time wasted. Why didn't you just go to the local store and pick a good copy of the `C-Programming Language`? – kesarling He-Him Nov 16 '21 at 08:38
  • @Barmar, the -Wall option (thanks for that btw) says the following: 40:37: warning: format '%d' expects argument of type 'int', but argument 3 has type 'int *' – dejjen Nov 16 '21 at 08:38
  • Why is `age` an array at all? `int age;` – Barmar Nov 16 '21 at 08:39
  • And `zip` should be a string, not integer. – Barmar Nov 16 '21 at 08:40
  • @kesarlingHe-Him because we were only given a week to get this lab done. There's no way I could have learned enough C in a week to be proficient enough to not make these mistakes. As a result, I've spent hours Googling examples, trying to figure this out. In hindsight, you're right...I probably should have done that. I just didn't expect it to be this complicated. – dejjen Nov 16 '21 at 08:40
  • Yes! A Whole Week!! That's probably all the time required to learn the basics of C – kesarling He-Him Nov 16 '21 at 08:42

1 Answers1

0

Let's go step by step. In your BillingAddress struct definition, you intend to store the street, city, and state. It seems logical that you could represent all of those parameters as strings (which are character arrays in C). I believe that is what you tried to do, but the declaration:

char *street[50];

represents give you an array of 50 char * (i.e., char pointers) NOT 50 chars, which is what you actually want. So, the struct definition should instead be:

typedef struct BillingAddress {
    char street[50];
    char city[25];
    char state[3];
    int zip;
} address;

You also intend to store the zip. Note how I changed the type of zip to an int array rather than an int array. You could do an int array, but you would have to do more work to properly accept the user's input (simply using scan("%d", &addr.zip) will not work).

Now, let's take a looked at a different way to define your definition for ContactInfo struct:

typedef struct ContactInfo {
    char name[30];
    int age;
    char phone[15];
    address addr;
} personaldata;

You can see that I've removed the *'s and changed age to be a single int for the similar reasoning as what I mentioned above. I've also replaced struct BillingAddress with the simpler address. Why? Because you created a typedef linking the keyword address to struct BillingAddress. So, by using address alone, the code looks a bit cleaner and you are putting that typedef to good use :D (Note that there's nothing incorrect about using struct BillingAddress, I just think it looks cleaner to utilize the typedef).

Also, you'll see that I renamed the variable of type address (i.e., of type struct BillingAddress -- remember the typedef means these two are the same) to addr. This makes more sense than naming it PersonalData as you did, because well, it's an address, not arbitrary personal data.

Now moving onto your main() method. You should be aware of some of the pitfalls of using scanf(). Since it reads from the default input stream stdin (i.e., most likely your terminal), any characters not gulped up by scanf() will be left in the input stream. So, any subsequent calls to scanf() will also read in those unwanted characters. See this post for more info. You might not have run into this if you supplied the less than the max number of desired characters, but it is important to take care of this error case. So, after each scanf(), you should clear the input stream, which can be done using a method like:

void clear_input_stream()
{
    int c;
    while ((c = fgetc(stdin)) != '\n' && c != EOF);
}

You can call this method after each one of your scanf() calls.

You want to make sure that if you are writing into a char array you should not add the & in front of the variable you are writing to -- check this answer for an explanation (your compiler should warn you about that).

The last thing I want to mention is that you could also add a length to the %d specifier to limit reading an integer of a certain length. Your main() could look something like this:

int main()
{
    printf("Enter your full name: ");
    scanf(" %49[^\n]", data.name); 
    clear_input_stream();
    printf("Enter your age: ");
    scanf(" %3d", &data.age); 
    clear_input_stream();
    printf("Enter your Phone Number (xxx) xxx-xxxx: ");
    scanf(" %14[^\n]", data.phone); 
    clear_input_stream();
    printf("Enter your street address: ");
    scanf(" %49[^\n]", addr.street); 
    clear_input_stream();
    printf("Enter your city: ");
    scanf(" %24[^\n]", addr.city); 
    clear_input_stream();
    printf("Enter your state abbreviation: ");
    scanf(" %2[^\n]", addr.state); 
    clear_input_stream();
    printf("Enter your zip code: ");
    scanf(" %5d", &addr.zip); 
    clear_input_stream();

    printf("Personal Data: \n %s\n %d\n %s\n %s\n %s\n %s\n %d\n", data.name, data.age, data.phone, addr.street, addr.city, addr.state, addr.zip);

    return 0;
}
ice05
  • 499
  • 2
  • 8
  • `char c;` should be `int c;`. Also you should check the return value of `scanf`, and there is some bizarre `s` in your format strings – M.M Nov 17 '21 at 01:27