how to use a string in struct in linked list? - c

In my code I have 2 structs named villa and apartment. They have members of type char*. When in my void record I get other parts of the structs like villa1.price (which is float) from user,It works ,but when it comes to the char*,I cannot read strings using scanf("%s",&villa1.city) and so I used another array of chars named v1 to get info from users and then assign it to villa1.city using villa1.city=a1.
This worked for the first time, but I want to make a linked list. The first time I send villa1.city to insertFirstVilla to add this to linked list it works, but when I add second node ,the villa1.city in first node is lost and it keeps happening every time I add a new node.
How can I get data from user like villa1.price or if it is not possible how to copy it in way that data remains safe when I add second node to my list.
I post a part of my code for villa, but the code is the same for apartment.
struct villa
{
float built;
float garden;
float price;
int floors;
char* city;
char* ST;
char* alley;
char* postal_code;
}villa1;
struct nodev
{
villa info;
nodev* next;
}*headv = NULL;
void insertFirstvilla(float built, float garden,float price,int floor, char*city) {
nodev* link = (nodev*)malloc(sizeof(nodev));
link->info.built = built;
link->info.garden = garden;
link->info.price = price;
link->info.floors = floor;
link->info.city = city;
link->next = headv;
headv = link;
}
void record()
{
char a;
printf("is the building apartment? (y/n):");
scanf("%c", &a);
char a1[100];
char v1[100];
if (a == 'y')
{
/* printf("enter apartment features:");
printf("\nenter built area:");
scanf("%f", &apart.built);
printf("\nenter basic price:");
scanf("%f", &apart.price);
printf("\nenter floors number:");
scanf("%d", &apart.floor_no);
printf("\ndoes apartment have elavator(if there is no elavotor enter zero else enter one):");
scanf("%d", &apart.elevator);
printf("\nenter city:");
scanf("%s", &a1);
apart.city = a1;
insertFirstapartment(apart.built, apart.price, apart.floor_no, apart.elevator,apart.city);
writetofilea(apart.built, apart.price, apart.floor_no, apart.elevator, apart.city);*/
}
else if (a == 'n')
{
printf("enter villa features:");
printf("\nenter built area:");
scanf("%f", &villa1.built);
printf("\nenter garden area:");
scanf("%f", &villa1.garden);
printf("\nenter basic price:");
scanf("%f", &villa1.price);
printf("\nenter floors number:");
scanf("%d", &villa1.floors);
printf("\nenter city:");
scanf("%s", &v1);
apart.city = v1;
insertFirstvilla(villa1.built, villa1.garden, villa1.price, villa1.floors, villa1.city);
writetofilev(villa1.built, villa1.garden, villa1.price, villa1.floors, villa1.city);
}
getchar();
}
int main()
{
int t = 0;
while (t<4)
{
record();
t++;
}
}

As an example reading the city:
char a1[100];
scanf("%99s", a1); // an array will be passed as an address, so no need for &
apart.city = malloc(strlen(a1)+1); // ask for memory
strcpy(apart.city, a1); // copy it
or use strdup, which does this for you:
char a1[100];
scanf("%99s", a1); // an array will be passed as an address, so no need for &
apart.city= strdup(a1); // get memory and copy it

The basic problem is deep copying versus shallow copying.
struct villa
{
int floors;
char* city;
};
villa V1, V2;
char buffer[10];
strcpy(buffer, "Venice");
V1.city = buffer; /* This copies nothing. V1.city now points to buffer. */
V2 = V1; /* This is a shallow copy. V2.city now points to buffer. */
strcpy(buffer, "Moscow");
printf("%s\n", V2.city); /* prints Moscow */
Do you see the problem? If you want each villa to have a buffer of its own, you must write code to allocate and manage that memory, and if you want the copies to be deep copies, you must write an assignment operator.

Related

Violation of access with pointers and scanf

