Checking if an array of structures is 'empty' in C - c

I'm making a program that sort of acts like a student records system using an array of structures within structures. The program allows adding, editing and viewing student profile and their corresponding information. I'm having trouble with my displayAll function, when checking if a structure is empty. Supposedly if no subject information has been added to a student profile yet I'm supposed to display a message saying so and display their subject they're enrolled in otherwise. But I'm quite confused how to do so. Some tips would be much appreciated.
I've omitted some parts of the code to put emphasis on the displayAll function.
Someone pointed out this thread: Checking if an array of structs is empty or not, but it doesn't really halp me fully as I am dealing with an array of structures within an array of structures.
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
struct name{
char fname[30];
char lname[20];
char mi;
};
struct local{
char address[30];
char city[20];
};
struct subjs{
char courseCode[10];
char courseDes[20];
char grade;
};
struct student{
char id[8];
struct name studName;
struct local place;
struct subjs course[4];
};
void inputInfo(struct student *studInfo);
void addSubjects(struct student *studInfo);
void displayAll(struct student info[], int limit);
int main(){
struct student info[12];
int i=0, j, courseLimit=0;
char choice;
char idVerify[8];
do{
printf("MENU");
printf("\n\n[A] Add student Information");
printf("\n[B] Add student subject");
printf("\n[C] Edit student address or city");
printf("\n[D] Edit subject grade");
printf("\n[E] View individual student info/subjects");
printf("\n[F] View all students with their corresponding subjects");
printf("\n[g] Quit");
printf("\n\nEnter choice: ");
choice=tolower(getche());
system("cls");
switch (choice){
case 'a':
inputInfo(&info[i]);
i++;
break;
case 'b':
printf("Enter you id number for verification: ");
gets(idVerify);
for(j=0; j<i; j++){
if(strcmp(idVerify, info[j].id) == 0){
addSubjects(&info[j]);
}
else
printf("ID Number not found");
}
break;
case 'c':
//codes
break;
case 'd':
//codes
break;
case 'e':
//codes
break;
case 'f':
displayAll(info, i);
break;
case 'g':
printf("This program will now close.\nPress any key to continue.");
break;
default: printf("Invalid character. Try again");
break;
}
getch();
system("cls");
}while (choice!='g');
}
void inputInfo(struct student *studInfo){
//codes
}
void addSubjects(struct student *studInfo){
//codes
}
void displayAll(struct student info[], int limit){
int i, j;
if(limit == 0){
printf("Records are empty");
}
else{
for(i=0; i<limit; i++){
printf("\nStudent Name: %s %c %s", info[i].studName.fname, info[i].studName.mi, info[i].studName.lname);
printf("\nID Number: %s", info[i].id);
printf("\nAddress and city: %s, %s", info[i].place.address, info[i].place.city);
if(info[i].course[j].courseCode == 0){
printf("\nNo enrolled subjects");
}
else{
printf("\nSubjects:");
for(j=0; j<4; j++){
if(info[i].course[j].courseCode != 0){
printf("Subject %d", j+1);
printf("\nCourse Code: %s", info[i].course[j].courseCode);
printf("\nCourse Description: %s", info[i].course[j].courseDes);
printf("\nCourse Grade: %c", info[i].course[j].grade);
printf("\n");
}
}
}
}
}
}

You can use a flag to track wether a subject has been found in the subject for loop. I would name it found and clear it before the loop. Then set it within the loop, when a subject has been found. If the flag is still cleared after the loop, then print the desired message. To print the header "Subjects", you can check within the loop if a subject has been found (and printed) before.
Example code:
int found = 0; // clear flag
for(j=0; j<=4; j++){
if(info[i].course[j].courseCode != 0){
if(!found) { // if true then this will be the first subject to print
printf("\nSubjects:");
}
found = 1; // set flag
printf("Subject %d", j);
// the other printfs
}
}
if(!found) { // check flag
printf("No enrolled subjects.\n");
}
This replaces the whole
if(info[i].course[j].courseCode == 0){
...
} else {
...
}
block within the student loop.

Related

Edit my struct in C with pointer

