Using malloc to create a pointer to multiple struct items - c

For a c programming class, I have been told to create the following structs with typedefs, in that order:
//STRUCTS
struct time {
unsigned int hour;
unsigned int minute;
unsigned int second;
};//end struct time
struct date {
unsigned int month;
unsigned int day;
unsigned int year;
};//end struct Date
struct event {
char name[20];
struct time* time;
struct date* date;
};//end struct event
//TYPEDEFS
typedef struct time Time;
typedef struct date Date;
typedef struct event Event;
From there I'm supposed to ask for the max number of events to create, then allocate a pointer with enough memory for that many Events. Part of my work is:
Event *events;
//Ask for max number of events and allocate memory
printf("Number of events to add: ");
scanf("%d", &numEvents);
events = (Event*) malloc(sizeof(Event) * numEvents);
However, from there I'm unsure of what to do to traverse the pointer to view a specific event. I know it isn't just an array, so events[i] won't work. but beyond that, I'm lost. My (broken)function for getting an event is:
void getEvent(Event *events, int index){
//variables
char title[20];
unsigned int day, month, year, hour, minute, second;
Event tempEvent;
//Ask for input
printf("Input title, date, and time.\n");
if(index == 0)
printf("example -> title: dd/mm/yy hh:mm:ss\n");
//Take input
scanf("%20[^:]: %u/%u/%u %u:%u:%u", title, &day, &month, &year, &hour, &minute, &second);
tempEvent = (Event) {*title, { hour, minute, second }, { month, day, year } };
events[index] = tempEvent;
}
I know that it isn't right, and I got a segmentation fault on testing.
When I compile, I get these warnings (and some repeats about similar things):
Lab4.c: In function ‘getEvent’: Lab4.c:82:2: warning: braces around scalar initializer
tempEvent = (Event) {*title, { hour, minute, second }, { month, day, year } };
^ Lab4.c:82:2: note: (near initialization for ‘(anonymous).name[1]’)
Lab4.c:82:39: warning: excess elements in scalar initializer
tempEvent = (Event) {*title, { hour, minute, second }, { month, day, year } }

The compiler is telling you that line 82 is a mess.
tempEvent = (Event) {*title, { hour, minute, second }, { month, day, year } };
In particular, the first member of the event structure is an array char name[20], but you attempt to initialize it with a single character *title. But the bigger problem is that time and date (in the event structure) are pointers, and you haven't allocated any memory for those pointers.
One solution is to allocate memory, and then have scanf fill in the values, like this:
void getEvent( Event *events, int n )
{
// allocate memory
events[n].time = malloc(sizeof(Time));
events[n].date = malloc(sizeof(Date));
if ( events[n].time == NULL || events[n].date == NULL )
{ /* TODO: handle the error */ }
//Ask for input
printf("Input title, date, and time.\n");
if ( n == 0 )
printf("example -> title: dd/mm/yy hh:mm:ss\n");
//Take input
int count = scanf( "%20[^:]:%u/%u/%u%u:%u:%u", events[n].name,
&events[n].date->day, &events[n].date->month, &events[n].date->year,
&events[n].time->hour, &events[n].time->minute, &events[n].time->second );
if ( count != 7 )
{ /* TODO: handle the error */ }
}

Related

adding a int from a struct pointer

I'm trying to increase the day of a date struct in C. I keep getting a return where the memory seems to be adding [not the actual int day in the struct].
For example, if I INPUT:
2018 10 2
I should get
OUTPUT:
10/03/2018
INSTEAD, I GET:
32594/10/-352487872
I believe I'm not using pointers correctly in the method: advanceDay(struct date d)
#include <stdio.h>
struct date {
int year;
int month;
int day;
};
/* function prototypes */
void printDate(struct date);
void readDate(struct date *);
struct date advanceDay(struct date);
int main(void) {
struct date today, tomorrow;
readDate(&today);
printDate(today);
tomorrow = advanceDay(today);
printDate(tomorrow);
return 0;
}
/* add your function definitions here */
void printDate(struct date d) {
printf("%02d/%02d/%04d\n", d.month, d.day, d.year);
}
void readDate(struct date *d){
scanf("%d %d %d", &(d->year), &(d->month), &(d->day));
}
struct date advanceDay(struct date d) {
d.day = d.day+1;
}
I've tried to change
d.day = d.day+1;
to
d.day = (*d.day)+1;
But I get an error. I've tried the -> and also moving around the *
Note that advanceDay doesn't explicitly return anything, resulting in undefined behavior (and probably reading uninitialized memory - the compiler should have warned you about it).
Instead, you could pass a struct date* to the function, and update it in place:
void advanceDay(struct date * d) {
d->day = d->day + 1;
}
Note that your main also needs to change accordingly:
int main(void) {
struct date today;
readDate(&today);
printDate(today);
advanceDay(&today); /* no retrun value here */
printDate(today); /* today was updated in-place */
return 0;
}
You declare advanceDay to return a value, but you don't return anything. You invoke undefined behavior by failing to return a value from this function and then subsequently attempting to use the return value.
Create a copy of the passed in struct date, perform the operation on the copy, and return it.
struct date advanceDay(struct date d) {
struct date nextDay;
nextDay.day = nextDay.day+1;
return nextDay;
}

