malloc array of struct inside of struct - c

I have project in school where in need to make a struct of AirportManager which holds the amount of airports and an array of Airport (another struct). I started writing the code but I having trouble with the malloc of the array of airports.
I attahced to code I write so far, the problem I have is that the values dont saved in the airportArray in the AirportManager.
//AirportManger Struct
typedef struct {
Airport* airportArray;
int airportAmount;
}AirportManager;
void initAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
airportManager->airportArray = (AirportManager*)malloc(0);
}
void addAirport(AirportManager* airportManager)
{
Airport airport;
printf("Enter Airport Name: ");
scanf("%s", airport.airportName);
printf("Enter Airport Address: ");
scanf("%s", airport.airportAddress);
airportManager->airportAmount++;
airportManager->airportArray = (Airport*)realloc(airportManager->airportArray, airportManager->airportAmount * sizeof(Airport));
airportManager->airportArray = airport;
}
//Airport Struct
typedef struct {
char airportName[MAX];
char airportAddress[MAX];
}Airport;
//Main
AirportManager airportManager;
initAirportManager(airportManager);
addAirport(&airportManager);

The code has some issues. We shouln't:
allocate zero bytes with malloc(0)
assign twice to airportManager->airportArray
use scanf
Here is the code modified. It uses malloc and realloc better, and fgets instead of scanf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZ 512
typedef struct {
char airportName[SIZ];
char airportAddress[SIZ];
} Airport;
typedef struct {
Airport* airportArray;
int airportAmount;
} AirportManager;
// Call first on AirportManager
void initAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
airportManager->airportArray = NULL;
}
// Call last on AirportManager
void finalAirportManager(AirportManager* airportManager)
{
airportManager->airportAmount = 0;
if (airportManager->airportArray != NULL)
free(airportManager->airportArray);
airportManager->airportArray == NULL;
}
// Add an airport to the manager
void addAirportByNameAndAddress(AirportManager* airportManager, char *name, char *address)
{
// Calculate the amount of memory needed
size_t mem = (airportManager->airportAmount + 1) * sizeof(Airport);
// Get the memory required
Airport* newAirports = NULL;
if (airportManager->airportArray == NULL)
newAirports = (Airport*)malloc(mem);
else
newAirports = (Airport*)realloc(airportManager->airportArray, mem);
if (newAirports == NULL)
{
// error: out of memory
return;
}
// Copy the name and the address to new the new Airport
Airport *current = newAirports + airportManager->airportAmount;
memset(current->airportName, '\0', SIZ);
strncpy(current->airportName, name, SIZ - 1);
memset(current->airportAddress, '\0', SIZ);
strncpy(current->airportAddress, address, SIZ - 1);
// Update the manager
airportManager->airportAmount++;
airportManager->airportArray = newAirports;
}
void addAirport(AirportManager* airportManager)
{
char name[SIZ] = { 0 };
char address[SIZ] = { 0 };
printf("Enter Airport Name: ");
fgets(name, SIZ - 1, stdin);
printf("Enter Airport Address: ");
fgets(address, SIZ - 1, stdin);
addAirportByNameAndAddress(airportManager, name, address);
}
void main() {
AirportManager airportManager;
initAirportManager(&airportManager);
addAirport(&airportManager);
finalAirportManager(&airportManager);
}

Related

Function to add struct to another struct in C

