Using loop to create new struct in C - c

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 😊

Related

Segmentation fault when trying to print out a struct

I'm trying to make a code that will allow the user to input any amount of entries he wants, and then print them out (and other functions, still have to get to that). But when I try to launch the code it allows me to input the entries, but when I want to print them out, it doesn't register current.name or current.telNo (only prints out 1: has tel. No. ) and a segmentation error follows after it. Any idea how I can fix that.
#include <stdio.h>
#include <stdlib.h>
int listSize;
int counter = 0;
struct Entry {
char name[20];
char telNo[9];
struct Entry *next;
} current;
int main()
{
struct Entry *linkedList = (struct Entry * )malloc(sizeof(struct Entry));
struct Entry *current = linkedList;
first(current);
print(current);
return 0;
}
void first(struct Entry linkedList)
{
int i;
printf("enter list size: ");
scanf("%d", &listSize);
printf("Now enter entries one by one: \n");
for (i = 0; i < listSize; i++) {
counter++;
printf("Name: ");
scanf("%s", linkedList.name);
printf("Telephone: ");
scanf("%s", linkedList.telNo);
if (i != listSize -1) {
linkedList.next = (struct Entry *)malloc(sizeof(struct Entry));
linkedList = *linkedList.next;
} else {
linkedList.next = NULL;
}
}
}
void print(struct Entry linkedList)
{
int nr = 1;
printf("\nTelephone book is:\n");
while (current.name != NULL) {
printf("%d: %s has tel. No.\t%s\n", nr, current.name, current.telNo);
current = *current.next;
nr++;
}
}
Instead of . you should have used -> and in your print() you were traversing current instead of linkedList which was causing the issue. Also your functions definitions should come before its usage. Please check the below snippet, i have made the corresponding changes.
#include <stdio.h>
#include <stdlib.h>
int listSize;
int counter = 0;
struct Entry {
char name[20];
char telNo[9];
struct Entry *next;
} current;
void print(struct Entry *linkedList)
{
int nr = 1;
printf("\nTelephone book is:\n");
while (linkedList->name != NULL) {
printf("%d: %s has tel. No.\t%s\n", nr, linkedList->name, linkedList->telNo);
linkedList = linkedList->next;
nr++;
}
}
void first(struct Entry *linkedList)
{
int i;
printf("enter list size: ");
scanf("%d", &listSize);
printf("Now enter entries one by one: \n");
for (i = 0; i < listSize; i++) {
counter++;
printf("Name: ");
scanf("%s", linkedList->name);
printf("Telephone: ");
scanf("%s", linkedList->telNo);
if (i != listSize -1) {
linkedList->next = (struct Entry *)malloc(sizeof(struct Entry));
linkedList = linkedList->next;
} else {
linkedList->next = NULL;
}
}
}
int main()
{
struct Entry *linkedList = (struct Entry * )malloc(sizeof(struct Entry));
struct Entry *current = linkedList;
first(current);
print(current);
return 0;
}
while (current.name != NULL)
should be
while (current != NULL)
otherwise current = *current.next will become NULL and crash on the while condition
current.name is a pointer to reserved 20-byte area, which is always non-NULL.
I would initialize *next with NULL every time I allocate it (there are few ways to do that, easiest: assign NULL to it right after malloc). And do the check like that: if (current.next != NULL).
You also can check for current.name[0] != 0, but the first option is cleaner.
There are a number of errors in your code but, essentially two main 'points of confusion':
First, you seem to be confusing a structure (struct Entry) with a pointer-to-structure (as in, for example, struct Entry *next;).
Second, you have two different variables called current - one defined globally (which is the only one that is 'visible' to your print function), and another one defined locally inside main (this one will 'hide' the former).
Here is a corrected version of your code, with triple-slash (///) comments wherever I've made changes. Feel free to ask for further clarification and/or explanation.
#include <stdio.h>
#include <stdlib.h>
int listSize;
int counter = 0;
struct Entry {
char name[20];
char telNo[9];
struct Entry* next;
} *current; /// Here, we define a GLOBAL variable, "current" that is a POINTER to the struct
void first(struct Entry* linkedList); /// Put "Function Prototypes* here, so that "main" knows what they are
void print(struct Entry* linkedList); /// You need to pass POINTERS to structures, not the actual structures
int main()
{
struct Entry* linkedList = (struct Entry*)malloc(sizeof(struct Entry));
// struct Entry* current = linkedList; /// This declaration 'hides' the global variable
current = linkedList; /// Here, we (properly) assign the global pointer's value
first(current);
print(current);
return 0;
}
void first(struct Entry* linkedList) /// Pointer (see above)
{
int i;
printf("enter list size: ");
scanf("%d", &listSize);
printf("Now enter entries one by one: \n");
for (i = 0; i < listSize; i++) {
counter++;
printf("Name: ");
scanf("%s", linkedList->name); /// Use "->" instead of "." to get a pointer's member (and elsewhere)
printf("Telephone: ");
scanf("%s", linkedList->telNo); /// See above
if (i != listSize - 1) {
linkedList->next = (struct Entry*)malloc(sizeof(struct Entry)); /// See above
linkedList = linkedList->next; /// Again - changed here to use pointers!
}
else {
linkedList->next = NULL; /// See above
}
}
}
void print(struct Entry* linkedList) /// Pointer (see above)
{
int nr = 1;
printf("\nTelephone book is:\n");
while (current != NULL) { /// You need to check if "current" is not NULL before trying to access any of its members...
// while (current.name != NULL) {
printf("%d: %s has tel. No.\t%s\n", nr, current->name, current->telNo); /// Same "." to "->" changes as before
current = current->next; /// And again!
nr++;
}
}
There are other ways to 'fix' your code (and also improve it): for example, you never use the argument you pass to print, relying instead on the 'global' variable I mentioned earlier.

Linked Lists and Structures in C - Passing Linked List and Structures as Parameters in function (C)

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;

Printing all "members" of a struct

I have nested-structs (shown below)
in slist* add_student() I am adding new students to the list
void print_student() should print the list
void print_students(slist* students){
slist *tempS = students;
while(tempS){
printf("%d:%s\n", tempS->info->id, tempS->info->name);
tempS = tempS->next;
}
}
slist* add_student(slist *students, char *name, int id){
student* tempStudent;
tempStudent = (student *)malloc(sizeof(student));
tempStudent->id = id;
tempStudent->name = (char*)malloc(strlen(name)+1);
strcpy(tempStudent->name, name);
slist *news;
news=(slist *)malloc(sizeof(slist));
news->info = tempStudent;
news->next = students;
return news;
}
Now the problem is it is only printing the last entered "student", and I can't seem to tell which function is doing it the wrong way, so the question is, is it doing it wrong because I am using newly defined part to the struct (slist* tempS = students in void print_students()) for example? or does it have to do with the next (in both functions)?
an example of an I/O would be
and another...
The struct and main I use, if anyone wants to look at them
static void getstring(char *buf, int length) {
int len;
buf = fgets(buf, length, stdin);
len = (int) strlen(buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
}
int main() {
slist* students = 0;
char c;
char buf[100];
int id, num;
do {
printf("Choose:\n"
" add (s)tudent\n"
" (p)rint lists\n"
" (q)uit\n");
while ((c = (char) getchar()) == '\n');
getchar();
switch (c) {
case 's':
printf("Adding new student.\n");
printf("Student name: ");
getstring(buf, 100);
printf("Student ID: ");
scanf("%d", &id);
students = add_student(students, buf, id);
break;
case 'p':
printf("Printing Information.\n");
print_students(students);
break;
}
if (c != 'q')
printf("\n");
} while (c != 'q');
return 0;
}
// structures
typedef struct student {
char *name;
int id;
struct clist *courses;
} student;
typedef struct course {
char *title;
int number;
struct slist *students;
} course;
typedef struct slist {
student *info;
struct slist *next;
} slist;
typedef struct clist {
course *info;
struct clist *next;
} clist;
In general, pick up a piece of paper and a pencil and draw what your code does; that's a pro tip for finding what's wrong with your list when in trouble!
Your code is fine* now, and let me explain you why.
So, if you do so you will see that when the first student arrives, you allocate space for him/her and then populate that struct correctly. tempStudent points to that struct.
Then, news will create a new struct that is the struct that handles the list. Its info field is set to the newly created student and next points to students, which I guess is NULL when the first student is added.
Then you return news and students now points to it.
Now we are about to add the second student. We create his struct - so far so good!
We again create the struct news which handles the list. It will assign info to newly created student and next will point to students, which is what we want.
Then you return news and students now points to it.
That way of course the newly created student will be places first in the list, despite the fact we added him/her secondly.
As a result, you will get something like this:
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out
Choose:
add (s)tudent
(p)rint lists
(q)uit
s
Adding new student.
Student name: Leon
Student ID: 1
Choose:
add (s)tudent
(p)rint lists
(q)uit
s
Adding new student.
Student name: kate
Student ID: 2
Choose:
add (s)tudent
(p)rint lists
(q)uit
p
Printing Information.
2:kate
1:Leon
which is OK.
*Of course you have to write other functions as well, such as deleting your list and de-allocating the space you already allocated.
Do I cast the result of malloc? No!

malloc and free with a dynamically changing structure

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.

C, Printing more than one integer from a linked list

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.

Resources