0

I'm trying to create a program with a loop that prompts the user to enter data in the array elements. And when the user no longer can enter data, print to screen the data entered in a last in, first out order.

And this is my attempt...

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

struct Name_Age
{
    char Name[10];
    int Age;
};

void printMe(struct Name_Age info)
{
    printf("Name: %s\n", info.Name);
    printf("Age:  %d\n", info.Age);
}

int main()
{
    int size = 0, i = 0, j = 0;
    struct Name_Age * array_ptr = (struct Name_Age*)malloc((size + 1)* sizeof(struct Name_Age));
    struct Name_Age myInfo = *array_ptr;

    printf("Enter size of array: ");
    scanf("%d\n", size);

    for (i = 0; i < size; ++i)
    {
        printf("Enter Name: \n");
        scanf("%s\n", myInfo.Name);
        printf("Enter Age: \n");
        scanf("%d\n", myInfo.Age);
    }

    printMe(myInfo);

    return 0;

};
miiworld2
  • 296
  • 1
  • 2
  • 11
  • So what exactly is your error....? Also, you need to remove that semicolon after your ending brace. – RastaJedi May 25 '16 at 02:36
  • I would look into using `fgets()` instead of `scanf()`, also you might want to specify a size for `%s` to prevent overflow, especially since your `Name` variable is so small. And `scanf()` takes a `pointer` to the variable where it will store stuff, so since `myInfo,Name` will decay into a pointer to the first element in that array, you're fine for that case, but `scanf("%d\n", myInfo.Age);` must be changed to `scanf("%d\n", &myInfo.Age);`. I've made the update in my edit, along with some other stuff to make your answer more technically correct. – RastaJedi May 25 '16 at 02:42
  • So what is your question? – Ken White May 25 '16 at 02:56
  • 1
    @Rasta: Your edit is invalid, and I've voted to reject it. It is a violation of the policy here to substantially change the code in a question other than formatting, and you've altered the meaning and intent of the code with your edit. Please stop making those sorts of changes; if you continue, your editing privileges will end up being suspended. – Ken White May 25 '16 at 02:58
  • @KenWhite wait what exactly did I change I don't even remember now? I thought I just added the `&` needed for the integer value for `scanf()`? – RastaJedi May 25 '16 at 03:01
  • 1
    @Rasta: You made several changes to the code (including changing *main*), and **any** changes to the code other than formatting are against the guidelines here. Altering the code can hide or change the problem the poster is having. Even the edit of adding `&` is invalid when editing a question. **No code changes other than formatting are permitted.** – Ken White May 25 '16 at 03:03
  • @KenWhite I see, I'm sorry about that. So even removing a cast for return value for `malloc()` is wrong too? I apologize. To change gears a little bit, is it okay to pass a struct to a function as opposed to a pointer to that struct? Does it make a copy of it (if so, I didn't think "pass by value" was even remotely a thing in C)? I know when you pass arrays it really is using pointers automatically, but I really don't know the behavior with structs. – RastaJedi May 25 '16 at 03:05
  • 1
    @Rasta: Yes, A change to **anything** other than formatting (and even those if the language is sensitive to formatting) are prohibited. – Ken White May 25 '16 at 03:06

4 Answers4

1

You can use fgets to read strings and cast the string to digits with atoi. The storage is not complete, but with my changes you can read to structs and specify the size of the loop (TODO: Save a list of structs so that you actually can print a list of structs that you have specified.)

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

struct Name_Age {
    char Name[10];
    int Age;
};

void printMe(struct Name_Age info) {
    printf("Name: %s\n", info.Name);
    printf("Age:  %d\n", info.Age);
}

int main() {
    int size = 0, i = 0, j = 0;
    struct Name_Age *array_ptr = malloc((size + 1) * sizeof(struct Name_Age));
    struct Name_Age myInfo = *array_ptr;

    printf("Enter size of array: ");
    char tmp[10];
    fgets(tmp, 10,stdin);
    size = atoi(tmp);
    for (i = 0; i < size; ++i) {
        printf("Enter Name: ");
        fgets(myInfo.Name, 10,stdin);
        printf("Enter Age: ");
        fgets(tmp, 10,stdin);
        myInfo.Age = atoi(tmp);
    }

    printMe(myInfo);
    return 0;

};

Test

$ ./a.out 
Enter size of array: 2
Enter Name: Superman
Enter Age: 25
Enter Name: Batman
Enter Age: 27
Name: Batman

Age:  27

See also this question about fgets fgets how to read int

Community
  • 1
  • 1
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • Sadly we don't use fgets for this particular class. For challenge purposes. But I will keep this in mind for future references. Thx. – miiworld2 May 25 '16 at 03:52
1

First, scanf("%d", &size) replace scanf("%d\n", size), put &size instead of size as argument(You need an address), and put the malloc things after this line of code, because you need an exact size value before malloc. Same thing with all the scanf stuffs.

As you want to print out all your input names and ages in order, I changed your code like this:

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