Malloc and realloc for union of structs linked to array of structs

What's the best way to dinamically allocate memory to an array of structs with union included? I should malloc and then realloc to record_user or to data_user? Below I explain more of it, this is the sample code:
core.h
#define MAX_USER sizeof(record_user) / sizeof(record_user[0])
#define MAX_ARTIST sizeof(record_artist) / sizeof(record_artist[0])
/* all my other defines here */
typedef enum {
admin = 1,
basic = 0
} type;
typedef struct {
int hour;
int minute;
int second;
} tm;
typedef struct {
int day;
int month;
int year;
} date;
typedef struct {
short id;
char name[MAX_USER_NAME];
char surname[MAX_USER_SURNAME];
char email[MAX_USER_EMAIL];
char password[MAX_PASSWORD_LENGTH];
date birthday;
date subscription_date;
tm subscription_time;
type role;
} user;
typedef struct {
short id;
char name[MAX_ARTIST_NAME];
char genre[MAX_GENRE][MAX_GENRE_NAME];
char producer[MAX_PRODUCER_NAME];
char nationality[MAX_NATIONALITY_NAME];
int starting_year;
} artist;
/* and other structs */
typedef struct {
enum { USER, ARTIST } type;
union {
user *u_user;
artist *u_artist;
};
int size;
} data;
data.h
#ifndef DATA_H
#define DATA_H
#include "core.h"
extern user record_user[];
extern artist record_artist[];
extern data data_user;
extern data data_artist;
/* etc */
#endif
data.c
#include "data.h"
// SOME PRESET DATA
user record_user[] = {
{ 1, "Name 1", "Surname 1", "name1.surname1#email.com", ",+o[oS", { 29, 9, 1996 }, { 7, 3, 2011 }, { 18, 25, 58 }, 0 },
/** The list goes on **/
}
artist record_artist[] = {
{ 1, "Coldplay", { "Pop", "Britpop", "Alternative Rock" }, "Parlophone", "United Kingdom", 1997 },
/** The list goes on **/
}
data data_user = { .type = USER,.u_user = record_user,.size = MAX_USER };
data data_artist = { .type = ARTIST,.u_artist = record_artist,.size = MAX_ARTIST };
As you can see, there is a union struct for artist and user. I decided to create a union struct in order to pass multiple array of structs to a generic function. In the full code, I have more unions, but that's not the point to list them all. I just really need to understand what's I'm going to further explain below.
record_user like record_artist has some preset data that I link to data_user and data_artist respectively in data.c. Now this data needs to be increased during the runtime. I mean if record_user has 100 preset data rows (same thing for record_artist) in it, I'd like to add more rows or even remove them. For that I know there's malloc and realloc. I tried to play with it, making some tests and I don't know what's the best way of doing that.
I tried to declare in my main.c file the following:
int main() {
data_user.u_user = (user *)malloc(size * sizeof(user));
/***/
}
but I also tried with this
int main() {
record_user = (user *)malloc(size * sizeof(user));
/***/
}
but as I already imagined I lose all the preset data delcared in data.c file.
MY GOAL
What I'd like to achieve is to malloc a temp size for my data (for starting 100) and then to link the array of structs (or the union struct), with the starting temp size, to my preset data in order for using them. Naturally, during runtime, I will add more rows, and for that I'll use realloc (or even remove them).
This is the sample code of my add function:
data *add_data(data *record_data) {
date record_date;
tm record_time;
switch (record_data->type) {
case USER:
{
/* SOMEWHERE HERE I should use realloc to my record_data */
int ID = record_data->size;
record_data->u_user[ID].id = ID;
printf("\n\n\tNEW USER");
printf("\n\tEnter name: ");
strcpy(record_data->u_user[ID].name, inputString(MIN_USER_NAME, MAX_USER_NAME));
printf("\tEnter surname: ");
strcpy(record_data->u_user[ID].surname, inputString(MIN_USER_SURNAME, MAX_USER_SURNAME));
printf("\tEnter email: ");
strcpy(record_data->u_user[ID].email, inputString(MIN_USER_EMAIL, MAX_USER_EMAIL));
printf("\tEnter password: ");
strcpy(record_data->u_user[ID].password, inputString(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH));
/* etc for birthday, subscription date */
record_data->size += 1;
printf("\n\tUser added!");
return record_data;
}
case ARTIST:
/* asking for input data */
return record_data;
}
}
this is how I call the function instead in the main.c file
int main() {
/***/
data_user = *add_data(&data_user);
/***/
}
I don't know how to move here, if I should work with the struct record_user or the union struct data_user. If it's the same or not... if I work with the original struct (allocating memory), is the union capable of reading the new memory size or not? Or is it best to work with the union struct leaving the original struct untouched?
I hope someone clear my mind!