The following code is supposed to insert the name of a good, whether it's getting stored or sent away (with just a single letter, like i for in or o for out) and in conclusion how much of that item is getting moved.
Then the program should end whenever I write the END phrase.
Problem is, I am finding a violation of access while trying to save the number of items, and cannot seem to find where I am doing something wrong.
#define MAX 20
#define END "FINE"
typedef struct type_struct {
char name[MAX];
char move[2];
int quantity;
struct type_struct* next;
}type;
void insert(type* p) {
type* aux;
aux = p;
while (aux != NULL)
aux = aux->next;
aux = malloc(sizeof(type));
printf("name of good: ");
scanf("%s", aux->name);
getchar();
printf("in or out?: ");
scanf("%c", aux->move);
printf("quantity: ");
scanf("%d", aux->quantity);
printf("\n");
}
int main(void) {
type* phrase=NULL;
char fine[5];
strcpy(fine, END);
do {
insert(phrase);
} while ((strcmp(phrase, fine) == 0));
}
It should be very simple, however, I am clueless and hope you might give me a hand

C programming : Grouping multiple strings and searching for it using an Unique key

Let's say for example you are entering the personal information of a student and you create a unique ID number for each student. What I'm having problems with is grouping those strings, and storing them together, so that it can be accessed through the ID.
I tried using memory allocation, however, it did not work out.
I'm quite new to C, so I'm not exactly sure on what to do.
Here is what I used :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
} student;
int reg(void);
int main(void) {
reg();
return 0;
}
//Registration function
int reg(void) {
int choice,shift,found,compare, nosub, y, sub, subcount;
char studentname[20];
FILE *fp;
FILE *fp2;
printf("Enter Student Details:\n\nStudent ID: ");
scanf("%d",&student.LogID);
printf("Name: ");
scanf("%s",student.firstname);
printf("Surname: ");
scanf("%s",student.lastname);
printf("How many subjects does the student take? ");
scanf("%d", &nosub);
//Opens a text file and prints the student's ID and firstname
fp2=fopen("subjects.txt","a+");
fprintf(fp2, "\n\n%d\t%s", student.LogID, student.firstname);
int i = 1;
size_t malloc_size = 100; //Allocating memory size to store subjects student is taking
for(i = 0; i < nosub; i++) {
student.subjects[i] = malloc(malloc_size * sizeof(char));
printf("Please enter the subject :\n(1)Mathematics\n(2)English\n(3) Social Studies\n(4)Science\n");
scanf("%d", &sub);
switch (sub) {
case (1) :
printf("Mathematics\n");
break;
case (2) :
printf("English\n");
break;
case (3) :
printf("Social Studies\n");
break;
case (4) :
printf("Science\n");
break;
}
}
for(i = 0; i < nosub; i++) { //Prints subjects to file, but it doesn't work...
fprintf(fp2,"%s\n", student.subjects[i]);
}
fclose(fp2);
free(student.subjects[i]);
student.subjects[i] = NULL;
fp=fopen("studentfile.txt","a+");
//Prints certain student Information into another file...
fprintf(fp,"\n%d\t%s\t%s\t",student.LogID,student.firstname,
student.lastname);
fclose(fp);
printf("Registration has been successful\n");
getchar();
return 0;
}
There were a number of issues I noticed and I'll address some of them, starting with the struct which I recommend defining like this:
struct studentpack {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
And under your main function, you can define the student entry for filling.
struct studentpack student;
which will be used over and over again in your code, as you did in your example, for filling from the user input.
In the switch you really don't need any parenthesis around the case numbers.
In addition to the printf statement in each case, try something like this:
case 1:
printf("%s\n", "Mathematics");
sprintf(student.subjects + i, "%s", "Mathematics");
break;
which will fill the subjects area that you memory allocated just prior.
Finally, for grouping together the ID's I would suggest starting with something like this:
#define MAXGROUP 1000
struct studentpack *group = calloc(MAXGROUP, sizeof(struct studentpack));
int studentno = 0;
And then after you print your subjects to the file (test that it is working first due to the sprintf change) you would assign to the group like this:
if (studentno < MAXGROUP) {
memcpy(group+studentno, &student, sizeof(struct studentpack));
studentno++;
}
The above will store away the student. Next you will probably want to iterate through the group variable, accessing group[0].LogID, group[1].LogID, etc. (all the way up to a maximum of 1000) just to confirm that all your data is there in memory.
For example you could write a function that steps through looking for a particular LogID and then calls a show or display function containing printf statements to see all the values on screen.
you need an array of students
struct student{
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
struct student students[100];
you now have space for 100 students. They are students[0], students[1],...students[99]
Now you can do
int studno = 0;
While(something)
{
printf("\Enter Student Details:\n\nStudent ID: ");
scanf("%d",&(students[studno].LogID));
....
studno++;
}

allocating in heap memory array of pointers to struct

I'm trying to make simple data base by using structure like
struct Employee{
char* name;
int ID;
int GPA;
int salary;
};
i know how i can allocate one pointer of the struct type in heap by using that
struct Employee* emp=malloc(sizeof(Employee));
my problem now that i'm not very good in allocating processes and i want
to allocate N number of pointer of the struct in the heap and i can't use arrays because the size will not be knows until running time
any suggestions ?
Yes, you need to allocate the memory dynamically, i.e. allocate a new heap block for every new struct Employee.
You can do this for example using realloc when the size changes:
yourArrayPtr=realloc(yourArrayPtr,newsize * sizeof(struct Employee));
The realloc function basically assigns a new amount of memory for the data pointed by its return value. It is a convenient way of expanding, or shrinking a dynamically allocated array. newsize here is the new number of elements of your array, and it is multiplied by the size of one Employee structure, rendering the total amount of space needed for your new array. The return value of realloc is assigned to your array pointer, so that it points specifically to this newly allocated space. In this case it could be used like this:
struct Employee* emp= NULL;
And then when you need it:
int n = 8;
emp = realloc (emp, n * sizeof(struct Employee));
Keep in mind, that you still have to free this memory.
You can now initialize and access this data:
emp[3] = {value1, value2, value3, ...};
As far as structures go, you could also think of another data structure - a linked list, where every structure contains a pointer to its successor. You can read about it here: http://www.cprogramming.com/tutorial/c/lesson15.html
In your case, it would be sth like:
struct Employee{
char* data;
struct Employee* next;
};
As others mentioned, you can use malloc to create as many entries of employee details in heap and store them in a dynamic list(linked list). i have given an example code, you can start from here and extend it, if you want to save the employee details before exiting, you can write it to a binary file and read it back when you run the program again(based on your needs), since once you program exits all the data will be lost.
#include <stdio.h>
#include <stdlib.h>
// Max length for employee name
const unsigned int MAX_NAME_LEN = 100;
typedef struct Employee{
char* name;
unsigned int ID;
int GPA;
float salary;
} EMPLOYEE ;
typedef struct emp_database_entry {
EMPLOYEE data;
struct emp_database_entry *next;
} EMPLOYEE_ENTRY;
typedef EMPLOYEE_ENTRY* EMPLOYEE_DATABASE;
// to create a new employee
EMPLOYEE_ENTRY* createEmployee() {
EMPLOYEE_ENTRY *newEmp = (EMPLOYEE_ENTRY*)malloc(sizeof(EMPLOYEE_ENTRY));
printf("Enter Employee Name:");
newEmp->data.name = (char*)malloc( MAX_NAME_LEN * sizeof(char) );
scanf("%s",newEmp->data.name);
printf("Enter employee ID:");
scanf("%u",&newEmp->data.ID);
printf("Enter employee GPA:");
scanf("%u",&newEmp->data.GPA);
printf("Enter employee salary:");
scanf("%f",&newEmp->data.salary);
newEmp->next = 0;
return (newEmp);
}
// add a new employee to database
EMPLOYEE_DATABASE addEmployee(EMPLOYEE_DATABASE db) {
EMPLOYEE_ENTRY *newEmp = createEmployee();
if(db == NULL) {
// add the first entry
db = newEmp;
} else {
// add it to the top
newEmp->next = db;
db = newEmp;
}
return (db);
}
// Search for Employee using ID
EMPLOYEE_ENTRY* searchEmployee(EMPLOYEE_DATABASE db, unsigned int ID) {
EMPLOYEE_ENTRY *employee = db;
if(employee == NULL) {
printf("There are no Employees in the database\n");
return (NULL);
}
// Search till the end, if a match is found return the
// pointer to employee
while( employee != NULL ) {
if( employee->data.ID == ID )
return (employee);
else
employee = employee->next;
}
return (NULL);
}
void printOneEmployee( EMPLOYEE_ENTRY *employee ) {
printf("Employee Details\n");
printf("Name : %s\n",employee->data.name);
printf("ID : %u\n",employee->data.ID);
printf("GPA : %d\n",employee->data.GPA);
printf("Salary: %f\n\n",employee->data.salary);
}
// Print all employee details
void printAllEmployee( EMPLOYEE_DATABASE db ) {
EMPLOYEE_ENTRY *employee = db;
// traverse till the end and print one by one
while( employee != NULL ) {
printOneEmployee(employee);
employee = employee->next;
}
}
// freeing allocated memory
void freeDatabase(EMPLOYEE_DATABASE db) {
EMPLOYEE_DATABASE employee = 0;
while( db != NULL ) {
employee = db;
db = employee->next;
free(employee->data.name);
free(employee);
}
}
void displayOption( EMPLOYEE_DATABASE db ) {
int option = -1;
while( option != 5 ) {
printf("\nEmployee DataBase\n");
printf("1: Add a Employee\n");
printf("2: Search Employee\n");
printf("3: Print All Employee\n");
printf("4: Exit\n");
printf("Enter a number for the choice: ");
scanf("%d",&option);
if( option > 4 || option < 0 ) {
option = -1;
}
switch( option ) {
case 1:
db = addEmployee(db);
break;
case 2:
int ID;
if(db != NULL){
printf("Enter the Employee ID: ");
scanf("%d",&ID);
printf("Search Result1: ");
printOneEmployee(searchEmployee(db, ID));
}
else
printf("No Employees in the database\n");
break;
case 3:
printAllEmployee(db);
break;
case 4:
freeDatabase(db);
printf("DataBase Deleted\nExiting..");
exit(0);
default:
printf("Invalid Option!. Try Again!.\n");
}
}
}
int main() {
EMPLOYEE_DATABASE db = 0;
displayOption(db);
return (0);
}
Of course you can use arrays if you use C99. In C99 you can do things like:
scanf("%d", &N);
struct Employee emp[N];
emp[0].ID = 123;
if you are using gcc (or MinGW), just be sure to compile with -std=c99
On the other hand, if you just want to create an array on the heap, you can do something like:
scanf("%d", &N);
struct Employee* emp=malloc(N*sizeof(Employee));
emp[0].ID =123;
...
// do not forget to deallocate emp
free(emp);

Adding records with pointers to arrays

I have to create a program which adds records to a simple phone book. The code is below, but it doesn't work - function ends and then it stucks on declaring struct record x and doesn't want to display my added record - the program breaks down. When I put this part of code on the end of the function (but instead of "struct record x = array[0];" I put "struct record x = (*array)[0]") it works - record is printed. So I guess the problem is something about pointers, but I'm struggling and I really couldn't find out what's wrong. I remember that few weeks ago I created a program which was very similar but it was adding a new record to an array of integers, with fixed values and it was working well, so maybe there's something with structures that I don't know about. Thanks for any help!
I know the program isn't done yet and I know that I didn't make any action for temp_array == NULL, it'll be done after I found out what's going on.
struct record {
char f_name[SIZE];
char name[SIZE];
long int phone;
};
int add_record(struct record** array, int n)
{
struct record* temp_array = malloc((n+1) * sizeof(struct record));
if (temp_array == NULL)
{
free(temp_array);
return -1;
}
int i;
for (i=0; i < n; i++)
{
temp_array[i] = (*array)[i];
}
struct record new_record;
printf("\nAplly data.");
printf("\nFirst name: "); /*fgets(new_record.f_name, SIZE, stdin);*/ scanf("%s", &new_record.f_name);
printf("Surname: "); /*fgets(new_record.name, SIZE, stdin);*/ scanf("%s", &new_record.name);
printf("Phone number: "); scanf("%d", &new_record.phone);
temp_array[n] = new_record;
free (*array);
*array = temp_array;
//struct record x = (*array)[0];
//puts(x.f_name); puts(x.name); printf("%d", x.phone);
return 0;
}
main()
{
struct record* array; int n = 0;
int choice;
printf("\n1. Add record\n2. Delete record\n3. Find record\n0. Exit\n\nChoose action: ");
scanf("%d", &choice);
switch(choice) {
case 0: printf("\nKsiazka zostala zamknieta.\n"); return;
case 1: add_record(&array, n); n++; break;
case 2: return;
case 3: return;
default: printf("Wrong choice.\n\n"); return;
}
struct record x = array[0];
puts(x.f_name); puts(x.name); printf("%d", x.phone);
}
struct record* array=NULL;, and use %ld for long int – BLUEPIXY

Searching through a linked list.

So i've been trying to understand the difference between a regularly defined structure without using malloc linked list that does utilize malloc.
The issue that i'm having right now is trying to search through the structure (pi) to find each part number that has a cost greater than what was entered into the search. this is my entire program so far. I've added comments for each section.
I'm simply not sure how i am suppose to search through each structure to compare its price to the search price.
#include <stdio.h>
#include <stdlib.h>
struct Item {
int quantity;
float cost;
char partNum[10];
struct Item *next;
};
void printItem(struct Item* pi);
void enterItem(struct Item* pi);
char search [100];
void main(int argc, char* argv[])
{
struct Item *pi;
struct Item *head;
int done = 0;
int i,j;
char choice;
// ENTERING ITEM INTO THE STRUCTURE
head = NULL;
while (!done) {
printf("Enter another item? (y/n)");
choice = getchar();
if (choice == 'y' || choice == 'Y') {
pi = (struct Item *)malloc(sizeof(struct Item));
enterItem(pi);
pi->next = head;
head = pi;
} else {
done = 1;
}
}
// SEARCHING FOR ITEM BY PRICE
printf("Enter a price to find all items more expensive, or type 'exit':");
while (strcmp(search, "exit") !=0) {
gets(search);
for (j = 0; j<i ; i++) {
if (strcmp(pi[j].cost, search) ==0) {
printItem(pi);
pi = pi->next;
}
}
}
}
getchar();
getchar();
}
// FUNCTION FOR PRINTING STRUCTURE ITEM
void printItem(struct Item* pi) {
printf("Quantity: %d\n", pi->quantity);
printf("Cost: $%.2f\n", pi->cost);
printf("Part # %s\n", pi->partNum);
printf("\n\n");
}
// FUNCITON FOR ENTERING IN NEW ITEM
void enterItem(struct Item* pi) {
printf("Quantity? ");
scanf("%d", &pi->quantity);
printf("Cost? ");
scanf("%f", &pi->cost);
getchar(); //need to clear out the carriage return from typeing in the cost
printf("Part Number? ");
gets(pi->partNum);
}
What you were doing wrong is comparing string(search variable) with a float(cost variable) using strcmp. This won't give you the desired output.
Instead, lets use -1 to indicate the exit, since parsing string and converting it to float is off-topic. Start iterating from head up to finding NULL, and compare the prices of the each item.
float price;
struct Item *it = head;
printf("Enter a price to find all items more expensive, or type '-1' to exit:");
scanf("%f", price);
// check price for the 'exit' -- compare with -1
while (it != NULL) {
if (it->cost > price)
printItem(pi);
it = it->next;
}

Resources