I am currently learning C and trying to create an app that allows students to input their name, address, student id and any subject id they have while at university (yes this is a task part of foundations of tech course). Basically the following code tries to create an array of students (that is unlimited in size) by using dynamic allocating memory. Further a student can have unlimited amounts of subjects (that is nested within the student subject and is dynamically allocated)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
typedef struct {
char subjectID[10];
char subjectName[10];
float grades;
}subject;
typedef struct {
char name[10];
int id;
struct subject *enrol;
char address[100];
int status;
int totalSubject;
}student; // This structure is to act like an unlimited list of students
int option=0, q=0, j=0, k=0, p=0, delete=0, position=0;
int count=0; // keeps the count of numbers added
student * studentAddress;
studentAddress = NULL; //Init structure
studentAddress->enrol = NULL; // Init nested structure
int flag = 0; //variable to indicate whether the number to delete is found or not
while (1) // Life cycle of the app
{
printf("1 - Add new student\n");
printf("2 - Display all students\n");
printf("3 - Delete student by id \n");
printf("4 - Delete student by name \n");
printf("5 - Quit\n");
scanf("%d",&option);
switch (option)
{
case 1: studentAddress = realloc(studentAddress, sizeof(student)*(count+1)); //using realloc memory is requested for the new number
printf("Enter your name\n");
fflush(stdin);
gets(studentAddress[count].name);
fflush(stdin);
printf("Enter your id\n");
scanf("%d", &studentAddress[count].id);
printf("Enter your address\n");
fflush(stdin);
gets(studentAddress[count].address);
fflush(stdin);
int subjectCounter = 0;
subjectCounter = 0;
char subjectContinue[10];
for (p = 0; p < subjectCounter; p++)
{
studentAddress[count].enrol = (struct subject *)realloc(studentAddress[count].enrol, (sizeof(subject)*(subjectCounter+1)));
// studentAddress[count].enrol[subjectCounter] = (struct subject *)realloc(sizeof(subject)*(subjectCounter+1));
// Above is teacher paste
printf("What is the id of your subject %d\n", (subjectCounter+1));
fflush(stdin);
gets(studentAddress[count].enrol[subjectCounter].subjectID);
fflush(stdin);
printf("Would you like to add another subject id\n");
fflush(stdin);
gets(subjectContinue);
fflush(stdin);
if (strcmp(subjectContinue, "Y") == 0)
{
subjectCounter++;
}
studentAddress[count].totalSubject = subjectCounter;
}
count++;
printf("\n");
break;
case 2:
for (j=0; j<count; j++)
{
if(studentAddress[j].status != 0)
printf("%s\n %d\n %s\n", studentAddress[j].name, studentAddress[j].id, studentAddress[j].address);
for (q = 0; q < studentAddress[count].totalSubject; q++)
{
printf("%s", studentAddress[j].enrol[q].subjectID);
}
}
printf("\n");
break;
case 3: k=count;
flag=0;
printf("Type the id of the person record you want to delete\n");
scanf("%d", &delete);
for (j=0; j < count; j++)
{
if (delete == studentAddress[j].id)
{
strcpy(studentAddress[j].name, " ");
strcpy(studentAddress[j].address, " ");
studentAddress[j].id = 0;
studentAddress[j].status = 0;
flag = 1;
}
}
if(flag==0)
printf("id not in the list ...\n");
else
printf("Deletion successful ...\n");
printf("\n");
break;
case 4:
flag=0;
char deletChar[100];
printf("Type the name of the person record you want to delete\n");
fflush(stdin);
gets(deletChar);
fflush(stdin);
for (j=0; j < count; j++)
{
if (strcmp(deletChar, studentAddress[j].name)==0)
{
flag = 1;
strcpy(studentAddress[j].name, " ");
strcpy(studentAddress[j].address, " ");
studentAddress[j].id = 0;
studentAddress[j].status = 0;
flag = 1;
}
}
if(flag==0)
printf("name not in the list ...\n");
else
printf("Deletion successful ...\n");
printf("\n");
break;
return 0;
case 5:
return 0;
}
}
return 0;
}
I try running this code and get the error on line 68 and similar on line 95
subscript of pointer to incomplete type 'struct subject'
gets(studentAddress[count].enrol[subjectCounter].subjectID);
plus I get this note (from the compiler) below the error
forward declaration of 'struct subject' struct subject *enrol;
My tutor and lecture have both tried helping me, but they have had no success. They are like most of my code looks correct, but it will not work. Sorry I am new to stack overflow so if you want me to add more information please let me know.
The easiest way to solve this is to create a function.
struct student* allocate_student() {
struct subject* new_subject = allocate_subject();
struct student* new_struct = malloc(sizeof(struct student));
// initialize all fields, which will eventually include
new_struct->enrol = new_subject;
return new_struct;
}
This code fails to check for any error conditions. You should add that. In addition, allocate_subject() is also not defined. Considering the offered example, odds are good you can figure out how to write allocate_subject().
If you add in parameters, allocate_student() might be a bad method name. With enough parameters to construct any student, you might want to call it construct_student(...)
Related
I'm incredibly new to this and have a school assignment I have to write a gradebook program that uses a custom struct to hold student IDs and grades. I have been trying unsuccessfully for days to figure out why it will not print properly, or when it does print (after a lot of shifting things around) it only prints the second set of input.
The gradebook.h section is the custom structure.
// gradebook.h
struct gradeID
{
int id;
char grades[25];
};
// Gradebook.h is a header file to define
// a global structure.
#include "gradebook.h"
#include <stdio.h>
#include <stdlib.h>
void sort(struct gradeID *, int);
int main(void)
{
// Variables and structure definitions
int ctr;
char contInput;
int i;
struct gradeID grade;
struct gradeID *identifier;
int *temps;
// Allocates 10 integers worth of memory for the program to use.
// If there is not enough memory, the program will print an error
// statement and terminate the program.
temps = (int *) malloc(10 * sizeof(int));
if (temps == 0)
{
printf("Not enough memory!\n");
exit(1);
}
// Prints basic instructions for the program
printf("\t\tGradebook Recorder\n");
printf("Input student IDs and grades.\n");
printf("These will be sorted by ID and printed.\n");
/* Creates a for loop that will continue until the program
hits the designated number of array elements. For the sake
of expediency, I have set this amount to 10, but it can be
changed as necessary.*/
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
printf("Grades Sorted by Student ID:\n\n");
printf("\tStudent ID: Student Grade: \n");
for(i = 0; i < ctr; i++)
{
printf("\t%d", grade.id );
printf("\t%s", grade.grades);
}
identifier[i] = grade;
return(0);
free(temps);
}
void sort(struct gradeID identifier[], int counter)
{
int inner;
int outer;
struct gradeID temp;
// Loops for sorting
for(outer = 0; outer < counter - 1; ++outer)
{
for(inner = outer + 1; inner < counter; ++inner)
{
if(identifier[inner].id < identifier[outer].id)
{
temp = identifier[inner];
identifier[inner] = identifier[outer];
identifier[outer] = temp;
}
}
}
return;
}
The pointer identifier is uninitialized
struct gradeID *identifier;
So this statement
identifier[i] = grade;
independent on the value of i invokes undefined behavior.
In this for loop
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
you are entering new data in the same object grade of the structure type. So the new data overrides the previous data stored in the object.
Moreover the variable ctr was not initialized
int ctr;
So this statement in the above for loop
ctr++;
also invokes undefined behavior.
The variable temps that points to a dynamically allocated array
temps = (int *) malloc(10 * sizeof(int));
is not used.
This statement
free(temps);
never gets the control because before it there is the return statement
return(0);
free(temps);
What you need is to define an array of the type struct gradeID as for example
struct gradeID grades[10];
and fill it with values.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm using nested structures and dynamic memory allocation and I'm having problems.
I'm using the following input:
Member ID: 1
Member Name: A
Policy Number: 1
Policy ID: P1
Policy Type: 1
Policy Premium: 100
However, I'm not able to enter anything else after I enter P1. The program terminates.
The other issue I'm having, is that when I select option 2, which is supposed to print all members, it doesn't display correctly.
Even before entering any member details, if I choose option 2, it displays the following:
Member ID: 0
Member Name:
I'm wondering if when creating the dynamic array, I've made a mistake, and it's actually printing member[0].
After adding members to the array, then choosing option 2, it prints:
Member ID: 1
Member Name: A
Policy ID: (null)
Policy Type: Premium: $100
It prints the member details, but when it comes to accessing the policy for that member, those details don't print, and it completely skips over the
policy type.
Full code below:
#include <malloc.h>
#include <stdio.h>
enum enumtype { Car, Health, Travel, Pet };
typedef struct policy {
char id[4];
enum enumtype type;
int premium;
}pol;
typedef struct member {
int id;
char name[30];
int polnum;
pol *policy;
}mem;
mem getmember() {
mem member;
int i, j;
printf("\n\nEnter member's details");
printf("\nMember ID: ");
scanf("%d", &member.id);
printf("Member Name: ");
scanf(" %s", member.name);
printf("Requested number of policies: ");
scanf("%d", &member.polnum);
if (member.polnum > 0) {
printf("\nEnter policy details for %s", member.name);
for (i = 0; i < member.polnum; i++) {
printf("\nEnter details for policy %d", i + 1);
printf("\nEnter Policy ID: ");
scanf(" %s", member.policy->id);
printf("\nEnter Policy Type:");
printf("\n1 - Car");
printf("\n2 - Health");
printf("\n3 - Travel");
printf("\n4 - Pet");
printf("\n\nEnter an option: ");
scanf("%d", &member.policy[i].type);
while (member.policy[i].type < 1 || member.policy[i].type > 4) {
printf("\nInvalid policy type");
printf("\nPlease enter a number from 1 - 4: ");
scanf("%d", &member.policy[i].type);
}
printf("\nEnter Premium: $");
scanf("%d", &member.policy[i].premium);
while (member.policy[i].premium < 0) {
printf("Invalid premium");
printf("\nPremium must be a positive value");
printf("\nEnter Premium: $");
scanf("%d", &member.policy[i].premium);
}
}
}
else
member.policy = NULL;
return member;
}
void printmember(mem* member, int memNum) {
int i, j;
for (i = 1; i = memNum+1; i++) { // This still doesn't print properly but I don't know why
//printf("\nDetails for Member %d", i + 1);
printf("\n\nMember ID: %d", member[i].id);
printf("\nMember Name: %s", member[i].name);
for (j = 0; j < member[i].polnum; j++) {
printf("\nPolicy ID: %s", member[i].policy[j].id);
printf("\nPolicy Type: ", member[i].policy[j].type);
switch (member[i].policy[j].type) {
case 1:
printf("Car");
break;
case 2:
printf("Health");
break;
case 3:
printf("Travel");
break;
case 4:
printf("Pet");
break;
}
printf("Premium: $%d", member[i].policy[j].premium);
}
}
}
int main()
{
int choice = 0;
int memNum = 0;
char name[30];
mem* member = NULL;
member = (mem*)realloc(member, (memNum++) * sizeof(member));
while (choice != 3) {
choice = 0;
printf("\n\t Menu");
printf("\n-----------------------------");
printf("\n1 - Add new member");
printf("\n2 - Display all members");
printf("\n3 - Exit");
printf("\n\nEnter an option: ");
scanf("%d", &choice);
switch (choice) {
case 1:
member = (mem*)realloc(member, (memNum + 1) * sizeof(member));
member[memNum++] = getmember();
break;
case 2:
printf("\n\nDisplaying all members");
printmember(member, memNum);
break;
case 3:
return 0;
}
}
}
typedef struct member {
int id;
char name[30];
int polnum;
struct policy {
char id[4];
enum enumtype type;
int premium;
}pol;
}mem;
You can have n members and each member can have polnum policies, but that's not what this struct says. This struct says each member has one policy that is represented by a nested structure. Your outer realloc keeping members in an array constrains the solution space. We can't actually do that and use a stretchy structure at the same time, so I don't have to get into how. We just do this the way you already know how.
typedef struct struct policy {
char id[4];
enum enumtype type;
int premium;
} pol;
typedef struct member {
int id;
char name[30];
int polnum;
pol *policies;
}mem;
Adding policies is like so:
if (member.polnum > 0) {
member.pol = malloc(member.polnum * sizeof(pol));
printf("\nEnter policy details for %s", member.name);
for (i = 0; i < member.polnum; i++) {
//...
scanf("%d", &member.pol[i].type);
//...
}
} else {
member.pol = NULL; // When you go to write the free memory code you will thank me
}
In print member, we have a very similar construct:
for (j = 0; j < member[i].polnum; j++) {
printf("\nPolicy ID: %s", member[i].pol[j].type);
Administrative note: code was removed from question after answer posted.
I have this task/function to determine if student's name/complete name already exist in the record.
No student's name should be the same in every input/entry. also no duplicate of entry in record.
The Error of my code:
Is that when I input 5 student names (e.g : A,B,C,D,E) then and search for D the return value will be not found. So I wonder what would be the correct logic for it to search every element if it exist? And when I tried A it says "Already Exist".
#include<stdio.h>
#include<string.h>
int main(){
char studentNames[50][50],names[50][50];
int i,studentcount;
printf("\nEnter number of students: ");
scanf("%d",&studentcount);
for(int i=0; i<studentcount; i++){
printf("\n[Student %d of %d]\n",i+1,studentcount);
printf("Enter name of student %d: \n",i+1);
scanf("%s", studentNames[i]);
}//this is the student record initialize.
/*assumed this is a function where it holds the data name to be searched
e.g
names[i]= "spiderman" then in studentNames[i]="venom",studentNames[i]="harley",studentNames[i]="octopops",
if i loop will it function like this?
the names[i]=spiderman compare to studentnames[i]=venom then if not equal iterate to harley and so on.
That's what I really want to do with my searching but I really dont know how to do it because of my poor logic thinking.
*/
for(int i=0; i<studentcount; i++){
printf("\nEnter Student's Name to be search: ");
scanf("%s",names[i]);
if (strcmp(studentNames[i],names[i]) == 0)
{
printf("Already exist.\n");
return 0;
}
printf("Not found\n");
return 1;
}
}
You probably want something like this:
char CompareStudent() {
printf("\nEnter Student's Name to be search: ");
char searchedname[100];
scanf("%99s", searchedname); // %99s instead of %s prevents buffer overflow
// (not very important at your level)
for (int i = 0; i < studentCount; i++) {
if (strcmp(studentNames[i], searchedname) == 0) {
printf("Already exists.\n");
return 0;
}
}
printf("Not found\n");
return 1;
}
This is your original bogous code with comments:
char CompareStudent() {
printf("\nEnter Student's Name to be search: ");
for (int i = 0; i < studentCount; i++) {
scanf("%s", names[i]); // 1
if (strcmp(studentNames[i], names[i]) == 0)
{
printf("Already exist.\n");
return 0;
}
printf("Not found\n"); // 2
return 1;
}
}
Problems:
You need to ask to input the student to search only once, not each time in the loop
This part must be outside the loop. In your code, we return inconditionally 1 if the student is not in the first element of the array.
First off Ill show you how I'm defining struct StudentRecord
typedef struct{
char SN[10];
char lname[20];
float GPA;
}StudentRecord;
Now the point of this is to read in information from a .dat file which this program does successfully but when I go to save the array that I have made (more on this below) it give me a very weird output this code has a 2 global variables
StudentRecord* studentRecordList;
int studentRecordSize;
the studentRecordSize is going to be the first input line from the file, the function for reading the files looks like the following.
void load_records(){
FILE* student_file = fopen("StudentRecordFile.dat", "r");
if(student_file == 0){
perror("cannot open StudentRecordFile.dat in load_records");
}
//free existing student list
if(studentRecordList != 0){
free(studentRecordList);
}
//get number of students in the list
fscanf(student_file, "%d",&studentRecordSize);
//create and load new student list
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
for(i = 0; i < studentRecordSize;i++){
fscanf(student_file,"%s %s %s %f", studentRecordList[i].SN,studentRecordList[i].fname,studentRecordList[i].lname,&studentRecordList[i].GPA);
}
fclose(student_file);
}
Now from the driver you are given 4 options to 0-exit(also saves to the file), 1-find(just a search through the array), 2-add(add another student to the array), 3-modify, 4-delete.
the function for adding a student to the array is where I'm getting my problem for some reason it is messing up my output file and changing all my GPA variables to 0.000000 and leaving random blank spaces throughout the document. Anyway here is what it looks like.
void add_record(){
char fname[20];
char lname[20];
char SN[10];
float GPA;
printf("Enter the Students first Name: ");
scanf("%s", &fname);
printf("\nEnter the Students last Name: ");
scanf("%s", &lname);
printf("\nEnter the Students number: ");
scanf("%s", &SN);
printf("\nEnter the Students GPA: ");
scanf("%f", &GPA);
StudentRecord* tempList;
tempList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
studentRecordSize = studentRecordSize+1;
for(i = 0; i < studentRecordSize -1; i ++){
tempList[i].GPA = studentRecordList[i].GPA;
strncpy(tempList[i].SN, studentRecordList[i].SN,10);
strncpy(tempList[i].fname, studentRecordList[i].fname,20);
strncpy(tempList[i].lname , studentRecordList[i].lname,20);
}
printf("%f", &tempList[i].GPA );
free(studentRecordList);
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
for(i=0; i < studentRecordSize; i ++){
//adds the new student at the end of the array.
if(i == studentRecordSize){
strncpy(*studentRecordList[i].fname, &fname,20);
strncpy(*studentRecordList[i].lname, &lname,20);
studentRecordList[i].GPA = GPA;
strncpy(*studentRecordList[i].SN, &SN,10);
}
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
free(tempList);
}
Also if your curious here is what my save_records function looks like otherwise ignore.
void save_records(){
FILE* student_file = fopen("StudentRecordFile.dat", "w");
if(student_file == 0){
perror("cannot open StudentRecordFile.dat in load_records");
}
fprintf(student_file,"%d\n",studentRecordSize);
int i;
for(i = 0; i < studentRecordSize; i++){
fprintf(student_file,"%s\n%s\n%s\n%f\n", studentRecordList[i].SN, studentRecordList[i].fname, studentRecordList[i].lname, &studentRecordList[i].GPA);
}
}
If you need anything else let me know and ill be sure to add it, thanks.
Please try this:
in save_records() open your file binary
fopen(student_file , "wb");
then use fwrite to write the record
fwrite( &studentRecordList[i] , sizeof( studentRecordList) , 1 , student_file );
It is also easier, if you can, to write the number of records to a separate file that you open text.
This code has some problems:
for(i=0; i < studentRecordSize; i ++){
//adds the new student at the end of the array.
if(i == studentRecordSize){ // <- This can never be TRUE !!!
strncpy(*studentRecordList[i].fname, &fname,20); // Wrong
strncpy(*studentRecordList[i].lname, &lname,20);
studentRecordList[i].GPA = GPA;
strncpy(*studentRecordList[i].SN, &SN,10);
}
// Should the code below be an else ?
// If not you'll access outside tempList
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
Maybe you wanted to do:
for(i=0; i < studentRecordSize; i ++){
if(i == (studentRecordSize-1)){
// Add the new record
strncpy(studentRecordList[i].fname, fname,20);
strncpy(studentRecordList[i].lname, lname,20);
studentRecordList[i].GPA = GPA;
strncpy(studentRecordList[i].SN, SN,10);
}
else
{
// Copy from the temp list
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
}
A more simple version of the add function could be:
void add_record(){
char fname[20];
char lname[20];
char SN[10];
float GPA;
printf("Enter the Students first Name: ");
scanf("%s", &fname);
printf("\nEnter the Students last Name: ");
scanf("%s", &lname);
printf("\nEnter the Students number: ");
scanf("%s", &SN);
printf("\nEnter the Students GPA: ");
scanf("%f", &GPA);
StudentRecord* tempList;
tempList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
for(i = 0; i < studentRecordSize; i ++){
tempList = studentRecordList[i];
}
free(studentRecordList);
studentRecordSize = studentRecordSize+1;
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
for(i=0; i < (studentRecordSize-1); i ++){
studentRecordList[i] = tempList[i];
}
free(tempList);
// Add the new record
strncpy(studentRecordList[(studentRecordSize-1)].fname, fname,20);
strncpy(studentRecordList[(studentRecordSize-1)].lname, lname,20);
studentRecordList[(studentRecordSize-1)].GPA = GPA;
strncpy(studentRecordList[(studentRecordSize-1)].SN, SN,10);
}
I want to know how I could sort elements in structs by score and search by last name.
The program also has a problem; when I enter 1 to print the records it asks me for a new entry and when I press 2 it prints the records and ask me for the entry.
So same thing for both cases — I don't know why?
#include <stdio.h>
#include <stdlib.h>
struct the_struct
{
char FirstName[20];
char LastName[32];
int Score[20];
};
int main ()
{
int i,n,z;
struct the_struct *ptr[100];
printf("how many students?\n");
scanf("%d",&n);
for (i = 0; i < n; ++i)
{
ptr[i] = malloc(sizeof(struct the_struct));
printf("Enter First Name \n");
scanf("%s",ptr[i]->FirstName);
printf("Enter Last Name \n");
scanf("%s",ptr[i]->LastName);
printf("Enter Score? \n");
scanf("%s",ptr[i]->Score);
printf("%s %s %s\n",ptr[i]->FirstName,ptr[i]->LastName,ptr[i]->Score);
}
printf("Enter the command you want to proceed to.\nprint record (press 1)\nadd new records (press 2)\ndelete record (press 3)\nSearch by last name (press 4)\nSort by score(press 5)\nSort by last name( press 6)\nFind Median score(press 7)\nExit program (press 0)\n");
scanf("%d",&z);
if (z==1);
{
for (i = 0; i<n;++i)
{
printf("%s %s %s\n",ptr[i]->FirstName,ptr[i]->LastName,ptr[i]->Score);
}
}
if (z==2);
{
ptr[i] = malloc(sizeof(struct the_struct));
printf("Enter First Name \n");
scanf("%s",ptr[i]->FirstName);
printf("Enter Last Name \n");
scanf("%s",ptr[i]->LastName);
printf("Enter Score? \n");
scanf("%s",ptr[i]->Score);
}
}
So I tried to write the sort function but it doesn't work when I print it.
if (z==5)
{
if(strcmp(The_final[i].Score,The_final[i+1].Score)>0)
{
temp = The_final[i];
The_final[i] = The_final[i+1];
The_final[i+1] = temp;
}
printf("%s %s %s\n",ptr[i]->FirstName,ptr[i]->LastName,ptr[i]->Score);
}