so I have 3 structs here:
typedef struct {
char *name; // allocated
int commonality;
int weight;
} monster;
typedef struct {
char *name; // allocated
char *description; // allocated
double area;
int monsters;
monster **monsters; // allocated
} region;
typedef struct {
char *name; // allocated
double diameter;
int regions;
region **regions; // allocated
} planet;
I already have function:
monster *new_monster(char *name, int commonality, int weight);
I am trying to create these functions:
void add_monster_to_region(region *r, char *mname, int mcommonality, int weight);
void delete_region_from_planet(planet *p, char *rname);
This is what I have so far, but I don't believe it's right, can anyone tell me what I'm doing wrong and how I can fix it?
void add_monster_to_region(region *r, char *mname, int mcommonality, int mweight)
{
for (int i = 0; i < mcommonality; i++)
{
if (strcmp(mname, r->monsters[i]->name) == 0)
{
r->monsters[i]->name = mname;
}
}
}
Thank you
It would be very helpful to have a minimal reproducible example. It would also clarify what was meant with fully allocated NOT a reference array.
Nevertheless, here is my take on how to create a planet, two regions and how to populate the regions with monsters:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char *name; // allocated
int commonality;
int weight;
} monster;
typedef struct {
char *name; // allocated
char *description; // allocated
double area;
int monster_count;
monster **monsters; // fully allocated, NOT a reference array
} region;
typedef struct {
char *name; // allocated
double diameter;
int region_count;
region **regions; // fully allocated, NOT a reference array
} planet;
monster *new_monster(char *name, int commonality, int weight) {
monster *new_monster = calloc(sizeof(monster), 0);
if (new_monster != NULL) {
new_monster->name = strdup(name);
if (new_monster->name == NULL) {
free(new_monster);
return NULL;
}
new_monster->commonality = commonality;
new_monster->weight = weight;
}
return new_monster;
}
void free_monster(monster *the_monster) {
if (the_monster != NULL) {
if (the_monster->name != NULL) {
free(the_monster->name);
}
free(the_monster);
}
}
void add_monster_to_region(region *r, char *mname, int mcommonality, int mweight)
{
monster *a_monster = new_monster(mname, mcommonality, mweight);
if (a_monster == NULL) return; // no memory
monster **monsters = NULL;
if (r->monsters != NULL) {
monsters = realloc(r->monsters, (r->monster_count + 1) * sizeof(monster *));
} else {
monsters = calloc(sizeof(monster *), 0);
}
if (monsters == NULL) {
free_monster(a_monster);
return; // no memory
}
r->monsters = monsters;
r->monsters[r->monster_count] = a_monster;
r->monster_count++;
}
void delete_region_from_planet(planet *p, char *rname) {
// TODO
}
int main() {
region desert = {"Desert", "Sunny and warm place.", 50.0, 0, NULL};
region ocean = {"Ocean", "Huge wet place.", 500.0, 0, NULL};
region *regions[] = {&desert, &ocean};
planet mud = {"Mud", 100.00, 2, regions};
add_monster_to_region(&desert, "Bug", 100, 100);
add_monster_to_region(&desert, "Zombie", 10, 20);
add_monster_to_region(&ocean, "Shark", 20, 40);
for (int i = 0; i < mud.region_count; i++) {
for (int j = 0; j < mud.regions[i]->monster_count; j++) {
printf("%s %d %d\n",
mud.regions[i]->monsters[j]->name,
mud.regions[i]->monsters[j]->commonality,
mud.regions[i]->monsters[j]->weight
);
}
}
// TODO: release allocated memory
return 0;
}
We can see all monsters in all regions of the defined planet:
$ gcc -Wall monsters.c
$ ./a.out
Bug 100 100
Zombie 10 20
Shark 20 40
$

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).

Searching for a string in an array without strcmp