I want to create an edit function that receives as a parameter by reference the vector of songs. (using pointers)
The user must choose the song number and re-enter the data of that position of the vector.
I created the struct, I am already receiving the values and I am playing. But I do not know how to edit. Anyone to help me start this part?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <locale.h>
#include <string.h>
struct registry_of_music {
char name[50];
char artist[60];
char url[80];
};
struct registry_of_music music[9];
int main() {
int i;
printf("\nRegistry of Music\n\n\n");
for(i = 0; i <= 3;i++ ){
printf("Name of Music: ");
fflush(stdin);
fgets(music[i].name, 50, stdin);
printf("Name of Artist: ");
fflush(stdin);
fgets(music[i].artist, 60, stdin);
printf("URL of Internet: ");
fflush(stdin);
fgets(music[i].url, 80, stdin);
}
int op;
do
{
printf("1 - Play\n");
printf("2 - Edit\n");
printf("3 - Exit\n");
printf("Please enter a value:");
scanf("%d", &op);
switch(op) {
case 1: play();
break;
case 2: edit();
break;
case 3: printf("Bye\n");
break;
default: printf("Try Again\n");
}
} while (op!=3);
getch();
return(0);
}
void play(){
int i;
for(i = 0; i <= 3;i++ ){
printf("Name ...........: %s", music[i].name);
printf("Artist .....: %s", music[i].artist);
printf("URL .....: %s", music[i].url);
}
}
void edit(){}
The «fill instance of structure» action is absolutely identical if performing on uninitialized structure or initialized. Even if an instance is not initialized, it has some rubbish values in its fields.
On the other hand there is no way to specify default value which will be shown in fgets's prompt and will be available for keyboard edit, unless you're using much more complicated (and NOT included in ISO C standard) tools.

C - Crashing when using Realloc on a Pointer inside a Struct

