Data Structure about struct array - c

Recently, I took a subject called Data structure. I've created a program to try out my knowledge but don't know why the program did not work. I can't figure it out so I post it here to ask for solution. I hope people can help me. I am newbie here. So please ignore my opinion if my opinion is found annoying.
#include <stdio.h>
int main()
{
struct Book
{
char title[50];
int year;
float price;
};
int i;
struct Book books[50];
books[0].title="Bullshit";
books[0].year=132;
books[0].price=146.9;
books[1]=(struct Book){"Money",1344,189.4
};
for(i=0;i<2;i++)
{
printf("Book Title is : %s\n",books[i].title);
printf("Book Year is %d\n",books[i].year);
printf("Book price is %3.2f\n",books[i].price);
printf("\n\n");
}
}

1 I would make declaration of struct rather outside main than inside
2 Try changing char title[50] to char *title
#include <stdio.h>
struct Book {
char *title;
int year;
float price;
};
int main() {
int i;
struct Book books[50];
books[0].title = "Bullshit";
books[0].year = 132;
books[0].price = 146.9;
books[1] = (struct Book) {"Money", 1344, 189.4
};
for (i = 0; i < 2; i++) {
printf("Book Title is : %s\n", books[i].title);
printf("Book Year is %d\n", books[i].year);
printf("Book price is %3.2f\n", books[i].price);
printf("\n\n");
}
}
Why it didn't worked before?
In c arrays are not assignable by = operator.
You could do something like instead title[0] = 'B'; title[1] = 'u', etc....(or use strcpy which does it for you).
char *x is not really an array, it's just pointer to single char.
If we write x = "abc", we are telling the compiler: set x to 'a', next byte to 'b', next to 'c', and next to 0(not '0', just zero).
And when you do printf("%s",x), the printf function prints chars from the place in memory specified by x until it see 0 byte.
char *x = "abcd";
char *y = x;
while(*y != 0){ // this loop acts like printf("%s",x);
printf("%c",*y);
y++;
}
See also this and this question.
Or if you are using c++, not c, use std::string:
#include <cstdio>
#include <string>
struct Book {
std::string title;
int year;
float price;
Book(std::string t, int y, float p) {
title = t;
year = y;
price = p;
}
};
int main() {
int i;
Book books[50];
books[0].title = "Bullshit";
books[0].year = 132;
books[0].price = 146.9;
books[1] = Book(std::string("Money"), 1344, 189.4);
for (i = 0; i < 2; i++) {
printf("Book Title is : %s\n", books[i].title.c_str());
printf("Book Year is %d\n", books[i].year);
printf("Book price is %3.2f\n", books[i].price);
printf("\n\n");
}
}

this
books[0].title="Bullshit";
is not valid. title is defined as char[50]. Either do
strcpy(books[0].title, "BS");
This will copy the bytes of BS to title. Or do
struct Book
{
char *title;
int year;
float price;
};
...
books[0].title = strdup("BS");
This sets title up as a pointer to a char string. strdup will allocate space for the string and copy BS to that space. You will have to free that allocated space.
Or - the best. Use std::string
struct Book
{
std::string title;
int year;
float price;
};
....
books[0].title = "BS";
And as a final thought - life goes better with std::vector instead of raw arrays

Related

Why does my char array not print anything?

In c I am trying to assign a char array inside a struct with a user provided value, here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person
{
char name[20];
int age;
};
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(struct person));
x->name[20] = arr[20];
x->age = 21;
return x;
}
int main()
{
char name[20] = "Arthur morgan";
int age = 34;
struct person* person1 = assign(name, age);
printf("name: %s\n", person1->name);
printf("age: %d\n", person1->age);
return 0;
}
The problem is that the name prints nothing for some reason, the age however prints as expected.
Why is the name not printing correctly?
x->name[20] = arr[20];
It does not copy the array
It copies 1 character and you are accessing array outside its bounds which is undefined behaviour (UB)
It is better to use objects not types in sizeof
Always check the result of malloc
You need to copy the string using strcpy function
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(*x));
if(x)
{
strcpy(x->name,arr);
x->age = 21;
}
return x;
}
https://godbolt.org/z/vKddb4b9a

Why does printing from this struct give a segmentation fault?

I'm trying to create an array of Product structs and then print the name and code of each Product in the array, but I keep getting a segmentation fault. I have tried to insert each value without a loop and then printing, and it works, but I'd like to automate it. The function fill_products fills the products array according to the user's input, and the select_products prints each name-code pair for the entire array.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int code;
char *name;
float price;
} Product;
void select_products(Product *products, int len)
{
int i;
printf("%-30s%s\n", "Name", "Code");
for (i = 0; i < len; i++)
{
printf("%-30s%d\n", products[i].name, products[i].code);
}
return;
}
void fill_products(Product *products, int len)
{
int i, code;
char *name;
float price;
for (i = 0; i < len; i++)
{
printf("Insert product name (%d / %d): ", i + 1, len);
scanf("%s", &name);
printf("Insert product price (%d / %d): ", i + 1, len);
scanf("%f", &price);
products[i].code = i;
products[i].name = name;
products[i].price = price;
}
return;
}
int is_alloc(Product *products)
{
if (products == NULL)
{
printf("Error: memory allocation unsuccessful.\n");
}
return products != NULL;
}
int main(void)
{
int len, n_bytes;
Product *products;
printf("Insert length of array: ");
scanf("%d", &len);
n_bytes = sizeof *products * len;
products = malloc(n_bytes);
if(!is_alloc(products))
{
exit(0);
}
fill_products(products, len);
select_products(products, len);
free(products);
return 0;
}
I keep getting a segmentation fault.
Please enable compiler warnings, and pay attention to them.
This code:
char *name;
...
scanf("%s", &name);
is bogus and doesn't do at all what you intend.
You must either allocate space for name separately (and then not forget to free() it), or make that space available in the Product structure like so:
typedef struct
{
int code;
char name[100];
float price;
} Product;
(this assumes there is a reasonable limit on name length).