I have a struct in this form:
typedef struct student{
double student_no;
char name[50];
char surname[50];
double phone_no;
char mail[50];
};
struct student person[100];
printf("Student's mail address: ");
scanf("%s", person[i].mail); //i use codeblocks and it works without the sign &
First I create an array of mails. Then I get a mail for user, then check if it is in my array that I created in the first place. I have to do it without strcmp(), and that's where I get stuck. Here is what I've tried so far:
char *e1, *e2;
int comp;
typedef struct info{
char email[50];
};
struct info mailaddress[0];
printf("Enter the mail address to search: ");
scanf("%s", mailaddress[0]);
for (int i = 0; i < u; i++) {
for (int j = i + 1; j < u; j++) {
e1 = person[i].mail;
e2 = mailaddress[j].email;
comp = 0;
while (*e1 && *e2) {
if (*e1 != *e2) {
comp = *e1 - *e2;
break;
}
++e1;
++e2;
}
if (comp == 0)
printf("%s\t %s %15.lf %15.lf %s\n",
person[i].name,
person[i].surname,
person[i].student_no,
person[i].phone_no,
person[i].mail);
}
}
Try like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
#include <string.h>
#define NO_MAX 20
#define NAME_MAX 20
#define SURNAME_MAX 20
#define PHONE_NO_MAX 20
#define MAIL_NO_MAX 50
struct student{
char student_no[NO_MAX + 1];
char name[NAME_MAX + 1];
char surname[SURNAME_MAX + 1];
char phone_no[PHONE_NO_MAX + 1];
char mail[MAIL_NO_MAX + 1];
struct student *ptr_next;
};
struct student *ptr_head = NULL;
struct student *ptr_position;
void enter_item(char *ptr_label, char *ptr_result, int max){
// enter item until pressed enter to finished
char tmp[256];
do {
printf("%s: ", ptr_label);
gets(tmp);
} while((strlen(tmp) > max));
strcpy(ptr_result, tmp);
}
void enter_list(void) {
char more;
struct student *ptr_new;
do{
// order dynamic memory
ptr_new = (struct student *) malloc(sizeof(struct student));
if(ptr_new) {
// enter item
enter_item("student_no", ptr_new->student_no, NO_MAX);
enter_item("name", ptr_new->name, NAME_MAX);
enter_item("surename", ptr_new->surname, SURNAME_MAX);
enter_item("phone_no", ptr_new->phone_no, PHONE_NO_MAX);
enter_item("mail", ptr_new->mail, MAIL_NO_MAX);
// next item
ptr_new-> ptr_next = ptr_head;
ptr_head = ptr_new;
// enter item again or not
printf("- again(Y/N)? -");
do{
more = toupper(getch());
} while(!(more=='Y' || more=='N'));
printf(" %c\n\n", more);
}
else {
printf("Memory isn't enough!\n");
break;
}
} while(more == 'Y');
}
void search_mail() {
// enter mail
struct student *ptr_search;
ptr_search = (struct student *) malloc(sizeof(struct student));
enter_item("mail searching", ptr_search->mail, MAIL_NO_MAX);
char *mail = ptr_search->mail;
// searching mail
ptr_position = ptr_head;
while(ptr_position) {
if(strcmp(mail, ptr_position->mail) != 0) {
ptr_position = ptr_position-> ptr_next;
}
else {
printf("Email is found\n");
return;
}
}
printf("Email isn't found!\n");
}
int main()
{
enter_list();
search_mail();
return 0;
}
Result:
bool streq(char *a, char *b)
{
while (*a && *b && *a != *b)
a++, b++;
return !*a && !*b;
}

Problems with editing and showing customer data - c

