Hi I'm creating a linked list that holds students' information.
However, when displaying the string variables of the student struct, it displays characters other than the strings that it's supposed to display. Here is the snippet from my code (I cut out the code unrelated to my problem):
# include <stdio.h>
# include <stdlib.h>
struct Student {
int student_number[2];
char *last;
char *first;
char *course;
int year;
int age;
char sex;
int grade;
struct Student * next;
};
typedef struct Student Student;
struct SLList {
Student * head;
Student * tail;
int size;
};
typedef struct SLList SLList;
void initList(SLList * list){
list->head = 0;
list->tail = 0;
list->size = 0;
}
Student * getStudent(SLList * list, int index) {
Student * current = list->head;
for (int i = 0; i < index; i ++) {
current = current->next;
}
return current;
}
Student * createStudent(int * number, char *last, char *first, char * course, int year, int age, char sex, int grade){
Student * student = (Student *) malloc(sizeof(Student));
student->student_number[0] = number[0];
student->student_number[1] = number[1];
student->last = last;
student->first = first;
student->course = course;
student->year = year;
student->age = age;
student->sex = sex;
student->grade = grade;
student->next = 0;
return student;
}
void enrolStudent(SLList * list, int index){
Student * student;
int i, found = 1;
int student_number[2];
char last[15];
char first[15];
char course[15];
int year;
int age;
char sex;
int grade;
printf("Student Number: ");
scanf("%i-%i", &student_number[0], &student_number[1]);
printf("Last Name: ");
scanf("%s", last);
printf("First Name: ");
scanf("%s", first);
printf("Course: ");
scanf("%s", course);
printf("Year: ");
scanf("%i", &year);
printf("Age: ");
scanf("%i", &age);
printf("Sex [M or F]: ");
scanf(" %c", &sex);
printf("Final Grade: ");
scanf("%i", &grade);
Student * toInsert = createStudent(student_number, last, first, course, year, age, sex, grade);
if (index == 0){
toInsert->next = list->head;
list->head = toInsert;
}
if (index == list->size){
if (list->tail != 0) {
list->tail->next = toInsert;
}
list->tail = toInsert;
}
list->size ++;
return;
}
void showStudents(SLList * list, int index) {
Student * student = getStudent(list, index);
printf("\n");
printf("Student Number: %i-%i\n", student->student_number[0], student->student_number[1]);
printf("Last Name: %s\n", student->last);
printf("First Name: %s\n", student->first); //! error in printing strings
printf("Course: %s\n", student->course);
printf("Year Level: %i\n", student->year);
printf("Age: %i\n", student->age);
printf("Sex: %c\n", student->sex);
printf("Final Grade: %i\n", student->grade);
printf("\n");
}
int main(){
int choice = 0;
int rtn = 0;
SLList students;
initList(&students);
printf("What do you want to do?\n");
printf("1. Enrol a student\n");
[...]
printf("4. Display all student/s\n");
for(;;){
printf("\nEnter a number: ");
rtn = scanf("%d", &choice);
if (choice == 1) {
enrolStudent(&students, students.size);
} else if (choice == 4) {
int i;
for (i = 0; i < students.size; i ++){
showStudents(&students, i);
}
printf("Displaying %i of %i student(s)\n", i, students.size);
}
[...]
}
I believe that I need to allocate memory for the char * variables of the struct, but I don't know how it should go.
Hope to get some help. Thanks!
you are passing local variable address to createStudent and simply assigning this to internal pointers that's wrong.
you can do is use something like an strdup call as below
student->last = strdup(last);
student->first = strdup(first);
student->course = stddup(course);
or allocate space to last, first and course and copy the string
Your assumption is correct: You assigned pointers to stack objects to your list elements. So the content is likely to be overwritten on the course of further execution of the program, which gives you the weird characters in the output further down the road.
The correct way would be to allocate memory for the strings during createStudent which is done through malloc or calloc of minimum the length of the string. And you already have an example there in your function, so I'm a bit surprised that you stated you don't know how to do that. Another possibility is to call strdup for that purpose which basically does exactly the combination of allocation and string copy.
Oh and one more remark: Please make it a habit from the beginning of your career that you clean up after yourself. Meaning: Whatever you allocate, deallocate it after usage. In your case: If you have a createStudent function, create a destroyStudent function. If you have a linked list somewhere, free it before exitting the program. Picking that habit up early will save you from memory leaks in the future.
Related
createPerson() returns struct, person is a pointer to an array of person
struct pointers, (personNode**). trying to copy the return of
createPerson() to personNode[x], memory error.
people[length - 1]->age = createPerson(name, age)->age;
strcpy(people[length - 1]->name, createPerson(name, age)->name);
typedef struct personNode
{
char name[20];
int age;
struct personNode* next;
}personNode;
personNode* createPerson(char name[], int age)
{
personNode* person = (personNode*)malloc(sizeof(personNode));
strcpy(person->name, name);
person->age = age;
return person;
}
void addPerson(personNode** people, int length)
{
int i = 0;
int age = 0;
char* name = 0;
people = (personNode**)realloc(people, sizeof(personNode*) * length + 1);
name = (char*)realloc(name, 20);
printf("Enter name: ");
fgets(name, 20, stdin);
name[strcspn(name, "\n")] = 0;
printf("Enter age: ");
scanf("%d", &age);
getchar();
people[length - 1]->age = createPerson(name, age)->age;
strcpy(people[length - 1]->name, createPerson(name, age)->name);
Expected non crashing, got crashing.
This question already has answers here:
malloc dynamic array in dynamic array of structs
(3 answers)
how to create array of struct
(3 answers)
Closed 4 years ago.
By using this code I can record only one student information, but what if I want to record thousand or more information of students ?
#include <stdio.h>
#include <string.h>
struct {
char name[10];
int id;
float marks;
char grade;
} s;
int main() {
printf("Name : ");
scanf("%s", s.name);
printf("Id : ");
scanf("%d", &s.id);
printf("Marks : ");
scanf("%f", &s.marks);
printf("Grade : ");
scanf(" %c", &s.grade);
printf("%s %d %.2f %c\n", s.name, s.id, s.marks, s.grade);
}
You can consider using dynamic arrays, if length of students reach max, realloc students
#include <stdio.h>
#include <stdlib.h>
typedef struct student {
const char* name;
int id;
float marks;
char grade;
} student;
typedef struct class {
int len;
int max_alloc_len;
student** students;
} class;
student* newClass() {
struct class* c;
c = malloc(sizeof(c));
c->len = 0;
c->max_alloc_len = 10;
c->students = malloc(sizeof(struct student*) * 10);
return c;
}
student* newStudent(const char* name)
{
struct student* s;
s = malloc(sizeof(s));
s->name = name;
return s;
}
void addStudent(class* c, student* s)
{
c->students[c->len++] = s;
if (c->len >= c->max_alloc_len) {
c->max_alloc_len *= 2;
c->students = realloc(c->students, sizeof(struct student*) * c->max_alloc_len);
}
}
int main() {
int i;
class* c;
student* s;
c = newClass();
for (i = 0; i < 20; i++) {
s = newStudent("jim");
addStudent(c, s);
}
printf("%s", c->students[19]->name);
}
You can create one array of structure and store them like how we store elements into array. See the complete code given below:
#include <stdio.h>
#include <string.h>
#define N 100
struct record{
char name[10];
int id;
float marks;
char grade;
} ;
int main() {
struct record s[N]; // allocate memory for N=100 records
int num_records= 0;
printf("How many records do you wish to store (1- 100): ");
scanf("%d", &num_records);
while (num_records > N)
{
printf("Enter between than (1- 100): ");
scanf("%d", &num_records);
}
for (int i= 0; i < num_records; i++)
{
printf("\n____Enter details for Record %d _____\n",i+1); // now records starts from 1 insted of f0
printf("Name : ");
scanf("%s", s[i].name);
printf("Id : ");
scanf("%d", &s[i].id);
printf("Marks : ");
scanf("%f", &s[i].marks);
printf("Grade : ");
scanf(" %c", &s[i].grade);
}
for (int i= 0; i < num_records; i++)
printf("%s %d %.2f %c\n", s[i].name, s[i].id, s[i].marks, s[i].grade);
}
Hope this helps you.
#include <stdio.h>
#include <stdlib.h>
struct{
char name[10];
int id;
int marks;
char grade;
}s[10];
int main()
{
int i;
for(i=0;i<sizeof(s);i++){
printf("name: ");
scanf("%s",s[i].name);
printf("id: ");
scanf("%d",&s[i].id);
printf("marks: ");
scanf("%d",&s[i].marks);
if(s[i].marks>=90)
s[i].grade='S';
else if(s[i].marks>=80)
s[i].grade='A';
printf("\n%s %d %d %c\n",s[i].name,s[i].id,s[i].marks,s[i].grade);
}
return 0;
}
This way you can add as many records as you want.
If you don't know the number of students at the time of coding this program you can always use linked lists and malloc to allocate memory dynamically although it's not safe especially if you have very limited memory resources for example in embedded systems case.
your code will be
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<conio.h>
struct LinkedList{
char name[10];
int id;
float marks;
char grade;
struct LinkedList *next;
};
typedef struct LinkedList *node; //Define node as a pointer of data type struct LinkedList
node createNode(){
node temp; // declare a node
temp = (node)malloc(sizeof(struct LinkedList)); // allocate memory using malloc()
temp->next = NULL;// make next point to NULL
return temp;//return the new node
}
node addNode(node head,char* name, int id, float marks, char grade){
node temp,p;// declare two nodes temp and p
temp = createNode();//createNode will return a new node with data = value and next pointing to NULL.
strncpy(temp->name, name, 10); // add element's data part of node
temp->id = id; // add element's data part of node
temp->marks = marks; // add element's data part of node
temp->grade = grade; // add element's data part of node
if(head == NULL){
head = temp; //when linked list is empty
}
else{
p = head;//assign head to p
while(p->next != NULL){
p = p->next;//traverse the list until p is the last node.The last node always points to NULL.
}
p->next = temp;//Point the previous last node to the new node created.
}
return head;
}
char i, x;
node head; // declare The head
char name[10];
int id;
float marks;
char grade;
int main() {
printf("If you want to quit press q ,to continue press anything else");
i = getch();
while(i !='q'){
printf("\n Name : ");
fgets(name, 10, stdin);
printf("\n Id : ");
scanf("%d", &id);
printf("\n Marks : ");
scanf("%f", &marks);
printf("\n Grade : ");
scanf(" %c", &grade);
printf("\n name: %s id: %d marks: %.2f grade: %c\n", name, id, marks, grade);
addNode(head, name, id, marks, grade);
x = 'y';
do{
printf("\n If you want to quit press q ,to continue press anything else");
i = getch();
if(i=='q'){
printf("\n Are you sure you want to quit?");
printf("\n press y: for yes anything else: for NO");
x = getch();
}
}while(x !='y');
}
return 0;
}
Whenever I attempt to scan in my input, example: JASON BOURNE JULY 5 1972, the program crashes.
scanf("%s %s %s %d %d", temp->fname, temp->lname, temp->month, temp->day, temp->year);
I determined it has to do with the %d's whereas if I put:
scanf("%s %s %s", temp->fname, temp->lname, temp->month);
scanf("%d %d", temp->month, temp->day);
The String values are correct and the program crashed before int's could be assigned.
Here's a copy of my struct:
typedef struct node{
char fname [29];
char lname [29];
char month [9];
int day;
int year;
struct student * next;
struct student * previous;
} student;
and here is a copy of my function in main():
student * head = malloc(sizeof(student));
student * temp = head;
int num = numStudents;
while(num != 0){
scanf("%s %s %s %d %d", temp->fname, temp->lname, temp->month, temp->day, temp->year);
printf("FUNCTION NEVER REACHES THIS POINT");
temp = temp->next = malloc(sizeof(student));
num--;
}temp->next = NULL;
Here's what I did to get everything to work if anyone is interested:
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
//Struct for Student
struct student{
char fname [29];
char lname [29];
char month [9];
int day;
int year;
struct student *next;
struct student *previous;
};
//Pre-Call
void printList(struct student *node);
struct student * insertNode(struct student * list, char fname[29], char lname[29], char month[9], int day, int year);
//Main function
int main(){
//Take Input and Assign Variables
int classes, i;
scanf("%d", &classes);
for(i = 0; i < classes; i++){
int numStudents, j;
scanf("%d", &numStudents);
struct student *list = NULL; //Create LL
int num = numStudents, day, year;
char fname[29]; char lname[29]; char month[9];
//Assign Values
while(num != 0){
scanf("%s %s %s %d %d", &fname, &lname, &month, &day, &year);
list = insertNode(list, fname, lname, month, day, year);
num--;
}
//
printList(list);
}
return 0;
}
//Function to insert a node to the LL
struct student * insertNode(struct student * list, char fname[29], char lname[29], char month[9], int day, int year){
//If the list is empty
if(list == NULL){
struct student * tempNode = (struct student *) malloc(sizeof(struct student));
strcpy(tempNode->fname,fname);
strcpy(tempNode->lname,lname);
strcpy(tempNode->month,month);
tempNode->day = day;
tempNode->year = year;
tempNode->next = NULL; // Extremely Important
return tempNode;
}
//If the list has a node
list->next = insertNode(list->next, fname, lname, month, day, year);
return list;
}
//Function to print a LL
void printList(struct student * node){
if(node->next == NULL)
printf("%s %s %s %d %d\n", node->fname, node->lname, node->month, node->day, node->year);
else
{
printf("%s %s %s %d %d\n", node->fname, node->lname, node->month, node->day, node->year);
printList(node->next);
}
}
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct student{
char firstname[20];
char lastname[20];
double grade;
char zipcode[10];
struct student *next;
};
void display(struct student *first)
{
while (first != NULL)
{
printf("\nFirst name: %s", first->firstname);
printf("\tLast name: %s", first->lastname);
printf("\tGrade: %.2f", first->grade);
printf("\t ZipCode: %s", first->zipcode);
first = first->next;
}
}
/*void add_Record(struct student *first)
{
char r[20];
struct student *t;
t = first;
while (t != NULL)
{
if (t == NULL)
{
first = (struct student*)malloc(sizeof(struct student));
printf("\nEnter the first name of the student:");
scanf("%s", first->firstname);
printf("\nEnter the last name of the student:");
scanf("%s", first->lastname);
printf("\nEnter the score of the student:");
scanf("%lf", &first->grade);
printf("\nEnter the zipcode of the student:");
scanf("%s", first->zipcode);
}
}
}
void del()
{
struct student *back, *t, *k;
char r[10];
int flag = 0;
printf("\nEnter the last name of student you want to delete:");
scanf("%s", r);
if (strcmpi(r, first->lastname) == 0)
{
first = first->next;
flag = 1;
}
else
{
back = first;
k = first->next;
while (k != NULL)
{
if (strcmpi(r, k->lastname) == 0)
{
back->next = k->next;
flag = 1;
break;
}
}
}
if (flag == 0)
printf("\nThe element not found!!!");
}
*/
void search(struct student *first)
{
char r[10];
int flag = 0;
printf("\nEnter the zipcode you want to search:");
scanf("%s", r);
struct student *t;
t = first;
while (t != NULL)
{
if (strcmp(r, t->zipcode) == 0)
{
printf("\nFirst name: %s", t->firstname);
printf("\tLast name: %s", t->lastname);
printf("\tGrade: %.2f", t->grade);
printf("\t ZipCode: %s", t->zipcode);
flag = 1;
break;
}t = t->next;
}
if (flag == 0)
printf("\nThe zipcode not in database!!");
}
void sort(struct student *first)
{
struct student *temp;
temp = NULL;
while (first != NULL)
{
if (first-> grade > first->next->grade)
{
strcpy(temp->firstname, first->firstname);
strcpy(temp->lastname, first->lastname);
temp->grade = first->grade;
strcpy(temp->zipcode, first->zipcode);
strcpy(first->firstname, first->next->firstname);
strcpy(first->lastname, first->next->lastname);
first->grade = first->next->grade;
strcpy(first->zipcode, first->next->zipcode);
strcpy(first->next->firstname, temp->firstname);
strcpy(first->next->lastname, temp->lastname);
first->next->grade = temp->grade;
strcpy(first->next->zipcode, temp->zipcode);
break;
}
}
printf("\nThe sorted record by score are: \n");
display(first);
}
int main(void)
{
struct student *first = NULL, *last = NULL;
struct student *temp;
int n;
printf("\nEnter the number of student:");
scanf("%d", &n);
int i;
for (i = 0; i < n; i++)
{
temp = (struct student*)malloc(sizeof(struct student));
printf("\nEnter the first name of the student:");
scanf("%s", temp->firstname);
printf("\nEnter the last name of the student:");
scanf("%s", temp->lastname);
printf("\nEnter the grade of the student:");
scanf("%lf", &temp->grade);
printf("\nEnter the zipcode of the student:");
scanf("%s", temp->zipcode);
temp->next = first;
first = temp;
}
int o;
o = 1;
while (o != 0)
{
printf("\nMENU\n");
printf("\nEnter 1 for displaying database.");
printf("\nEnter 2 for inserting an record.");
printf("\nEnter 3 for deleting a record by lastname.");
printf("\nEnter 4 for searching a record by zipcode.");
printf("\nEnter 5 for sorting record by score.");
printf("\nEnter 0 for exit!");
printf("\nEnter the choice:");
scanf("%d", &o);
switch (o)
{
case 1:display(first); break;
/*case 2:insertafter(*first); break;
case 3:del(); break;*/
case 4:search(first); break;
case 5: sort(first); break;
case 0:exit(0); break;
default:printf("\nYou have entered a wrong choice!!!");
}
}
}
The problem is that how do i sort the scores by score. My code seems right but doesn't work. I made a temp structure and tried to swap values but it doesn't work. Am i doing the loop wrong? Or all my code is wrong?
Here are two answers to the problem
First one sorts the nodes in the node linked list by bubble sorting them, rearranging the linked list
Second one walks the linked list, copies a pointer to each one into an array and then sorts the array by using the struct grade members, the linked list remains unchanged
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#define SWAP(T,x,y) {T *p = &(x); T *q = &(y); T z = *p; *p = *q; *q = z;}
struct student{
char firstname[20];
char lastname[20];
double grade;
char zipcode[10];
struct student *next;
};
struct student *head=NULL;
void add(char *f, char *s, double score) {
struct student *a;
a=(struct student*)malloc(sizeof(struct student));
strcpy(a->firstname,f);
strcpy(a->lastname,s);
a->grade = score;
a->next = head;
head = a;
}
void printout(char *label) {
struct student *node;
printf("%s\n",label);
for(node=head; node !=NULL; node=node->next) {
printf("%s %s %f\n", node->firstname, node->lastname, node->grade);
}
}
int main(int argc, char ** argv){
int mark=8;
struct student *walk, *prev;
add("Bob","Smith",10);
add("Eric","Von Däniken",90);
add("Morris","Minor",91);
add("Master","Bates",9);
add("Zoe","Bodkin",20);
add("Mary","Pippin",30);
/* bubble sort */
printout("before");
prev=head;
while(mark) {
mark=0;
for(walk=head;
walk != NULL;
walk=walk->next) {
if (walk->next && walk->grade > walk->next->grade) {
/* printf("swapping %s %s\n", walk->firstname, walk->next->firstname); */
mark=1;
if (walk == head) {
struct student *v2=walk->next;
struct student *v3=walk->next->next;
SWAP(struct student *, v3->next, v2->next);
SWAP(struct student *, head, v3->next);
walk = v3;
} else {
struct student *v1=prev;
struct student *v2=walk;
struct student *v3=walk->next;
SWAP(struct student *, v3->next, v2->next);
SWAP(struct student *, v1->next, v3->next);
walk = v3;
}
}
prev=walk;
}
}
printout("after");
return 0;
}
second version, uses qsort, retains linked list order
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
struct student{
char firstname[20];
char lastname[20];
double grade;
char zipcode[10];
struct student *next;
};
struct student *head=NULL;
size_t nodecount=0;
void add(char *f, char *s, double score) {
struct student *a;
a=(struct student*)malloc(sizeof(struct student));
strcpy(a->firstname,f);
strcpy(a->lastname,s);
a->grade = score;
a->next = head;
head = a;
nodecount++;
}
static int cmpgrade(const void *p1, const void *p2) {
struct student *g1, *g2;
g1=*(struct student **)p1;
g2=*(struct student **)p2;
return g1->grade > g2->grade;
}
int main(int argc, char ** argv){
int i;
struct student *walk,**sa, **sap;
add("Bob","Smith",10);
add("Eric","Von Däniken",90);
add("Morris","Minor",91);
add("Master","Bates",9);
add("Zoe","Bodkin",20);
add("Mary","Pippin",30);
/*copy into array of pointers*/
sa=calloc(sizeof (struct student*), nodecount);
sap=sa;
for(walk=head; walk != NULL; walk=walk->next) {
*sap = walk;
sap++;
}
printf("before\n");
for (i=0; i< nodecount; i++) {
printf("%s %s %f\n", sa[i]->firstname, sa[i]->lastname, sa[i]->grade);
}
/* qsort */
qsort(sa, nodecount, sizeof (struct student *), cmpgrade);
printf("after\n");
for (i=0; i< nodecount; i++) {
printf("%s %s %f\n", sa[i]->firstname, sa[i]->lastname, sa[i]->grade);
}
return 0;
}
I am trying to do linked list of persons in c.
All my methods work in main() until I put them into while loop (for reading commands from user). Everything compiles, but when I try to run it, it crashes returning random values.
Here are parts of my code.
Structure:
struct Person{
const char* name;
const char* sex;
int age;
struct Person* next;
} *head;
Method insert:
void insert(struct Person* h, char*n, char* s, int a){
for(; h->next != NULL; h=h->next){}
struct Person* p = (struct Person*) malloc(sizeof(struct Person));
p->name=n;
p->age=a;
p->sex=s;
p->next=NULL;
h->next=p;
}
and main in which it doesn't work:
int main()
{
struct Person Maciek={"Maciek", "Male", 20, NULL};
head = &Maciek;
int comand = 0;
while(comand != 6){
printf("Choose command:\n 1-insert person \n 2-delete by index \n 3-delete by name \n 4-display by index \n 5-print whole list \n 6-exit\n");
scanf("%d", &comand);
if(comand == 1){
printf("Name, Gender, Age\n");
char* name;
char* sex;
int age;
scanf("%s, %s, %d", &name, &sex, &age);
printf("Name %s, Sex %s, Age %d", name, sex, age);
insert(head, name, sex, age);
}
if(comand == 2){
printf("2\n");
}
if(comand == 3){
printf("3\n");
}
if(comand == 4){
printf("4\n");
}
if(comand == 5){
printf("5\n");
}
}
return 0;
}
I am quite new to C/C++, and I would really appreciate any help.
if(comand == 1){
printf("Name, Gender, Age\n");
char* name;
char* sex;
int age;
scanf("%s, %s, %d", &name, &sex, &age);
Here you are using dangling pointers (which are pointing anywhere in memory), you should use malloc to allocate some memory or use char arrays, and as Carl Norum pointed out you shouldn't have & in your scanf call as you need to provide some char* and not char**. You can do it like this (this code is vulnerable to buffer overflow, don't use that in production code, consider using fgets+sscanf):
char name[50];
char sex[20];
int age = 0;
scanf("%s, %s, %d", name, sex, &age);
In your insert function:
struct Person* p = (struct Person*) malloc(sizeof(struct Person));
p->name=n;
p->age=a;
p->sex=s;
You are replacing p->name with n, instead of copying the content of n into p->name. You want:
struct Person *p = malloc(sizeof(struct Person));
p->name = malloc(strlen(n)+1);
if(p->name == NULL) {
//error handling...
}
strcpy(p->name, n);
p->sex = malloc(strlen(s)+1);
if(p->sex == NULL) {
//error handling...
}
strcpy(p->sex, s);
p->age = a;
You're reading strings into pointers that have not been initialized with allocated memory.