comparing two string using a pointer and strcmp

i'm trying to solve this problem but it's not working i think the statement inside 'if' is wrong and i don't know if i can put a pointer inside strcmp like this!!
#include <string.h>
#include <studio.h>
struct PersonCar {
char pname[20];
char cModel[20];
float price;
};
struct PersonCar pc[4];
float calculatePrice(struct PersonCar *p, char *name) {
p = malloc(sizeof(pc));
float s = 0;
for (int i = 0; i < 4; i++) {
if ((strcmp((p[i].pname), name)) == 0) //(p+i)->pname
s += (p + i)->price; //(p+i)->price; }
return s;
}
int main() {
// entering the element of the array from the user
char A[20];
printf("Enter a name : ");
fgets(A, sizeof(A), stdin);
printf("the total price of the registered cars for %s =%f\n", A,
calculatePrice(&pc, A));
}
First you need some data (I have included some statically initialized data in my version)
Second, you need to eliminate the malloc() statement at the beginning of the function, that modifies the passed pointer to the data and makes it to point to an uninitialized data, that is very unprobable that finds any register that matches.
You h ad better to know the size of the data array, and pass the number of entries on it.
You need to eliminate the last '\n' from the array read by fgets(). If you don't, it is comparing "smith" against "smith\n", which will never be equal. I suggest one way below, but you have to be careful and read the man page of strtok, as it modifies the source string, this can be not what you want (while in this case is preciselly what we want)
To illustrate, I have written this sample code (but a full program you can compile and execute) to see the logic.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct PersonCar {
char *pname;
char *cModel;
float price;
};
/* initialized data */
struct PersonCar pc[] = {
{ .pname = "smith",
.cModel = "foo",
.price = 10.50F,
}, {
.pname = "montgomery",
.cModel = "bar",
.price = 20.50F,
}, {
.pname = "mckormack",
.cModel = "blah",
.price = 35.50F,
}, {
.pname = "smith",
.cModel = "pong",
.price = 55.50F,
}, {
.pname = "phelps",
.cModel = "ping",
.price = 75.50F,
},
};
size_t pc_count = sizeof pc / sizeof pc[0];
float calculatePrice(
struct PersonCar *p,
size_t p_count,
char *name)
{
float total = 0.0;
for (int i = 0; i < p_count; i++) {
if (strcmp(p[i].pname, name) == 0)
total += p[i].price; /* found */
}
/* not found */
return total;
}
int main()
{
// entering the element of the array from the user
char A[80];
printf("Enter a name : ");
fgets(A, sizeof(A), stdin);
char *p = strtok(A, "\n"); /* chop the last \n if present */
printf("the total price of the registered cars for %s =%f\n",
p, calculatePrice(pc, pc_count, p));
}
I think you're looking for something like:
#include <string.h>
#include <stdio.h>
struct PersonCar {
char pname[20];
char cModel[20];
float price;
};
struct PersonCar pc[4] = {
{"abc", "", 1.0},
{"def", "", 2.0},
{"abc", "", 3.0},
{"jkl", "", 4.0},
};
float
calculatePrice(struct PersonCar *p, char *name)
{
float s = 0;
for( struct PersonCar *e = p + 4; p < e; p++ ){
if( strcmp((p->pname), name) == 0 ){
s += p->price;
}
}
return s;
}
int
main(void)
{
char A[20];
printf("Enter a name : ");
fgets(A, sizeof(A), stdin);
printf("the total price of the registered cars for %s =%f\n", A,
calculatePrice(pc, A));
}
One glaring issue here is that you're not dealing with the newline in the input, but since I don't know how you're actually initializing the data it's not clear how you want to deal with it.

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?
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.
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;
}
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 );

Creating an array of structures

I am trying to create an array of structures containing some basic information. My code is as follows:
typedef struct {
char firstName[30];
char lastName[30];
char street[35];
char city[20];
char state[3];
int zip;
char phone[15];
int accountId;
} Customer;
int main(void) {
int i, customer_number, _zip, _accountId;
struct Customer customer_list[9];
char _firstName[30], _lastName[30], _street[35], _city[20], _state[3], _phone[15];
for (i = 0; i < 10; i++) {
customer_number = 0;
printf("Enter data for customer %d: \n", customer_number);
printf("Enter First Last Phone: ");
scanf("%s%s%s", &_firstName, &_lastName, &_phone);
printf("\nEnter Address (Street City State ZIP): ");
scanf("%s%s%s%d", &_street, &_city, &_state, &_zip);
Customer customer_list[i] = {[i].firstName = _firstName}
}
return 0;
}
It seems like this should work, however I am getting an error saying " i must have constant value" Can anyone push me in the right direction? Thank you!
Customer customer_list[i] = {[i].firstName = _firstName}
This line needs to be
strcpy(customer_list[i].firstName, _firstName);
EDIT: assignment should be done by strcpy()

Resources