I've been writing a small program that will allow the user to read a file, create a small "database" and the ability to create / delete entries, etc. When I try to use the
realloc()
function, it crashes.
Not sure if I am doing something wrong, probably am though, since I'm rather new to C.
So, I try to do it this way:
StudentDB database;
//More code in between, that does include malloc()
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
//It crashes when it gets to that part.
What I am trying to do is use the realloc() function for a pointer that's inside a struct.
This is the entire program so far:
#include <stdio.h>
#include <stdlib.h>
typedef struct Lesson {
char *name;
int semester;
float grade;
} Lesson;
typedef struct Student {
char *name;
char *surname;
int id;
int numberOfLessons;
Lesson *lesson;
} Student;
typedef struct Database {
int numberOfStudents;
Student *student;
} StudentDB;
static int maxNameSize = 100;
static int autoclear = 1;
void addStudent(FILE *studentFile, StudentDB *database) {
database->numberOfStudents++;
printf("\nAdded +1 to number of students");
database->student = realloc(&database->student, 10);
//
// printf("Name of the student: ");
// scanf("%s", database.student[database.numberOfStudents].name);
}
void clear() {
if(autoclear) {
system("cls");
}
}
Lesson getNextLesson(FILE *studentFile) {
Lesson lesson;
lesson.name = malloc(maxNameSize * sizeof(char));
if(!lesson.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", lesson.name);
fscanf(studentFile, "%d", &lesson.semester);
fscanf(studentFile, "%f", &lesson.grade);
printf("\n\t%s %d || %.2f\n", lesson.name, lesson.semester, lesson.grade);
return lesson;
}
Student getNextStudent(FILE *studentFile) {
Student student;
student.name = malloc(maxNameSize * sizeof(char));
if(!student.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.name);
student.surname = malloc(maxNameSize * sizeof(char));
if(!student.surname) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.surname);
fscanf(studentFile, "%d", &student.id);
fscanf(studentFile, "%d", &student.numberOfLessons);
printf("%d || %s %s || %d\n", student.id, student.name, student.surname, student.numberOfLessons);
int lesson;
student.lesson = malloc(student.numberOfLessons * sizeof(Lesson));
for(lesson = 0; lesson < student.numberOfLessons; lesson++) {
student.lesson[lesson] = getNextLesson(studentFile);
}
return student;
}
void loadStudents() {
}
void run(FILE *studentFile, StudentDB *database) {
int answer;
do {
clear();
answer = menu();
switch(answer) {
case 1: {
break;
}
case 2: {
break;
}
case 3: {
addStudent(studentFile, &database);
break;
}
case 4: {
break;
}
}
} while(answer < 0 || answer > 9);
}
int menu() {
int answer;
printf("1. Load students records from file\n");
printf("2. Save students records to file\n");
printf("3. Add a student record\n");
printf("4. Delete a student record by student id\n");
printf("5. Display a student record by student id\n");
printf("6. Display a student record by student surname\n");
printf("7. Display all student records\n");
printf("8. Find the lesson average for all students\n");
printf("9. Exit\n");
printf("Enter the number of the thing you would like to do: ");
// scanf("%d", &answer);
return 3;
}
void programInfo() {
printf("\n\n====================================================\n\tProgram Info\n\n This program was created by KKosyfarinis\n\n KKosyfarinis#uth.gr\n====================================================\n\n");
}
void readData(FILE *studentFile, StudentDB *db) {
int i;
printf("Running the loop\n");
for(i = 0; i < db->numberOfStudents; i++) {
printf("=====================\n\n\tStudent #%d\n", i);
db->student[i] = getNextStudent(studentFile);
printf("\n\tCompleted\n\n=====================\n");
}
clear();
}
void saveStudents() {
}
void main() {
system("color 02");
system("#echo off");
FILE *studentFile;
StudentDB database;
studentFile = fopen("students.txt", "r+w");
int numberOfStudents;
//Set the number of students
fscanf(studentFile, "%d", &database.numberOfStudents);
//Prints the number of students
printf("Number of students: %d\n", database.numberOfStudents);
//Set the memory allocation
database.student = malloc(database.numberOfStudents * sizeof(Student));
if(!database.student) {
printf("The memory allocation has failed. Exiting the program!");
exit(0);
}
//Read the students
readData(studentFile, &database);
programInfo();
run(studentFile, &database);
}
Thanks in advance for any help!
You're two code blocks have differing lines. One of which (the larger one) is incorrect. You are passing in a dereference to the student pointer? That's not needed, just pass the pointer itself.
database->student = realloc(&database->student, 10);
Should be:
database->student = realloc(database->student, 10);
You are also not passing in a realistic size, but your first code sample was. Does the following line not work?
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
That was just copied from your question. I'm confused as to what you have/have not tried and which one gives you the error.
Also, in the future provide more of a minimal example that still produces the error. There's also a chance you would figure out the issue while stripping the code down.
What with this line ?
addStudent(studentFile, &database);
in run function ? Where pointer to local variable is taken and passed to addStudent function
void run(FILE *studentFile, StudentDB *database) {
...
case 3: {
addStudent(studentFile, &database); // <-- get pointer to local variable
i think this code cannot work even with Nick's changes without this modification
addStudent(studentFile, database);

Error: c:87:(.text+0x247): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `course_insert'

I'm brand new to C and I'm trying to figure out what in the world is causing this. Another similar question said that I had to download another library but that hasn't fixed the issue. So, hopefully someone can spot my problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Subject {SER=0, EGR=1, CSE=2, EEE=3} subject;
struct Course {
enum Subject subject;
int number;
char teacher[1024];
int hours;
} *course;
//place to store course information
struct Course* CourseCollection = NULL;
//number of courses in the collection. also the index of the next empty element.
int courseCount = 0;
void branching(char option);
void course_insert(struct Course course);
int main() {
char input_buffer;
printf("Welcome to ASU Class Schedule\n");
//menu and input loop
do {
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("a: Add a class\n");
printf("d: Drop a class\n");
printf("s: Show your classes\n");
printf("q: Quit\n");
printf("\nTotal Credits: %d\n\n", courseCount);
printf("Please enter a choice ---> ");
scanf(" %c", &input_buffer);
branching(input_buffer);
} while (input_buffer != 'q');
return 0;
}
//takes a character representing an inputs menu choice and calls the appropriate
//function to fulfill that choice. display an error message if the character is
//not recognized.
void branching(char option) {
int prefix, courseNum, credits;
char instructor;
struct Course course1;
switch(option) {
case 'a' :
printf("Adding a class");
printf("\nWhat is the subject (SER=0, EGR=1, CSE=2, EEE=3)? ");
scanf(" %d", &prefix);
course1.subject = prefix;
printf("\nWhat is the course number (e.g. 334)? ");
scanf(" %d", &courseNum);
course1.number = courseNum;
printf("\nHow many credits is the class? ");
scanf(" %d", &credits);
course1.hours = credits;
printf("\nWhat is the name of the teacher? ");
scanf(" %s", &instructor);
strlcpy(course1.teacher, instructor, 1024);
printf(" %s %d", course1.subject, course1.number);
courseCount++;
course_insert(course1);
break;
case 'd' :
// TODO
break;
case 's' :
// TODO
break;
case 'q' :
printf("Goodbye ");
break;
default :
printf("Error: Invalid Input. Please Try Again. ");
break;
}
void course_insert(struct Course course) {
CourseCollection = malloc(sizeof(course)*courseCount);
}
}
The problem is a syntactical bug; the function definition for course_insert() is inside the curly braces of the function definition of branching(). You need to fix the curly braces:
void branching (char option)
{
// Code for function
}
void course_insert(struct Course course)
{
CourseCollection = malloc(sizeof(course)*courseCount);
}

making a program to add a list of names in 2d array actually I just made a part of it and I have a lot of errors

my code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char names[10][31];
int u=0;
char new[31];
int ctr=1;
int notInList=0;
int y=0;
int i=0;
char *p;
strcpy(names[0],"mahmoud");
while(1)
{
printf("\t\t§§§Menu items§§§\n");
printf("1==>enter a new name\n");
printf("2==>search for a name\n");
printf("3==>delete a name from the list\n");
printf("Note !!.. ((if you want to exit the program press(1)and then type ((exit))\n");
fflush(stdin);
scanf("%i",&u);
notInList=1;
if(u==1)
{
printf("please enter a name : ");
fflush(stdin);
gets(new);
_strlwr(new);
if(strcmp(new,"exit")==0)
{
printf("bye bye\n");
break;
}
else
{
notInList=1;
for(int i=0;i<=ctr;i++)
{
p=strstr(new,names[i]);
if(strcmp(new,names[i])==0)
{
printf("the name is already exist\n");
break;
}
else if (p)
{
printf("did you mean (( %s ))\n",names[i]);
printf("1==>yes\n");
printf("2==>no\n");
fflush(stdin);
scanf("%d",&y);
if(y==1)
{
printf("the name is already exist\n");
break;
}
else if(y==2)
{
notInList=0;
strcpy(new,names[ctr]);
ctr++;
break;
}
else printf("plz enter a number from the list");
}
else
{
notInList=0;
}
}
if(notInList==0)
{
strcpy(new,names[ctr]);
ctr++;
for(int i=0;i<ctr;i++);
{
printf("%d==>%s\n",i+1,names[i]);
}
}
// break;
}
}
return 0;
}
the first problem is: when I enter ( 1) and then add a name is similar to the first name it printf to me did you mean ( )//// without a name
the second is when I want to add a new name it doesn't please help me
notice that he program is not finished only the first choise

.exe crashes when I enter a vaue for &records[*rCount].source

Update *
I have now tried to return something from the function and still the .exe crashes! I am quite new to c so sorry if I am been a bit thick at not spotting why.
struct packet* addRecord(int *rCount, struct packet *records){
int valid = 0; //used to indicated valid input
int length = 0; //used to store the string lengths
int i = 0; //used in the for loops
char dataTest[51]; //temporary storage of input to be checked before adding to records
do{
puts("What is the source of this packet?: ");
if(scanf(" %c", &records[*rCount].source) == 1){ //if correct insert the record at the index
valid=1; //determined by rCount(the current record count passed to addRecord
}
else{
valid = 0;
getchar();
puts("\nNot a valid input");
}
}while(valid!=1);
do{
puts("What is the destination of this packet?: ");
if(scanf(" %c", &records[*rCount].destination) == 1)
{
valid = 1;
}
else
{
valid = 1;
getchar();
puts("\nNot a valid input");
}
}
while(valid!=1);
records = realloc(records,(*rCount+1)*sizeof(struct packet));
return records;
}
So I have got this code to work, but when I enter a value for &records[*rCount].source, the .exe crashes. I have been looking at this code for an hour now and cannot find the broken link, but I feel like it's something simple.
Here is the little bit of code that I feel like is not working properly.
Also can someone please explain what == 1 means in the if statement, I've kinda just hacked this code together. Thanks
do{
puts("What is the source of this packet?: ");
if(scanf("%i", &records[*rCount].source) == 1){ //if correct insert the record at the index
valid=1; //determined by rCount(the current record count passed to addRecord
}
else{
valid = 0;
getchar();
puts("\nNot a valid input");
}
}while(valid!=1);
Full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct packet{ // declare structure for packet creation
int source;
int destination;
int type;
int port;
char data[51];
};
//function prototypes
void listRecords(int, struct packet*);
struct packet* addRecord(int*, struct packet*);
void save(int, struct packet*);
struct packet* open(int*, struct packet*);
int main ()
{
int recordCount = 0;
char choice;
struct packet *records;
struct packet *temp;
do {
printf("\nWhat would you like to do?\n");
printf("\t1) Add a packet.\n"); //---------------------//
printf("\t2) List all packets.\n"); //---------------------//
printf("\t3) Save packets.\n"); //---------MENU--------//
printf("\t4) Clear all packets.\n"); //---------------------//
printf("\t5) Quit the programme.\n"); //---------------------//
scanf("%i", &choice); // scan user input and put the entry into variable "choice"
if(choice == '/n')
scanf("%i", &choice);
switch(choice)
{
case 1: system("cls");
records = addRecord(&recordCount, records);
break;
case 2: system("cls");
break;
case 3: system("cls");
break;
case 4: system("cls");
break;
default: system("cls");
printf("%i was not a valid option\n", choice);
break;
}
}
while (choice != 5);
return 0;
}
struct packet* addRecord(int *rCount, struct packet *records){
int valid = 0; //used to indicated valid input
int length = 0; //used to store the string lengths
int i = 0; //used in the for loops
char dataTest[51]; //temporary storage of input to be checked before adding to records
do{
puts("What is the source of this packet?: ");
if(scanf("%i", &records[*rCount].source) == 1){ //if correct insert the record at the index
valid=1; //determined by rCount(the current record count passed to addRecord
}
else{
valid = 0;
getchar();
puts("\nNot a valid input");
}
}while(valid!=1);
do{
puts("What is the destination of this packet?: ");
if(scanf("%i", &records[*rCount].destination == 1))
{
valid = 1;
}
else
{
valid = 1;
getchar();
puts("\nNot a valid input");
}
}
while(valid!=1);
}
Change
if(scanf("%i", &records[*rCount].destination == 1))
to
if(scanf("%d", &records[*rCount].destination) == 1)
Also change %i to %d and char choice; to int choice;
Another problem is you are returning nothing from your function which has pointer to struct packet return type .
After some changes that I made the compiling code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct packet{ // declare structure for packet creation
int source;
int destination;
int type;
int port;
char data[51];
};
//function prototypes
void listRecords(int, struct packet*);
void addRecord(int*, struct packet*);
void save(int, struct packet*);
struct packet* open(int*, struct packet*);
int main (void)
{
int recordCount = 0;
int choice;
struct packet *records;
//struct packet *temp;
do {
printf("\nWhat would you like to do?\n");
printf("\t1) Add a packet.\n"); //---------------------//
printf("\t2) List all packets.\n"); //---------------------//
printf("\t3) Save packets.\n"); //---------MENU--------//
printf("\t4) Clear all packets.\n"); //---------------------//
printf("\t5) Quit the programme.\n"); //---------------------//
scanf("%d", &choice); // scan user input and put the entry into variable "choice"
if(choice == '\n')
scanf("%d", &choice);
switch(choice)
{
case 1: system("cls");
addRecord(&recordCount, records);
break;
case 2: system("cls");
break;
case 3: system("cls");
break;
case 4: system("cls");
break;
default: system("cls");
printf("%d was not a valid option\n", choice);
break;
}
}
while (choice != 5);
return 0;
}
void addRecord(int *rCount, struct packet *records){
int valid = 0; //used to indicated valid input
//int length = 0; //used to store the string lengths
//int i = 0; //used in the for loops
//char dataTest[51]; //temporary storage of input to be checked before adding to records
do{
puts("What is the source of this packet?: ");
if(scanf("%d", &records[*rCount].source) == 1){ //if correct insert the record at the index
valid=1; //determined by rCount(the current record count passed to addRecord
}
else{
valid = 0;
getchar();
puts("\nNot a valid input");
}
}while(valid!=1);
do{
puts("What is the destination of this packet?: ");
if(scanf("%d", &records[*rCount].destination) == 1)
{
valid = 1;
}
else
{
valid = 1;
getchar();
puts("\nNot a valid input");
}
}
while(valid!=1);
}
struct packet *records;
All well and good but you never actually created a struct packet for this pointer to point to. Therefore all access through this pointer is to invalid memory that does not belong to you.
I don't see any need for a pointer here. Simply declare it as:
struct packet records;
Then pass a pointer to that object:
case 1: system("cls");
addRecord(&recordCount, &records);
Notice that I've gotten rid of the return for addRecord; you simply do not need it. Make it return void. As it is now, you are taking one invalid pointer and overwriting it with another invalid pointer populated with randomness, since you never actually return anything. It's the same problem, just happening to trigger a crash due to the random value you get.
What is %i supposed to be doing? Are you looking for an integer? If so, you want %d (d for decimal).
== 1 checks that scanf successfully processed 1 item.
And what #haccks said about missing ).

Resources