I'm doing a customer and product management project in C. And right now I'm having some problems:
in the part of showing the customer's data, he doesn't show the whole name, only the first letter; the phone number puts a number that I didn't enter; in nif does not say what corresponds; as well as the email that put characters that I did not indicate.
Already in the edit part, it edits but not correctly, because it changes data that I didn't ask for and others I don't sample.
Stays like this:
-- customer creation:
enter image description here
-- show customer data:
enter image description here
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUFFER 64
/* List structure declared to store our data. */
typedef struct list {
int *customer_code;
char name;
int age;
int tin;
char email;
double phone;
char country;
struct list *next;
} Data;
/* Prototype of data handling functions. */
int *data_start(int *customer_code, char name, int age, int tin, char email, double phone, char country);
int *insert_data(Data *data, int *customer_code, char name, int age, int tin, char email, double phone, char country);
int *edita_dados(Dados *dados, int item, int *customer_code, char name, int age, int tin, char email, double phone, char country);
void display_data(Data *data);
void data_search(Data *data, char *key);
int *delete_data(Data *data);
int check_empty(Data *data);
/* Prototype of menu functions.*/
void insert(void);
void edit(void);
void displays(void);
void search(void);
void delete(void);
/* Initializes the main data structure. */
int *main = NULL;
/* Cria a nova lista apontando o proximo no para NULL. */
int *data_start(int *cliente_codigo, char name, int age, int tin, char email, double phone, char country) {
Data *new;
new = (Data *) malloc(sizeof (Data));
new->customer_code = (int *) malloc(strlen(customer_code) + 1);
strncpy(new->customer_code, customer_code, strlen(customer_code) + 1);
new->name = name;
new->age = age;
new->tin = tin;
new->email = email;
new->phone = phone;
new->country = country
new->next = NULL;
return new;
}
/* As the list is no longer empty, we point the next node to the previous list. */
int *insert_data(Data *data, int *customer_code, char name, int age, int tin, char email, double phone, char country) {
Data *new;
new = (Data *) malloc(sizeof (Data));
new->customer_code = (int *) malloc(strlen(customer_code) + 1);
strncpy(new->customer_code, customer_code, strlen(customer_code) + 1);
new->name = name;
new->age = age;
new->tin = tin;
new->email = email;
new->phone = phone;
new->country = country
new->next = Data;
return new;
}
/* Cycles through all fields in the list and prints until the next pointer reaches NULL. */
int *edita_dados(Data *data, int item, int *customer_code, char name, int age, int tin, char email, double phone, char country) {
int i = 0;
/*while(data != NULL && i <= item) {
data = data->next;
}*/
while (data->next != NULL && i < item) {
data = data->next;
++i;
}
if (data != NULL && i == item) {
strcpy(data->customer_code, customer_code);
new->name = name;
data->age = age;
data->tin = tin;
data->email = email;
data->phone = phone;
data->country = country
}
printf("Successfully edited.\n");
}
/* Cycles through all fields in the list and prints until the next pointer reaches NULL. */
void display_data(Data *data) {
printf("Registration Report\n\n");
printf("------------------------\n");
for (; data != NULL; data = data->next) {
printf("Name: %c\n", data->name);
printf("Age: %d\n", data->age);
printf("TIN: %d\n", data->tin);
printf("Email: %c\n", data->email);
printf("Phone: %lf\n", data->phone);
printf("Country: %c\n", data->country);
printf("------------------------\n");
}
}
/* Cycle through each end comparing the name to the key. */
void data_search(Data *data, char *key) {
int find = 0;
printf("registration data\n\n");
for (; data != NULL; data = data->next) {
if (strcmp(key, data->customer_code) == 0) {
printf("------------------------\n");
printf("Name: %c\n", data->name);
printf("Age: %d\n", data->age);
printf("TIN: %d\n", data->tin);
printf("Email: %c\n", data->email);
printf("Phone: %lf\n", data->phone);
printf("Country: %c\n", data->country);
printf("------------------------\n");
find++;
}
}
if (find == 0)
printf("No results found.\n\nPress a key to continue.\n\n");
else
printf("%d records were found.\n\nPress a key to continue.\n\n", find);
}
/* Deletes the last record entered. */
int *delete_data(Data *data) {
Data *new;
new = data->next;
free(data->customer_code);
free(data);
printf("The last record entered was deleted successfully!\n");
return new;
}
/* it's worth checking whether the list is NULL or not. */
int check_empty(Data *data) {
if (data == NULL) {
printf("List empty!\n");
return 1;
} else
return 0;
}
/* Gets the necessary data to call the data handling functions. */
void insert(void) {
int intend_tin;
Data d;
d.customer_code = (char *) malloc(BUFFER);
printf("Client Code: ");
scanf("%d", d.customer_code);
printf("Type your name: ");
scanf("%s", &d.name);
printf("\nEnter your age:");
scanf("%d", &d.age);
printf("\nEnter your email:");
scanf("%s", &d.email);
printf("\nEnter your mobile number: ");
scanf("%lf", &d.phone);
printf("TIN present? ");
scanf("%s", &intend_tin);
if (intend_tin == 's' || intend_tin == 'S') {
while (1) {
printf("\n\tEnter your TIN: ");
scanf("%d", &d.tin);
if (&d.tin >= 999999999) {
printf("\tNumber with more than 9 digits is not allowed. "
"Please try again.");
} else if (&d.tin <= 99999999) {
printf("\tNumber with less than 9 digits is not allowed. "
"Please try again.");
} else
break;
}
printf("\tValid.\n");
} else {
printf("TIN not entered\n");
}
printf("What is your country? ");
scanf("%s", &d.country);
if (main == NULL)
main = data_start(d.customer_code, d.name, d.age, d.email, d.phone, d.tin, d.country);
else
main = insert_data(main, d.customer_code, d.name, d.age, d.email, d.phone, d.tin, d.country);
}
/* Gets the necessary data to call the data handling functions. */
void edit(void) {
int item = 0;
Data d;
d.customer_code = (char *) malloc(BUFFER);
printf("Enter the customer code you want to change the data:");
scanf("%d", d.customer_code);
printf("Enter the item to edit:\n--> ");
scanf("%d", &item);
printf("\Enter your email:");
scanf("%s", &d.email);
printf("\nEnter your mobile number: ");
scanf("%lf", &d.phone);
if (main == NULL)
main = data_start(d.customer_code, d.name, d.age, d.email, d.phone, d.tin, d.country);
else
edit_data(main, item, d.customer_code, d.name, d.age, d.email, d.phone, d.tin, d.country);
}
void displays(void) {
if (!check_empty(main))
display_data(main);
}
void search(void) {
Data d;
if (!check_empty(main)) {
d.customer_code = (char *) malloc(BUFFER);
printf("Enter the name to search:\n--> ");
scanf("%d", d.customer_code);
data_search(main, d.customer_code);
}
}
void delete(void) {
if (!check_empty(main))
main = delete_data(main);
}
In the struct definition, nome is of type char. So scanf("%s", &d.nome); is (almost certainly) undefined behavior. nome is large enough to store a string of length zero (it can only hold the null terminator), and if there is any data for scanf to write, then the behavior is undefined since you've overflowed the buffer. If you want to store a string, you need to give it some space. Perhaps just do:
struct lista {
int *cliente_codigo;
char nome[256]; /* Make nome a character array */
int idade;
int nif;
char email;
double phone;
char pais;
struct lista *proximo;
};
and then read into it with "%255s" to ensure you don't overflow the buffer. Also, check the value returned by all your scanf and handle invalid data. (eg, discard bad input, or throw an error).
There may be other issues in your code as well, but this is certainly a show stopper.

