How to print out the members of a struct, weird errors? - c

I've been trying to print of the members of a struct I have created, however there are a few declarations errors that are showing saying my structs are undeclared. I have a separate function for printing the members of the struct. I have no idea on how to debug it... please help
I have errors such as game1- undeclared (first use in this function) and expected = , ; asm or attribute before { token
#include <stdio.h>
#include <stdlib.h>
struct video_game
{
char *name, *genre, *developer, *platformer, *app_purchase;
int release_year, age_limit;
float price;
};
void print_video_game_details(struct video_game* s)
{
printf("\nTitle: %s\n", s->name);
printf("Genre: %s\n", s->genre);
printf("Developer: %s\n", s->developer);
printf("Year of Release: %d\n", s->release_year);
printf("Lower Age Limit: %d\n", s->age_limit);
printf("Price: $%f\n", s->price);
printf("In-app Purchase: %s\n", s->app_purchase);
}
int main(int agrc, char* agrv[])
{
struct video_game game1
{
game1.name = "Candy Crush Saga";
game1.genre = "Match-Three Puzzle";
game1.developer = "King";
game1.release_year = 2012;
game1.platform = "Android, iOS, Windows Phone";
game1.age_limit = 7;
game1.price = 0.00;
game1.app_purchase = "Yes";
};
struct video_game game2
{
game2.name = "Halo 4";
game2.genre = "First Person Shooter";
game2.developer = "343 Industries";
game2.release_year = 2014;
game2.platform = "Xbox 360, Xbox One";
game2.age_limit = 16;
game2.price = 69.95;
game2.app_purchase = "No";
};
struct video_game game1
{
game3.name = "Uncharted 2: Among Thieves";
game3.genre = "Action adventure RPG";
game3.developer = "Naughty Dog";
game3.release_year = 2012;
game3.platform = "PS3";
game3.age_limit = 16;
game3.price = 30.00;
game3.app_purchase = "No";
};
print_video_game_details(&game1);
print_video_game_details(&game2);
print_video_game_details(&game3);
return 0;
}

Your instance creations (game1, game2 and game3) are not C, they are using some made-up syntax.
They should be something like
struct video_game game1 = {
.name = "Candy Crush Saga",
/* ... */
};
You need to define three variables of type struct video_game, and <type> <name> [= <initializer>] is (roughly) how variables are defined in C.
If you don't have C99, it must be:
struct video_game game1 = {
"Candy Crush Saga",
"Match-Three Puzzle",
"King",
"Android, iOS, Windows Phone",
"Yes",
2012,
7,
0.00
};
Things to notice, that you seem to be ignoring:
No names of fields inside the initializer, just values.
The order must be exactly the same as when the struct was declared; first five strings, then two integers, then a float.
Values are separated with commas, not semicolons.

Related

C mutating struct properties by reference

I'm learning pointers in C and i came across a confusion between pointers X struts X functions
The goal: creating two structs and mutate properties inside them.
The path I'm going: I am creating these two structs and then passing its memory addresses to the mutate function, the function then prints and mutates some properties of these structs.
Result I get:
1: The name of the struct created is nod being entirely printed and its of the wrong struct passed, and the life property is not properly changed and printed to the screen.
2: On the terminal I get "Segmentation Fault", not sure why but I'm pretty sure its something wrong I did.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
void attackHero(Hero *hero, int *power) {
(*hero).life = (*hero).life - *power;
printf("Damage: %d\n", *power);
printf("Attacked hero: %s\n", (*hero).name);
printf("Hero's remaining life: %d\n", (*hero).life);
};
int main () {
Hero flash;
flash.power = 250;
flash.life = 500;
strcpy(flash.name, "The Flash");
Hero batman;
batman.power = 380;
batman.life = 700;
strcpy(batman.name, "Batman arkham knight");
attackHero(&flash, &batman.power);
return 0;
}
Result printed to the terminal (Vscode + gcc):
Here is the warning that I get when I compile your original code:
1.c:25:2: warning: ‘__builtin_memcpy’ writing 10 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
25 | strcpy(flash.name, "The Flash");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.c:30:2: warning: ‘__builtin_memcpy’ writing 21 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
30 | strcpy(batman.name, "Batman arkham knight");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use the flexible array then you have to allocate space for it like this:
int main () {
Hero *flash = malloc(sizeof(*flash) + sizeof("The Flash"));
flash->power = 250;
flash->life = 500;
strcpy(flash->name, "The Flash");
Hero *batman = malloc(sizeof(*flash) + sizeof("Batman arkham knight"));
batman->power = 380;
batman->life = 700;
strcpy(batman->name, "Batman arkham knight");
attackHero(flash, &batman->power);
free(flash);
free(batman);
}
Here there the resulting code refactored a bit, and I added a error check for malloc:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
Hero *createHero(int power, int life, const char *name) {
Hero *h = malloc(sizeof(*h) + strlen(name) + 1);
if(!h) {
printf("malloc failed\n");
exit(1);
}
h->power = power;
h->life = life;
strcpy(h->name, name);
return h;
}
void attackHero(Hero *hero, int power) {
hero->life -= power;
printf(
"Damage: %d\n"
"Attacked hero: %s\n"
"Hero's remaining life: %d\n",
power,
hero->name,
hero->life
);
};
int main(void) {
Hero *flash = createHero(250, 500, "The Flash");
Hero *batman = createHero(380, 700, "Batman arkham knight");
attackHero(flash, batman->power);
free(flash);
free(batman);
}
Alternatively use a fixed array (char [64] as suggested by #Diego) or a char * and allocate space to it. The former only needs 2 lines of code change from the original:
// largest name in use
#define NAME_LEN sizeof("Batman arkham knight")
typedef struct {
int power;
int life;
char name[NAME_LEN];
} Hero;
Whole lotta malloc() going on. Since the hero’s names are string literals (and assuming they don’t change), just change name[]; to const char *name in the structure and initialize via simple assignment:
flash.name = "The Flash";
batman.name = "Batman arkham knight";
No worries about malloc() failures, name sizes or free() requirements.

Trying to get the DisplayStats function to iterate through each element of the people arrays

I am trying to get the function DisplayStats to iterate through each array of people and display the information but it keeps returning some errors I can't figure out. I have the array for each person and then I feed DisplayStats "people[i]" and have a for loop inside DisplayStats to iterate through each person but it keeps telling me i isn't declared in the function call and the formal parameter 1 is incomplete which I don't understand. Here is my code:
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
void DisplayStats(struct person Input[i])
{
int i;
for(i=0; i<7; i++)
printf("%s, %s: %lf PPG in %d\n", Input[i].last, Input[i].first, Input[i].ppg, Input[i].year);
}
struct person
{
char first[32];
char last[32];
int year;
double ppg;
};
int main(void)
{
int i;
struct person people[6];
people[0].year=2004;
people[0].ppg=5.2;
strcpy(people[0].first,"Jane");
strcpy(people[0].last,"Doe");
people[1].year = 2007;
people[1].ppg = 5.9;
strcpy(people[1].first,"Brian");
strcpy(people[1].last,"Smith");
people[2].year = 2020;
people[2].ppg = 15.3;
strcpy(people[2].first,"Kevin");
strcpy(people[2].last,"McAllister");
people[3].year = 2019;
people[3].ppg = 24.8;
strcpy(people[3].first,"Kobe");
strcpy(people[3].last,"Bryant");
people[4].year = 2845;
people[4].ppg = 93.1;
strcpy(people[4].first,"Offensive");
strcpy(people[4].last,"Bias");
people[5].year = 2371;
people[5].ppg = 7.9;
strcpy(people[5].first,"Ronald");
strcpy(people[5].last,"McDonald");
people[6].year = 1960;
people[6].ppg = 28.5;
strcpy(people[6].first,"Weyland");
strcpy(people[6].last,"Yutani");
DisplayStats(people[0]);
return (0);
}
Here are the errors:
main.c:14:39: error: ‘i’ undeclared here (not in a function)
void DisplayStats(struct person Input[i])
^
main.c:14:26: warning: ‘struct person’ declared inside parameter list will not be visible outside of this definition or declaration
void DisplayStats(struct person Input[i])
^~~~~~
main.c: In function ‘main’:
main.c:69:15: error: type of formal parameter 1 is incomplete
DisplayStats(people[0]);

 #user12982636, hello, this will give the desired result:
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
struct person
{
char first[32];
char last[32];
int year;
double ppg;
};
void DisplayStats(struct person *input)
{
struct person * i;
for(i=input; i-input<7; i++)
printf("%s, %s: %lf PPG in %d\n", i->last, i->first, i->ppg, i->year);
}
int main()
{
struct person people[6];
people[0].year=2004;
people[0].ppg=5.2;
strcpy(people[0].first,"Jane");
strcpy(people[0].last,"Doe");
people[1].year = 2007;
people[1].ppg = 5.9;
strcpy(people[1].first,"Brian");
strcpy(people[1].last,"Smith");
people[2].year = 2020;
people[2].ppg = 15.3;
strcpy(people[2].first,"Kevin");
strcpy(people[2].last,"McAllister");
people[3].year = 2019;
people[3].ppg = 24.8;
strcpy(people[3].first,"Kobe");
strcpy(people[3].last,"Bryant");
people[4].year = 2845;
people[4].ppg = 93.1;
strcpy(people[4].first,"Offensive");
strcpy(people[4].last,"Bias");
people[5].year = 2371;
people[5].ppg = 7.9;
strcpy(people[5].first,"Ronald");
strcpy(people[5].last,"McDonald");
people[6].year = 1960;
people[6].ppg = 28.5;
strcpy(people[6].first,"Weyland");
strcpy(people[6].last,"Yutani");
DisplayStats(people);
return (0);
}
The following proposed code:
cleanly compiles
performs the desired functionality
eliminates the 'messy' manipulation of the data by moving all the data to a simple table
greatly shrinks the amount of code
Properly defines the struct before any references to that struct
Uses appropriate horizontal and vertial spacing for readability
eliminates inclusion of unneeded header files
lets the compiler determine the number of instances of 'struct person' is needed
folds the printf statement to honor the right printer margin
And now, the proposed code:
#include <stdio.h>
struct person
{
char first[32];
char last[32];
int year;
double ppg;
};
struct person people[] =
{
{ "Jane", "Doe", 2004, 5.2 },
{ "Brian", "Smith", 2007, 5.9 },
{ "Kevin", "McAllister", 2020, 15.3 },
{ "Kobe", "Bryant", 2019, 24.8 },
{ "Offensive", "Bias", 2845, 93.1 },
{ "Ronald", "McDonald", 2371, 9.5 },
{ "Weyland", "Yutani", 1960, 28.5 }
};
void DisplayStats( struct person Input[] )
{
for( int i=0; i<7; i++)
{
printf( "%s, %s: %lf PPG in %d\n",
Input[i].last,
Input[i].first,
Input[i].ppg,
Input[i].year);
}
}
int main( void )
{
DisplayStats( people );
return (0);
}
The output of the proposed code:
Doe, Jane: 5.200000 PPG in 2004
Smith, Brian: 5.900000 PPG in 2007
McAllister, Kevin: 15.300000 PPG in 2020
Bryant, Kobe: 24.800000 PPG in 2019
Bias, Offensive: 93.100000 PPG in 2845
McDonald, Ronald: 9.500000 PPG in 2371
Yutani, Weyland: 28.500000 PPG in 1960
Suggest limiting the number of digits after the decimal point to 1 or 2 via using a 'output format conversion' specifier similar to %.2lf
Suggest formatting the output strings so they all take the same amount of horizontal space. Similar to %12.12s for better output formatting

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!

Pointer to array of pointers points to unexpected address

The question is related to my former question here:
Arduino compile error while using reference to a struct in another struct
I ported the sample code back to the pc and compiled it to get a clue, what's going wrong.
Here's the sample:
#include <stdio.h>
unsigned int steps=64;
unsigned int mode=0;
unsigned int speed=1;
typedef struct{
unsigned int option_value;
char option_name[17];
} SELECTION;
typedef struct{
char item_name[17];
unsigned int* variable;
SELECTION** options;
} MENU_ITEM;
SELECTION mode_forward = { 0, "Forward" };
SELECTION mode_backward = { 1, "Backward" };
SELECTION* options_mode[] = { &mode_forward, &mode_backward };
SELECTION speed_slow = { 0, "Slow" };
SELECTION speed_normal = { 1, "Normal" };
SELECTION speed_fast = { 2, "Fast" };
SELECTION* options_speed[] = { &speed_slow, &speed_normal, &speed_fast };
MENU_ITEM menu_steps = { "Steps", &steps, NULL };
MENU_ITEM menu_mode = { "Mode", &mode, options_mode };
MENU_ITEM menu_speed = { "Speed", &speed, options_speed };
MENU_ITEM menu_exit = { "Exit", NULL, NULL };
const unsigned char menu_items = 4;
MENU_ITEM* menu_list[menu_items] = { &menu_steps, &menu_mode, &menu_speed, &menu_exit };
//-----------------------------------------------------------
int main(){
int options;
options=(int)(sizeof(options_speed)/sizeof(options_speed[0]));
printf("Speed options: %i\n\n",options);
printf("Address of speed_slow: %p\n",&speed_slow);
printf("Address of speed_normal: %p\n",&speed_normal);
printf("Address of speed_fast: %p\n",&speed_fast);
printf("Address of array: %p\n\n",&options_speed);
MENU_ITEM item;
item=*menu_list[2];
printf("Menu Item: %s - Item Value: %i\n",item.item_name,*item.variable);
printf("Address of name: %p\n",&item.item_name);
printf("Address of variable-pointer: %p\n",&item.variable);
printf("Address of options-pointer: %p\n",&item.options);
printf("Value of options-pointer: %p\n",*item.options);
return 0;
}
When i start the program i get the following output:
Speed options: 3
Address of speed_slow: 0x6010c0
Address of speed_normal: 0x6010e0
Address of speed_fast: 0x601100
Address of array: 0x601120
Menu Item: Speed - Item Value: 1
Address of name: 0x7fff18a5dc90
Address of variable-pointer: 0x7fff18a5dca8
Address of options-pointer: 0x7fff18a5dcb0
Value of options-pointer: 0x6010c0
That's what i expect....except the last line. Shouldn't the address that it points to be 0x601120 - the address of options_speed array?
Why does it point to the first member of the array instead?
What do i have to change to let it point to 0x601120?
You are evaluating *item.options, not item.options. This seems is not what you wanted to print (i.e. the "options pointer") as there is an extra dereferencing operation.

C: initializing struct with an array of strings

I'm trying to do the following, but the compiler is complaining about brackets, however, I can't find my way to an alternative.
struct cards {
char faces[13][6], suits[4][9];
}
typedef struct cards cards;
void init_struct(cards *s) {
s->suits = {"hearts","spades","clubs","diamonds"};
s->faces = {"ace","two","three","four","five",
"six","seven","eight","nine"
"ten","jack","queen","king"};
}
I realize that there are several possible duplicate threads out there, but none of them has led me on the track. I hope one of you can :) Thanks
#include <string.h>
typedef struct cards {
char faces[13][6], suits[4][9];
} cards;
cards base_card = {
{"ace","two","three","four","five",
"six","seven","eight","nine", //forgot "," at nine after
"ten","jack","queen","king"},
{"hearts","spades","clubs","diamonds"}
};
void init_struct(cards *s) {
memcpy(s, &base_card,sizeof(cards));
}
The direct initialization syntax can only be used for initialization, not assignment. You cannot do this, for example:
char p[2][5];
p = {"a", "b"}; //error
That's why it fails to compile. Try strcpy-ing string by string
strcpy(s->suits[0], "hearts");
strcpy(s->suits[1], "spades");
...etc
or, alternatively, initialize a temporary array and then copy it
char suits_tmp[4][9] = {"hearts","spades","clubs","diamonds"};
memcpy(s->suits, suits_tmp, 4*9);
#include <string.h>
#include <stdio.h>
struct cards {
const char** suits;
const char** faces;
};
typedef struct cards cards;
const char* suits[4] = {"hearts","spades","clubs","diamonds"};
const char* faces[13] = {"ace","two","three","four","five",
"six","seven","eight","nine"
"ten","jack","queen","king"};
int main()
{
cards deck;
deck.suits = suits;
deck.faces = faces;
printf(deck.suits[0]);
return 0;
}
This works as well. Uses no pointers.
Clarification
I know mine is the quick and dirty answer, but there is no strcpy or memcpy or a long list of assignments. If your plan is to use the standard deck of cards for your game, then it would be a constant set of values anyway. If your intent is to have different types of decks, then my answer may not be adequate. Yes, it doesn't have a init_struct function, but you could easily modify it for your intent (since I am not well versed in C and malloc.)
Use const char * within your struct (I assume there is no requirement to modify the actual content of the suit/face value) and initialise them individually:
struct cards {
const char *suits[4];
const char *faces[13];
};
typedef struct cards cards;
void init_struct(cards *s)
{
s->suits[0] = "hearts";
s->suits[1] = "spades";
s->suits[2] = "clubs";
s->suits[3] = "diamonds";
s->faces[0] = "ace";
s->faces[1] = "two";
s->faces[2] = "three";
s->faces[3] = "four";
s->faces[4] = "five";
s->faces[5] = "six";
s->faces[6] = "seven";
s->faces[7] = "eight";
s->faces[8] = "nine";
s->faces[9] = "ten";
s->faces[10] = "jack";
s->faces[11] = "queen";
s->faces[12] = "king";
}
Of course, if you just want a one-off set of cards, which is reasonable, then this will work:
struct
{
const char *suits[4];
const char *faces[13];
} cards =
{
{"hearts","spades","clubs","diamonds"},
{"ace","two","three","four","five",
"six","seven","eight","nine",
"ten","jack","queen","king"}
};

Resources