Return pointer to a structure

I have this program, where you enter two dates into two structures (same type), and then I want a function to find which date I entered is the later date. It compares only year and month. Once the later date is found, I want the function to return a pointer to the structure with the later date. I then want to print out the later date.
This is what I have so far, but I get errors and I'm not sure about the pointer syntax.
Code:
#include <stdio.h>
struct date{
int year;
int month;
int day;
};
main()
{
struct date dates[2];
int i = 0, res = 0;
for ( i = 0 ; i < 2 ; i++){
printf("Enter a year!");
scanf("%d", &dates[i].year);
printf("Enter a month!");
scanf("%d", &dates[i].month);
printf("Enter a day!");
scanf("%d", &dates[i].day);
}
res = later(&dates[1], &dates[2]);
}
struct date *later(struct date *one, struct date *two)
{
if (one->year > two->year){
return *one;
}
else if (one->year == two->year){
if(one->month > two->month){
return *one;
}
else
return *two;
}
else {
return *two;
}
}
Error messages:
q4.c:28:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d", &res);
^
q4.c: At top level:
q4.c:32:14: error: conflicting types for ‘later’
struct date *later(struct date *one, struct date *two){
^
q4.c:26:9: note: previous implicit declaration of ‘later’ was here
res = later(&dates[1], &dates[2]);
^
q4.c:55:1: error: expected identifier or ‘(’ before ‘}’ token
}
There are multiple problem with your program:
There is no prototype for your function later() Solution: Add date *later(date *one, date *two); after ending declaration of struct date or move the whole function above main().
Change return type of you function to date* as you are returning a pointer to date object.
Change data type of res to date* as you want to store a pointer to date object.
Then print the object res is pointing to by printing each of its components individually as printf is not designed to print your custom data type.
This is only a suggestion but i recommend you moving declaration of int i to for(int i = 0; i < 2; i++); it is just considered better and saves memory.
If you want res to be an int you will have to return a object instead of a pointer and then typecast it to int. Guide on typecasting: http://www.cplusplus.com/doc/tutorial/typecasting/
There are a number of ways to handle the return as have been pointed out in the comments. You can either declare your later function as int (as you have), and use the return similar to the return from strcmp (0 - dates are equal, -1 first is earlier than last, 1 first is later than last).
You can also declare later as struct date * and return a pointer to the later date (which leaves you in a pickle as to what to return if the dates are equivalent).
Your return is more meaningful, if you return a int value similar to strcmp. An implementation that compares your struct date and returns -1, 0 or 1 based on the first being earlier, equivalent, or later could be:
int later (struct date *one, struct date *two)
{ /* the ternary operator is your friend */
if (one->year != two->year) /* years differ */
return one->year > two->year ? 1 : -1;
if (one->month != two->month) /* months differ */
return one->month > two->month ? 1 : -1;
if (one->day != two->day) /* days differ */
return one->day > two->day ? 1 : -1;
return 0; /* dates are equivalent */
}
(note: the use of the ternary operator (e.g. test ? if true : if false) to simply comparing each date component)
Also, note, in this case your are free to pass struct date instead of struct date * as the function will work fine operating on a copy of each date struct. It is up to you how you want to do it.
A small sample program testing the function (and noting a few code improvements) could be:
#include <stdio.h>
struct date {
int year;
int month;
int day;
};
int later (struct date *one, struct date *two);
void prn_result (struct date a, struct date b, char op);
/* main is a function of type 'int' and returns a value */
int main (void) {
struct date dates[2] = {{0}}; /* initialize variables */
int i = 0, res = 0;
for (i = 0; i < 2; i++) { /* user input of dates */
printf ("Enter a year: ");
scanf ("%d", &dates[i].year);
printf ("Enter a month :");
scanf ("%d", &dates[i].month);
printf ("Enter a day: ");
scanf ("%d", &dates[i].day);
putchar ('\n');
}
res = later (&dates[0], &dates[1]); /* comparison */
if (res == 0)
prn_result (dates[0], dates[1], '=');
else if (res > 0)
prn_result (dates[0], dates[1], '>');
else
prn_result (dates[0], dates[1], '<');
return 0;
}
int later (struct date *one, struct date *two)
{ /* the ternary operator is your friend */
if (one->year != two->year) /* years differ */
return one->year > two->year ? 1 : -1;
if (one->month != two->month) /* months differ */
return one->month > two->month ? 1 : -1;
if (one->day != two->day) /* days differ */
return one->day > two->day ? 1 : -1;
return 0; /* dates are equivalent */
}
void prn_result (struct date a, struct date b, char op)
{
printf ("%d/%d/%d %c %d/%d/%d\n",
a.month, a.day, a.year, op,
b.month, b.day, b.year);
}
Example Use/Output
$ ./bin/cmpyear
Enter a year: 1993
Enter a month :3
Enter a day: 13
Enter a year: 1993
Enter a month :3
Enter a day: 12
3/13/1993 > 3/12/1993
$ ./bin/cmpyear
Enter a year: 1993
Enter a month :3
Enter a day: 12
Enter a year: 1993
Enter a month :3
Enter a day: 12
3/12/1993 = 3/12/1993
$ ./bin/cmpyear
Enter a year: 1993
Enter a month :3
Enter a day: 12
Enter a year: 1993
Enter a month :3
Enter a day: 13
3/12/1993 < 3/13/1993
Look it over and let me know if you have an further questions.

