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!
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 😊
In the code below I tried to use printf and scanf to get data from user and store them inside a struct i defined called node.
The programme works fine for the first prompt, but as soon as the user input name, the programme ends with printing Age:salary:
Can anyone help me with this?
On a side note, can anyone also help me to understand how to create a loop to store data in various nodes and store them together? (Not hard-code it one by one)
Thank you very much!!
typedef struct node
{
char *name;
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
Use a char[] for name,
for example:
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
If you want to get several users, loop for ever and ask if the user wants to add more data.
I have create a function to print the list
Console:
Name:Foo
Age:12
salary:12
Continue Y/N
Y
Name:Bar
Age:14
salary:14
Continue Y/N
Y
Name:John
Age:30
salary:45
Continue Y/N
N
John, 30, 45
Bar, 14, 14
Foo, 12, 12
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
static void printList(node *n)
{
while (n) {
printf("%s, %d, %d\n", n->name, n->age, n->salary);
n = n->next;
}
}
static node *get_nodes(void) {
node *list = NULL;
while (42) {
char c;
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = list;
list = tmp;
printf("Continue Y/N\n");
scanf(" %c", &c);
if (c == 'N')
break;
}
return list;
}
static void clearList(node *node) {
if (node->next) {
clearList(node->next);
}
free(node);
}
int main(void)
{
node *list = get_nodes();
printList(list);
clearList(list);
return 0;
}
You are trying to write to Uninitialized memory
This is a very common problem beginners face.
You are trying to store the name using char *name declaration.
Here name does not point to a valid memory location, that's why You program is not running as expected.
Even if name points to a valid memory address, you must have enough memory allocated to store the data.
You can use
#define BUFFER_SIZE 50
char name[BUFFER_SIZE];
You can use any buffer size as you like, and then store a string of that length - 1 in the name array. -1 is for the null termination character \0.
Using this declaration you are allocating memory of BUFFER_SIZE bytes and the name points to the first byte in that array.
This allocation happens on the stack not in the HEAP
For fix your bug, you should allocate memory of your char *.
First Way, when you create your struct.
typedef struct node
{
char name[200]; // You specify that your char * can save 200 char
int age;
int salary;
struct node * next;
}node;
or you can create init struct function
node *init_node()
{
node *test = null;
test->name = malloc(sizeof(char) * 200);
test->age = 0;
test->salary = 0;
test->node = null;
return test
}
I am writing a program that will let user add or delete the car from inventory.Right now,
I am trying to get user to choose a car name instead of explicitly stating name and I created a struct CriteriaSelector in which array name companyList will store value of companies and when I let user choose car name it will copy a string from companyList at a particular index into the char array called carname which will then be copied into carname char array in the CarData object.
The thing is whenever I compile the below code, I get the error saying expected specifier qualifier list before 'companyList' at line 27 and I don't know what to do?
Can anybody help?
#include <stdio.h>
#include <stdlib.h>
#define MAX_WORD_LENGTH 20
typedef struct cardata{
char carname[MAX_WORD_LENGTH];
char carmodel[MAX_WORD_LENGTH];
char caryear[MAX_WORD_LENGTH];
char cartype[MAX_WORD_LENGTH];
int quantity;
}CarData;
struct node{
CarData data;
struct node *next;
struct node *prev;
}*start=NULL;
typedef struct criteriaselector{
const char *companyList[10];
companyList[0] = "Toyota"; <-- This is where error is happening!!(Line 27)
companyList[1] = "Honda";
companyList[2] = "Hyundai";
companyList[3] = "Nissan";
companyList[4] = "Mitsubishi";
companyList[5] = "Volksvagon";
companyList[6] = "Acura";
companyList[7] = "Ford";
companyList[8] = "Dodge"
companyList[9] = "GMC";
}CriteriaSelector;
void insert_first(){
struct node *ptr;
CriteriaSelector criteriaselector;
char carname[MAX_WORD_LENGTH];
char carmodel[MAX_WORD_LENGTH];
char caryear[MAX_WORD_LENGTH];
char cartype[MAX_WORD_LENGTH];
int carQuantity;
int ch;
printf("\nChoose your car");
printf("\n\n\n1.Toyota \n2.Honda \n3.Hyundai \n4.Nissan \n5. Mitsubishi \n6. Volksvagon \n7. Acura \n8. Ford \n9. Dodge \n10. GNC Exit\n");
scanf("%d", &ch);
strcpy(carname,criteriaselector.companyList[ch-1]);
printf("\n\nEnter the car model: ");
scanf("%s", carmodel);
printf("\n\nEnter the car year: ");
scanf("%s", caryear);
printf("\n\nEnter the car type: ");
scanf("%s", cartype);
printf("\n\nEnter the quantity of models: ");
scanf("%d", &carQuantity);
if(start==NULL){
start=(struct node *)malloc(sizeof(struct node));
strcpy(start->data.carname,carname);
strcpy(start->data.carmodel,carmodel);
strcpy(start->data.caryear,caryear);
strcpy(start->data.cartype,cartype);
start->data.quantity=carQuantity;
start->prev=NULL;
start->next=NULL;
}else{
ptr=start;
start=(struct node *)malloc(sizeof(struct node));
strcpy(start->data.carname,carname);
strcpy(start->data.carmodel,carmodel);
strcpy(start->data.caryear,caryear);
strcpy(start->data.cartype,cartype);
start->data.quantity=carQuantity;
start->next=ptr;
}
}
void delete_first(){
struct node *ptr;
char carname[MAX_WORD_LENGTH];
char carmodel[MAX_WORD_LENGTH];
char caryear[MAX_WORD_LENGTH];
char cartype[MAX_WORD_LENGTH];
char modelNumber[MAX_WORD_LENGTH];
int carQuantity;
if(start==NULL){
printf("\n\nLinked list is empty.\n");
}else{
ptr=start;
printf("\nThe car for which the entry is removed is %s \n",ptr->data.carname);
strcpy(start->data.carname,carname);
strcpy(start->data.carmodel,carmodel);
strcpy(start->data.caryear,caryear);
strcpy(start->data.cartype,cartype);
start->data.quantity=carQuantity;
start=start->next;
free(ptr);
}
}
void display()
{
struct node *ptr=start;
int i=1;
if(ptr == NULL){
printf("\nLinklist is empty.\n");
}else{
printf("\nSr. No Make Model Year Type Quantity\n");
while(ptr != NULL){
printf("\n%d.\t%s %s %s %s %d\n", i,ptr->data.carname,ptr->data.carmodel,ptr->data.caryear,ptr->data.cartype,ptr->data.quantity);
ptr = ptr->next;
i++;
}
}
}
int main(void)
{
int ch;
do
{
printf("\n\n\n1. Insert \n2. Delete \n3. Display \n4. Exit\n");
printf("\nEnter your choice: ");
scanf("%d", &ch);
switch(ch)
{
case 1:
insert_first();
break;
case 2:
delete_first();
break;
case 3:
display();
break;
case 4:
exit(0);
default:
printf("\n\nInvalid choice. Please try again. \n");
}
} while(1);
return EXIT_SUCCESS;
}
You can't mix definitions of a struct with initialisation.
typedef struct criteriaselector{
const char *companyList[10];
companyList[0] = "Toyota"; // This bit needs to be elsewhere.
Instead, after you declare an instance of the struct, you'll then need to fill in the values. For example:
typedef struct criteriaselector{
const char *companyList[10];
}
.....
void some_function() {
CriteriaSelector criteriaselector;
criteriaselector.companyList[0] = "Toyota"
.... etc
However, it looks like you were intending to make a constant, rather than describe a structure. Instead of the whole struct definition, you can do:
const char *criteriaselector[10] = {"Toyota", "Honda" ... }
somewhere in global scope. This will declare a "global" array of constant strings.
As an aside, there's a little subtlety with the way that const works here. This declaration says "define an array of pointers to constant chars". This means that you can't change the strings themselves, but you can change the pointers. So, you can't do:
criteriaselector[1][0] = '\0' // changing a character inside a const string
But, you can do:
criteriaselector[1] = "some other string".
This probably isn't what you meant. Instead, we can say "define an array of constant pointers to constant strings", like this:
const char * const criteriaselector[10] = {"Toyota", "Honda" ... }
That way, you won't be able to change the contents of the string, or which strings are pointed to.
The comments on that question that I linked explain this in a bit more detail.
You cannot initialize variables inside a structure. This is because a struct defines a type and not a variable. You can initialize a structure members outside the structure definition using a structure variable (criteriaselector in your case) and .or -> access specifiers.
For eg.,
criteriaselector.companyList[0] = "Ford";
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.
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.