When freeing a pointer for a nested struct getting Segmentation fault

This is my code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define NAMESIZE 20
#define LINESIZE 1024
typedef struct name name;
struct name
{
char last[NAMESIZE]; /* last name */
char first[NAMESIZE]; /* first name*/
};
typedef struct record record;
struct record
{
name name;
int score;
};
typedef struct record_list record_list;
struct record_list
{
record *data; /* the dynamic array of records */
size_t nalloc; /* number of records allocated */
size_t nused; /* number of records in use */
};
void list_init(record_list *list)
{
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int list_insert(record_list *list, const record *rec)
{
size_t newSize;
record *tmp;
if(list -> nalloc == list -> nused)
{
if(list -> nalloc == 0)
{
newSize = 1;
}
else
{
newSize = 2 * list -> nalloc;
}
tmp = realloc(list -> data, newSize * sizeof(record));
if(tmp == 0)
{
return 0;
}
list -> data = tmp;
list -> nalloc = newSize;
}
list -> data[list -> nused++] = *rec;
return 1;
}
void list_destroy(record_list *list)
{
printf("Attempting Deletion");
free(list->data);
free(list->nalloc);
free(list->nused);
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int main(void){
record_list list;
record *r;
name n;
int score;
char input[NAMESIZE];
char name[NAMESIZE];
char lname[NAMESIZE];
list_init(&list);
while(input != NULL) {
printf("Please enter a value for Name: ");
scanf("%s", input);
strcpy(input, name);
printf("Enter last name: ");
scanf("%s", input);
strcpy(input, lname);
printf("Enter score: ");
scanf("%d", &score);
r=(record*)malloc(sizeof(record));
if(r == NULL){
printf("There isn't enough memory.\n");
}
strcpy(n.first, name);
strcpy(n.last, lname);
r -> name = n;
list_insert(&list, r);
printf("\n");
printf("Choose next action:\n");
printf("\tTo add more type \"add\";\n");
printf("\tTo delete all records type \"del\";\n");
scanf("%s", input);
if(strcmp(input, "del") == 0){
list_destroy(&list);
printf("Deleted");
break;
}
}
return 1;
}
I am working on a small lab exercise where we make a struct, fill it and clear it if the user needs to. Yesterday everything worked but today I seem to either have not saved it or broke something because I am getting a ton of errors.
Here is an example of the error I'm getting:
Essentially when I call a method
void list_destroy(record_list *list);
it crashes before reaching the first print statement which means I am doing something wrong with the method call.
Summarized question: What could be causing the segmentation fault (where am I accessing incorrect memory) Or how else can I clear my struct memory without using free?
Thank you very much.
This should tell what your problem is:
code.c: In function 'list_destroy':
code.c:74: warning: passing argument 1 of 'free' makes pointer from integer without a cast
code.c:75: warning: passing argument 1 of 'free' makes pointer from integer without a cast
You're trying to free int fields. You can't free them because they are not pointers to memory blocks.
So, remove these lines of code:
free(list->nalloc);
free(list->nused);

Resources