Convert struct array to struct?

I have a struct array (Training data[10]) that contains some data that I want to pass to functions.
int convertTime(Time time)
{
minutes = time.seconds * 60;
// Takes data from data[0].time.seconds and converts them to minutes.
// My only problem is that I am being asked send a struct to this function, but I have to send the array because that's where all my data is stored
return minutes;
}
typedef struct
{
int seconds;
} Time;
typedef struct
{
Time time;
double distance;
} Training;
Training data[10];
Training input;
scanf("%d %lf", input.time.seconds, input.distance);
data[0].time.seconds = input.time.seconds;
data[0].distance = input.distance;
So now data[0].time.seconds and data[0].distance contains all data I need. I just have to pass data[0].time.seconds to the function, but in my assignment I am prompted to send the struct Time to the function, and I don't understand that since Time is only storing temporary data? It's the stored data that I want to send to the function.
How do I convert seconds to hours, minutes and seconds?
time.hours = seconds / 3600;
time.minutes = (seconds - time.hours * 3600) / 60;
time.seconds = seconds - 3600 * time.hours - 60 * time.minutes;
This seems to be right in my eyes but it fails. hours is correctly calculated but not minutes and sconds :(
To pass the structure, name it in the call:
some_function(data[0].time); // By value
other_function(&data[0].time); // By address
Both functions get passed the Time value contained in the data[0] element of your array of Training structures.
Suppose you have a value which is the number of seconds since midnight. And suppose you define another structure with hours/minutes/seconds, you can set this clock structure as follows,
typedef struct
{
int hours;
int minutes;
int seconds;
} Clock;
You can print this structure, either to a char buffer, or to stdout,
char*
clockPrint(Clock* timep,char *stringbuf)
{
if(stringbuf)
sprintf(stringbuf,"%02d:%02d:%02d",(timep)->seconds,(timep)->minutes,(timep)->seconds);
else
printf("%02d:%02d:%02d",(timep)->seconds,(timep)->minutes,(timep)->seconds);
return stringbuf;
}
Extracting hours, minutes, and seconds from an epoch time or a number of seconds since midnight can be done,
int //return days...
TimeSet(Clock* timep, int epoch)
{
(timep)->seconds = (epoch) % 60;
(timep)->minutes = (epoch/60) % 60;
(timep)->hours = (epoch/60/60) % 24;
int days;
return days = (epoch/60/60/24);
}
Should you want to obtain hours, minutes, or seconds from this clock value,
void
TimeGet(Clock* timep, int* hoursp, int* minutesp, int* secondsp)
{
if(hoursp) *hoursp = (timep)->hours;
if(minutesp) *minutesp = (timep)->minutes;
if(secondsp) *secondsp = (timep)->seconds;
return;
}
Since you have stored a Time in your Date struct, which contains a number of seconds (presumably since midnight), and you have an array of some number of these Date's defined,
Training data[10];
Training input;
You can use scanf to read your seconds and distance values. And as stated, you can then place your input into your data[0] element,
//scanf wants pointers to int and float data
float distance;
printf("enter: seconds distance "); fflush(stdout);
scanf("%d %lf", &(input.time.seconds), &distance);
//you can then store the distance into your input struct double
input.distance = distance;
data[0].time.seconds = input.time.seconds;
data[0].distance = input.distance;
You could also use gettimeofday(3) or clock_gettime(2) to grab the current time (seconds since epoch),
struct timeval tv;
gettimeofday(&tv,NULL); //posix.1-2001 function, seconds
input.time.seconds = tv.tv_sec;
//or
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts); //posix.1-2008 function, seconds
input.time.seconds = ts.tv_sec;
Then you can separate your seconds into hours, minutes, and seconds,
Clock clk;
int hours, minutes, seconds;
TimeSet(&clk, data[0].time.seconds);
TimeGet(&clk, &hours, &minutes, &seconds);
Or you can format a string for printing, or print to stdout,
char clockbuffer[30];
clockPrint(&clk,NULL);
printf("time (HH:MM:SS): %s\n", clockPrint(&clk,clockbuffer));

