I am having trouble with moving my pointer in a dynamically changing structure.
I have created my code where you can malloc more memory and this seems to be working.
The problems that I am running into is how to add to the structure, how to free memory and how to move from structure to structure and print all items.
I am trying to test add and print (the delete function that is there does not seem to work, segfaults)
When I add to the struct and then print the struct I get a segfault from the values that I have added. I don't know if I am moving from the first struct to the next struct correctly.
#include <stdio.h>
#include <stdlib.h>
#include "pointer.h"
/********************************************
Creates more memory for size (strut * rec+1)
*********************************************/
employee *create(int record){
employee *new_employee = malloc(sizeof(employee) * (record+1));
return new_employee;
}
/********************************************
Copies the data from one structure to a new structure with
size "structure" multipled by rec+1
***********************************************/
employee *copy(employee *data, int record){
employee *new_employee = create(record);
int i;
for(i = 0; i<record;i++){
new_employee->first = data->first;
new_employee->last = data->last;
new_employee->start_date = data->start_date;
new_employee->sal = data->sal;
data++;
}
/********************
Needs to free the old struct
*********************/
//deleteData(data, record);
return new_employee;
}
/********************************************
Function prints everything in the struct
*********************************************/
void printStruct(employee *data, int record){
int i;
for(i = 0; i<record; i++){
printf("\nEntry: %d\n", i+1);
printf("The employee's name is %s %s\n", data->first, data->last);
printf("The employee was hired on: %s\n", data->start_date);
printf("The employee make $%f\n\n", data->sal);
data++;
}
}
/******************************************
Function frees the old data base
*******************************************/
void deleteData(employee *data, int record){
int i;
for(i = 0; i<record; i++){
free(data->first);
free(data->last);
free(data->start_date);
data++;
}
free(data);
}
/******************************************
Adds an employee to the new structure
*******************************************/
employee *add(employee *data,char *fname, char *lname, char *date, float salary, int record){
employee *employeeDB = create(record);
employeeDB = copy(data, record);
int i;
employeeDB++;
employeeDB->first = fname;
employeeDB->last = lname;
employeeDB->start_date = date;
employeeDB->sal = salary;
return employeeDB;
}
/**************************
Starts of the main function
***************************/
int main(void){
//Keeps track of the number of records that are in the structure
int rec = 0;
//Keeps the number of accesses to the structure. Even with the one entry the structure has not been accessed.
int acc = 0;
//Holds the input information for the menu
int input;
//holds the information for inputing user first name
char *fname;
//holds the information for inputing user last name
char *lname;
//holds the information for for the startdate
char *start;
//holds the information for the salary;
float sal;
/*********************************
This next section adds an employee to the record
************************************/
//This creates the first entry to the dynamic structure.
employee *first_employee = create(rec);
first_employee->first = "FIRST";
first_employee->last = "LAST";
first_employee->start_date = "June-20th-2006";
first_employee->sal = 55555.55;
//increase the number of records
rec = rec+1;
employee *new_employeeDB = add(first_employee, "fname", "lname", "JUNE-20th-2010", 55555.55, rec);
rec = rec + 1;
printStruct(new_employeeDB, rec);
printf("%d\n", (sizeof(employee)* rec));
}
First problem: Ok... you didn't include the declaration of employee type.
I guess first and last are declared as char pointers, and this is an error.
You need them to be fixed size char array or this will never work.
Choose a maximum length for the string and declare the structure like this.
typedef struct
{
char name[50];
char surname[50];
....
} employee;
Previous post:
Well i must admit i don't like much this way of implementing the thing.
I would use a more stable approach.
First of all, since it is just a list of items, you can use a doubly linked list.
This will allow you to add and remove elements with an O(1) complexity. Quite good, indeed.
This will also allow you to iterate all items from the first to the last.
For doing that i would use a more OOP oriented approach :) I know, we are in C but listen to this idea.
typedef struct
{
MyList* OwnerList;
Employee* Previous;
Employee* Next;
char name[50];
int age;
} Employee;
typedef struct
{
Employee* First;
Employee* Last;
int Count;
} MyList;
MyList* AllocList() { return calloc(sizeof(MyList), 1); }
void DeleteList(MyList* list)
{
Employee* current;
Employee* next;
for (current = list->First; current != NULL; current = next)
{
next = current->Next;
free(current);
}
free(list);
}
int GetCount(const MyList* list)
{
return list->Count;
}
Employee* AddAmployee(MyList* list)
{
Employee* result = calloc(sizeof(Employee), 1);
Employee* last = list->Last;
if (last != null)
last->Next = result;
else
list->First = result;
result->Previous = last;
list->Last = result;
++list->Count;
result->OwnerList = list;
return result;
}
void RemoveEmployee(Employee* employee)
{
/* i leave removal for you as exercise :) look for doubly linked list */
free(employee);
}
Now, to iterate all items is simple:
Employee* current;
for (current = list->First; current != null; current = current->Next)
printf("%s %d\n", current->name, current->age);
You're not using malloc to allocate first, last, and start_date attributes of employee. Therefore, when you call free on the pointers in deleteData, you're corrupting memory. I would also consider using a linked list or some other data structure (like an array) to hold the employee records instead, allowing you to have a cleaner interface.
Related
Here, I have created a structure of student having name, roll no, marks, etc as their members. So, what I wanted to do was create a new struct every time it iterates through a loop and saving data in it as it loops through.
So, I created a variable stdname that changes it's value every iteration and use it as a way to name a new student but it's not working. I am fairly new to C and I don't know what is wrong with my code here.
#include <stdio.h>
struct Marks
{
int phy;
int chem;
int math;
};
struct Student{
char name[50];
int rollN0;
char remarks[100];
struct Marks marks;
};
int main()
{
for (int i=0; i<10; i++)
{
char stdname[50];
sprintf(stdname,"student%d",i+1);
struct Student stdname;
printf("Enter the following data of Student No. %d:\n", i+1);
//taking data from user and storing
}
}
I propose you to solve your problem by implementing a systeme of linked list or tabs. I personnaly perfere linked list because when your code will evolute it's going to be easier to used the list in my pov.
So in the code you will see in your structure i add a next pointer this one will store the adresse of another student, if next is NULL then we can affirm there is no more student and we can stop crawling throught the list.
the function add use this principe; she goes to the tail of the list then replace the next with the adresse of the new student structure. And because the next of the new structure is NULL this process it re-usable
The function create_new_node is only data initation and memory allocation.
It looks very ugly because i don't realy know what you want store.
❗ I didn't test this code and it's not optimised at all ❗
#include <stdio.h>
#include <stdlib.h> // for malloc function
struct Marks
{
int phy;
int chem;
int math;
};
struct Student{
char name[50];
int rollN0;
char remarks[100];
struct Marks marks;
struct Student* next; // I had this
};
/// new ///
void add_node_to_list(struct Student* node, struct Student* list)
{
while (list->next != NULL)
list = list->next;
list->next = node;
}
struct Student* create_new_node(struct Student data)
{
struct Student* new_node = malloc(sizeof(struct Marks));
if (!new_node)
return NULL;
new_node->name = data.name;
new_node->rollN0 = data.rollN0;
new_node->remarks = data.remarks;
new_node->marks = data.marks;
new_node->next = NULL;
return new_node;
}
/// end-new ///
int main(void /* new */)
{
struct Student* list = NULL;
struct Student* new_node = NULL;
for (int i=0; i<10; i++)
{
char stdname[50];
sprintf(stdname,"student%d",i+1);
/// new ///
if (!list) { // first the first element
list = create_new_node((struct Marks) {stdname, 0, "\0", {0, 0, 0}, NULL});
if (!list) // check for malloc errors
return 1;
} else { // every time there is a new student
new_node = create_new_node((struct Marks) {stdname, 0, "\0", {0, 0, 0}, NULL});
if (!new_node) // check for malloc errors
return 1;
add_node_to_list(new_node, list);
}
/// end-new ///
printf("Enter the following data of Student No. %d:\n", i+1);
//taking data from user and storing
}
return 0; // new: your main should always return a value. Compile with W flags see: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
}
Here is my propostion,
Notice me if i had been clumsy, i'm a new user on stack.
Also feel free to ask question or fix my own error
Hope I helped you 😊
I have the following code and I am trying to make it more dynamic and reusable.
Well, I have a struct named Student and struct list, which contains all the added students. I have a function "int addStudent(Student b, list StudentList){", and I am trying to pass the structs Student and StudentList as parameters. But the problem is that I am doing something wrong and my list does not contains all the Students added. It contains only the last one.
Can you help me?
NOTE: I have to create a body for the "int addStudent(Student b, list StudentList)". It is not permitted to change the declaration of this function ... this is very difficult for me and I need suggestions to work on ...
thank you in advance!
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRING 100
#define MAXLessonS 100
typedef enum genders{
female,
male
} genders;
typedef struct Student
{
char name[MAXSTRING];
char Surname[MAXSTRING];
enum genders gender;
int id;
char Lessons[MAXLessonS][MAXSTRING];
} Student;
typedef struct list
{
struct list * next;
struct Student * Student;
} list;
void printlist(list * StudentList)
{
list * current = StudentList;
while (current != NULL) {
printf("Student ID = %d\n", current->Student->id);
printf("Student name = %s\n", current->Student->name);
printf("Student Surname = %s\n", current->Student->Surname);
printf("Student gender = %d\n", current->Student->gender);
printf("Student Lesson = %s\n", current->Student->Lessons);
current = current->next;
}
}
int main()
{
Student b={"name 1","Surname 1",male,22,{"Lesson 1"}};
Student c={"name 2","Surname 2",female,32,{"Lesson 2"}};
list* StudentList = NULL;
StudentList = malloc(sizeof(list));
StudentList->next = NULL;
//StudentList->next->next = NULL;
int x=addStudent(b,StudentList);
StudentList->next=NULL;
int xx=addStudent(c,StudentList);
printlist(StudentList);
return 0;
}
int addStudent(Student b, list StudentList){
//StudentList=malloc(sizeof(list));
StudentList.Student = &b;
//StudentList.next->next=NULL;
//free(StudentList);
return 1;
}
The addStudent method always overwrites previous nodes. So your list only ever contains 1 node. Also, to "store" a linked list, you would want to keep a pointer to the head (first element) of the list.
You have two problems:
1) You add the address of a local variable to the list
2) You never expand the list, i.e. it always contain a single element
To solve problem 1) change the addStudent function like:
int addStudent(Student* b, list* StudentList){
^^^ ^^^
Use a pointer
StudentList->Student = b;
^^^
Save the pointer
return 1;
}
and call it like:
int x=addStudent(&b, StudentList);
^^
To solve problem 2):
You need to malloc a new list item and insert it into the current list.
However, your current code is a bit strange as you also allocate a list in main but puts nothing into it. Instead it would seem better to only allocate list items in the addStudent function.
A simple way to do that is:
// This function inserts new item in the front of the list
list* addStudent(Student* b, list* StudentList){
list* t;
t = malloc(sizeof(list));
if (!t) exit(1);
t->next = StudentList;
t->Student = b;
return t;
}
int main()
{
Student b={"name 1","Surname 1",male,22,{"Lesson 1"}};
Student c={"name 2","Surname 2",female,32,{"Lesson 2"}};
list* StudentList = NULL;
StudentList = addStudent(&b, StudentList);
StudentList = addStudent(&c, StudentList);
printlist(StudentList);
return 0;
}
Use a while to go to the last element with a pointer, then create your new element in your list
void addStudent(Student *b, list *StudentList)
list *elem;
elem = StudentList;
while (elem->next)
elem = elem->next;
//now you can create your elem
elem->next = malloc(sizeof(list));
elem->next->student = b;
elem->next->next = NULL;
I have a struct and in that a struct i have a character pointer but and i am creating different instances of this struct but when i am changing the pointer in one struct the other is also changing.
#include <stdio.h>
#include <stdlib.h>
typedef struct human{
int age;
char name[100];
} Human;
int main(){
FILE *s = fopen("h.txt","r");
if(s==NULL){
printf("file not available");
}
for(int i=0 ;i<5;i++){
Human h;
fscanf(s,"%d",&h.age);
fscanf(s,"%s",h.name);
insertintolinkedlist(h);
// this method is going to insert the human into the linked list
}
return 0;
}
what is happening that all humans in the linked list have different ages but same name!
You need to allocate memory to hold the name.
char* name is just a pointer - it has no memory for saving the name.
You change it to
char name[100];
Remember to check that the names you put into Human.name isn't longer than 100 characters.
To use a linked list you can do something like:
typedef struct human{
int age;
char name[100];
struct human* next;
} Human;
int main()
{
Human* head = NULL;
Human* tail = NULL;
for(.....)
{
Human* h = malloc(sizeof(Human));
if (head == NULL) head = h;
if (tail != NULL)
{
tail->next = h;
}
tail = h;
h->next = NULL;
h->age = ....;
strncpy(h->age, "..name..", 100);
}
// ..... other code
// Remember to free all allocated memory
}
I am goofing around with pointers and structures. I want to achieve the following:
(1) define a linked list with a structure (numberRecord)
(2) write a function that fills a linked list with some sample records by going thourgh a loop (fillList)
(3) count the number of elements in the linked list
(4) print the number of elements
I am now so far that the fillList function works well, but I do not succeed in handing over the filled linked list to a pointer in the main(). In the code below, the printList function only displays the single record that was added in main() instead of displaying the list that was created in the function fillList.
#include <stdio.h>
#include <stdlib.h>
typedef struct numberRecord numberRecord;
//linked list
struct numberRecord {
int number;
struct numberRecord *next;
};
//count #records in linked list
int countList(struct numberRecord *record) {
struct numberRecord *index = record;
int i = 0;
if (record == NULL)
return i;
while (index->next != NULL) {
++i;
index = index->next;
}
return i + 1;
}
//print linked list
void printList (struct numberRecord *record) {
struct numberRecord *index = record;
if (index == NULL)
printf("List is empty \n");
while (index != NULL) {
printf("%i \n", index->number);
index = index->next;
}
}
//fill the linked list with some sample records
void fillList(numberRecord *record) {
numberRecord *first, *prev, *new, *buffer;
//as soon as you add more records you get an memory error, static construction
new = (numberRecord *)malloc(100 * sizeof(numberRecord));
new->number = 0;
new->next = NULL;
first = new;
prev = new;
buffer = new;
int i;
for (i = 1; i < 11; i++) {
new++;
new->number = i;
new->next = NULL;
prev->next = new;
prev = prev->next;
}
record = first;
}
int main(void) {
numberRecord *list;
list = malloc(sizeof(numberRecord));
list->number = 1;
list->next = NULL;
fillList(list);
printf("ListCount: %i \n", countList(list));
printList(list);
return 0;
}
SOLUTION
Do read the posts below, they indicated this solution and contain some very insightful remarks about pointers. Below the adapted code that works:
#include <stdio.h>
#include <stdlib.h>
typedef struct numberRecord numberRecord;
//linked list
struct numberRecord {
int number;
struct numberRecord *next;
};
//count #records in linked list
int countList(struct numberRecord *record) {
struct numberRecord *index = record;
int i = 0;
if (record == NULL)
return i;
while (index->next != NULL) {
++i;
index = index->next;
}
return i + 1;
}
//print linked list
void printList (struct numberRecord *record) {
struct numberRecord *index = record;
if (index == NULL)
printf("List is empty \n");
while (index != NULL) {
printf("%i \n", index->number);
index = index->next;
}
}
//fill the linked list with some sample records
numberRecord *fillList() {
numberRecord *firstRec, *prevRec, *newRec;
int i;
for (i = 1; i < 11; i++) {
newRec = malloc(sizeof(numberRecord));
newRec->number = i;
newRec->next = NULL;
//initialize firstRec and prevRec with newRec, firstRec remains head
if (i == 1) {
firstRec = newRec;
prevRec = newRec;
}
prevRec->next = newRec;
prevRec = prevRec->next;
}
return firstRec;
}
int main(void) {
numberRecord *list;
list = fillList();
printf("ListCount: %i \n", countList(list));
printList(list);
return 0;
}
This statement in fillList
record = first;
has no effect on the list variable in main. Pointers are passed by value (like everything else) in C. If you want to update the list variable in main, you'll either have to pass a pointer to it (&list) and modify fillList accordingly, or return a numberRecord* from fillList. (I'd actually go with that second option.)
Here's a (bad) illustration:
When main calls fillList, at the starting point of that function, the pointers are like this:
main memory fillList
list ----> 0x01234 <---- record
A bit later in fillList, you allocate some storage for new (that's actually a bad name, it conflicts with an operator in C++, will get people confused)
main memory fillList
list ----> 0x01234 <---- record
0x03123 <---- new
At the last line of fillList you're left with:
main memory fillList
list ----> 0x01234 ,-- record
0x03123 <---- new
record and list are not the same variable. They start out with the same value, but changing record will not change list. The fact that they are both pointers doesn't make them any different from say ints in this respect.
You can change the thing pointed to by list in fillList, but you can't change what list points to (with your version of the code).
The easiest way for you to get around that is to change fillList like this:
numberRecord *fillList() {
....
return new;
}
And in main, don't allocate list directly, just call fillList() to initialize it.
I'm very new to C, so I'm not totally sure what's the matter. I can't figure out how to print more than a single integer value in a function.
add function:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof(struct list));
strcpy((*newAlbum).name, name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
show function:
void show()
{
system("clear");
struct list *current_node;
current_node = pFirst;
while(current_node != NULL)
{
printf("Album #%d \n",current_node->id);
printf("Album Name: %s \n",current_node->name);
printf("Album Copies:%d \n",current_node->copies);
printf("\n");
current_node=current_node->pNext;
}
}
My program prints out the current_node->id as if it were current_node->copies, and current_node->copies is printed out as 134516043, which is obviously, wrong.
I think I must be passing something wrong to the function or something, but I can't figure it out. Any tips?
I call the function add like this:
add(name,id,copies);
The list is as so:
/* THE LIST */
struct list{
char name[52];
int id;
int copies;
int sold;
struct list* pNext;
};
struct list *pFirst = NULL;
I call the function with user input with this piece of code:
printf("Enter the name of the new album. \n");
scanf("%s",&name);
printf("Enter the album id. \n");
scanf("%d",&id);
printf("Enter number of copies. \n");
scanf("%d," &copies);
// Pass data to add()
add(name,id,copies);
Your code that you've shown is OK, as long as you don't pass an album name to add() which is longer than 51 characters. If you do, you'll get very weird output, and possibly a crash.
To guard against this, you should use a length-limited copy - for example:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof *newAlbum);
if (newAlbum) {
snprintf(newAlbum->name, sizeof newAlbum->name, "%s", name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
}
(note that sizeof *newAlbum is a little better than sizeof(struct list), since the former is "obviously correct" when reading the line - it will still be corret if the type of newAlbum is ever changed).
The only thing I can see wrong here is that you don't check the length of name. You should use:
strncpy(newAlbum->name, 52, name);
This will prevent overrunning the name buffer.