struct Name_Age
{
    char Name[10];
    int Age;
};

void printMe(struct Name_Age *infoList, int size)
{
    int i;
    for (i = size-1; i >= 0; --i)
    {
        printf("Name: %s\n", infoList[i].Name);
        printf("Age:  %d\n", infoList[i].Age);
        printf("\n");
    }
}

int main()
{
    int size, i;

    printf("Enter size of array: ");
    scanf("%d", &size);

    struct Name_Age * array_ptr = (struct Name_Age*)malloc(size* sizeof(struct Name_Age));

    for (i = 0; i < size; ++i)
    {
        printf("Enter Name: \n");
        scanf("%s", array_ptr[i].Name);
        printf("Enter Age: \n");
        scanf("%d", &array_ptr[i].Age);
    }

    printMe(array_ptr, size);

    return 0;
}

Try to test and compare with your code, questions are welcome.

elricfeng
  • 364
  • 1
  • 8
  • 1
    Change `scanf("%s", &array_ptr[i].Name);` to `scanf("%s", array_ptr[i].Name);`, it is incorrect otherwise because the name of the array is already decaying to a pointer. And also, don't cast the return value of `malloc()`, see [here](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858#605858). – RastaJedi May 25 '16 at 03:11
  • 1
    @RastaJedi maybe `scanf("%s", &(array_ptr[i].Name))` is clearer, but not `scanf("%s", array_ptr[i].Name)`. – elricfeng May 25 '16 at 03:25
  • 1
    It's not a matter of what is clearer; it is _incorrect_, because using the name of an array already decays to a pointer to the first element, you are actually taking the memory address of the pointer to the first element. That is **not** what you want to be passing to `scanf()`. Actually, I think you are giving it a pointer to the entire array, and this is wrong because `%s` expects a _pointer to char_, i.e., `char *`, not a pointer to a character array.... (`char (*)[10]`): `warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char (*)[10]'`. – RastaJedi May 25 '16 at 03:31
  • 1
    Within the very first 5 examples of any C tutorial/book, they tell you to use `&` for `%d` for `scanf()`, but **NOT** for `%s`. Everyone knows that, and doing so is incorrect (see above); please do not suggest incorrect code to OP. – RastaJedi May 25 '16 at 03:36
  • This works tremendously! Thank you both! I appreciate the feedback and the explanation :) – miiworld2 May 25 '16 at 04:03
  • @RastaJedi Yes, you're right, I didn't take enough care about it. I've edited the post, thanks! – elricfeng May 25 '16 at 04:23
  • @Wenfeng You're welcome and I'm sorry if I came off sort of brash; that wasn't my intention :). And also +miiworld2 you are welcome :). – RastaJedi Jul 19 '16 at 00:01
1

Obviously using fgets() is a much better approach, but making the fewest amount of changes as possible to your code and still achieving your result is the following:

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

struct Name_Age
{
    char Name[10];
    int Age;
};

void printMe(struct Name_Age *info);

int main(void)
{
    int size, i;
    struct Name_Age *array_ptr;

    printf("Enter size of array: ");
    scanf("%d", &size);

    array_ptr = malloc(size * sizeof *array_ptr);

    for (i = 0; i < size; ++i)
    {
            printf("Enter Name: ");
            scanf(" %s", array_ptr[i].Name);
            printf("Enter Age: ");
            scanf("%d", &array_ptr[i].Age);
            printf("\n");
    }

    for (i = 0; i < size; ++i)
            printMe(&array_ptr[i]);

    return 0;
}

void printMe(struct Name_Age *info)
{
    printf("Name: %s\n", info->Name);
    printf("Age:  %d\n", info->Age);
}

Note that passing the struct by pointer to the function should be faster, note that you don't need the myInfo struct; you can just directly modify the elements of the array. Note the space before %s in the scanf() line, this is to discard any whitespace (including \n), this is done automatically for %d so it is only necessary for your strings (technically not the first iteration of the loop, but it doesn't fail if no whitespace is found). If you have any questions about why I made the changes I did, please feel free to comment on this answer!

RastaJedi
  • 641
  • 1
  • 6
  • 18
  • 1
    Definitely add some error checking and input validation. You wouldn't want someone to try to specify a negative number for `size` e.g.... – RastaJedi May 25 '16 at 03:40
1

example of fix

//struct Name_Age myInfo = *array_ptr;//Not necessary

printf("Enter size of array: ");
scanf("%d", &size);//remove `\n`, add `&`

//To ensure after the size has been determined
struct Name_Age * array_ptr = (struct Name_Age*)malloc(size * sizeof(struct Name_Age));//Cast is not necessary in C

for (i = 0; i < size; ++i)
{
    printf("Enter Name: \n");
    scanf("%s", array_ptr[i].Name);//remove `\n`
    printf("Enter Age: \n");
    scanf("%d", &array_ptr[i].Age);//need `&`
}

for (i = 0; i < size; ++i)
    printMe(array_ptr[i]);
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70