scanf doesn't store proper information in structure

I have a problem with scanf. scanf doesn't store proper information in structure. Part of code is:
if( figure->pro.p_category == 'C' || figure->pro.p_category == 'c' ){
printf("Enter data line> ");
result += scanf("%s %d%c %d %d %d%c", (figure->pro.name), &temp,\
&figure->pro.money, &figure->exp.month, &figure->exp.year,\
&figure->ais.aisle_num, &figure->ais.aisle_side);
if ( figure->pro.money == 'C')
figure->pro.cents = temp;
else if( figure->pro.money == 'D')
figure->pro.dollars = temp;
}
figure->pro.name and figure->exp.month store different values.
My structures are:
typedef struct {
char name[20];
char p_category,
sub_p_category,
money;
int cents,
dollars;
}product_t;
typedef struct {
int aisle_num;
char aisle_side;
}aisle_t;
typedef struct {
int day,
month,
year;
}experiment_t;
typedef struct {
int day,
month,
year;
}packaging_t;
typedef union {
product_t pro;
experiment_t exp;
packaging_t pack;
aisle_t ais;
}figure_t;
For instance;
input> corn 89C 11 2010 11B
This piece of code from output function:
printf("The %s costs %d cents, expires in ",my_figure.pro.name, my_figure.pro.cents);
print_exp_month(my_figure);
printf("of %d, and is displayed in %d%c", my_figure.exp.year, my_figure.ais.aisle_num,\
my_figure.ais.aisle_side);
its output:
The
costs 89 Dollar, expires in of 2000, and is displayed in 12B
The proper output:
The corn costs 89 cents, expires in November of 2000, and is displayed in 12B
If you store your data in a union
typedef union {
product_t pro;
experiment_t exp;
packaging_t pack;
aisle_t ais;
} figure_t;
only one set of data is stored at each time. When you read into, for example, figure->pro.money and figure->exp.month the data will be stored in the same place and overwrite each other.
So when you try to print it, it is not there anymore!

Resources