aNaN
aNaN

Reputation: 337

Assign a string pointer in a struct

I'm learning about C and having trouble with this. It does compile but the result is unexpected. In my code, I have a struct:

typedef struct {
    char *title[50];
    float price;
} Book;

In the main, I am asking the user for number of books they want to have in the library. Then let them initialize the attributes of each book. Finally, print them out to the terminal using Display function.

void Display(Book* lib, int n);

int main() {
    int n;
    printf("Enter the number of books:\n" );
    scanf("%d", &n);
    if(n <= 0) {
        printf("Invalid number of book.");
        return 1;
    }

    Book *lib = (Book *) malloc(n * sizeof(Book));
    if(lib == NULL) {
        printf("The memory is full");
        return 1;
    }

    for(int i = 0; i < n; ++i) {
        char title[50];
        float price;
        printf("Book no.%d\n", i);
        printf("Book Title: ");
        scanf("%s", title);
        printf("Book Price: ");
        scanf("%f", &price);
        printf("\n");
        *(lib+i)->title = title;
        (lib+i)->price = price;
    }

    Display(lib, n);

    return 0;
}

The code compiles successfully, but the result is like this:

Enter the number of books:
2
Book no.0
Book Title: AAAA
Book Price: 1.0

Book no.1
Book Title: BBBB
Book Price: 9.9


----Displaying----
Book no.0
Book Title: BBBB
Book Price: $1.000000

Book no.1
Book Title: BBBB
Book Price: $9.900000

The title of the first book is wrong and it is the title of the second book. Why does this happen? And how should I fix it? Thank you

Edit: One of the requirements in my assignment is the title of Book must be of type char*

Edit 2: I realized my mistake when having 50 pointers of type char now. How should I fix it?

Upvotes: 0

Views: 1496

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 310920

Before you updated your post the declaration of the data member title of the structure

typedef struct {
    char *title[50];
    float price;
} Book;

is incorrect (in the context of the program it does not make sense). The structure should look like

typedef struct {
    char title[50];
    float price;
} Book;

That is each book has one title and not 50 pointers to titles.

And instead of this statement

*(lib+i)->title = title;

you have to write at least like

#include <string.h>

//...

strcpy( ( lib+i )->title, title );

As for your output then you assigned the address of the same local variable title to the first pointer of the array

    char *title[50];

of each element of the dynamically allocated array.

Pay attention to that you should free the dynamically allocated memory when it is not used any more. For example

free( lib );

Edit: One of the requirements in my assignment is the title of Book must be of type char*

After you updated your post then in this case the structure definition should look like

typedef struct {
    char *title;
    float price;
} Book;

And you will need to allocate dynamically memory for entered title of an object of the structure.

You could do it for example the following way. I suppose that you want to use pointers instead of the subscript operator.

( lib + i )->title = malloc( strlen( title ) + 1 );
strcpy( ( lib + i )->title, title );

In this case before freeing the allocated array pointed to by the pointer lib you will need to free also each allocated character array like for example

for ( int i = 0; i < n; i++ )
{
    free( ( lib + i )->title );
}

free( lib );

Upvotes: -1

Barmar
Barmar

Reputation: 780723

If you have to use a pointer, you'll need to use dynamic allocation.

The structure member should be declared as a pointer, not an array of pointers:

typedef struct {
    char *title;
    float price;
} Book;

Then the loop should allocate memory for a copy of the title, and copy the title into it.

    for(int i = 0; i < n; ++i) {
        char title[50];
        float price;
        printf("Book no.%d\n", i);
        printf("Book Title: ");
        scanf("%s", title);
        printf("Book Price: ");
        scanf("%f", &price);
        printf("\n");
        (lib+i)->title = malloc(strlen(title)+1); // +1 for the trailing null
        strcpy((lib+i)->title, title);
        (lib+i)->price = price;
    }

Upvotes: 2

dbush
dbush

Reputation: 223689

In your struct defintion:

typedef struct {
    char *title[50];
    float price;
} Book;

You don't have an array of char (which can hold a string) but an array of pointers to char each of which can point to a string.

Also, this doesn't do what you expect due to the definition of the price member:

*(lib+i)->title = title;

Change the definition to:

typedef struct {
    char title[50];
    float price;
} Book;

And read directly into the struct fields instead of temp variables to avoid copying:

    printf("Book Title: ");
    scanf("%s", lib[i].title);
    printf("Book Price: ");
    scanf("%f", &lib[i].price);

Alternately, you can define title as a char *:

typedef struct {
    char *title;
    float price;
} Book;

In which case you have to allocate space for the pointer to point to:

    lib[i].title = malloc(50);
    printf("Book Title: ");
    scanf("%s", lib[i].title);

Note that you can't have it point to a local like you did before because that local goes out of scope at the end of the loop, making the pointer invalid.

Upvotes: 4

Related Questions