Making a queue program - c

Can someone help me making a queue program. I want to set the array[0] to be array[1] just in display but in real I am adding value at array[0]. I got how to run the add function to it, but I can't do the view and delete command that will view from ex. array[0] to array[4], when displayed array[1] to array[5] with the value inserted.
#include <stdio.h>
#include <stdlib.h>
#define p printf
#define s scanf
int rear = 0;
int front = 0;
int *q_array = NULL;
int size = 0;
main()
{
int num, opt;
char cont[] = { 'y' };
clrscr();
p("Queue Program\n\n");
p("Queue size: ");
s("%d", &size);
p("\n");
if(size > 0)
{
q_array = malloc(size * sizeof(int));
if(q_array == NULL)
{
p("ERROR: malloc() failed\n");
exit(2);
}
}
else
{
p("ERROR: size should be positive integer\n");
exit(1);
}
while((cont[0] == 'y') || (cont[0] == 'Y'))
{
clrscr();
p("Queue Program");
p("\n\nQueue size: %d\n\n", size);
p("MAIN MENU\n1. Add\n2. Delete\n3. View");
p("\n\nYour choice: ");
s("%d", &opt);
p("\n");
switch(opt) {
case 1:
if(rear==size)
{
p("You can't add more data");
}
else
{
p("Enter data for Queue[%d]: ", rear+1);
s("%d", &num);
add(num);
}
break;
case 2:
delt();
break;
case 3:
view();
break;
}
p("\n\nDo you want to continue? (Y\/N)");
s("%s", &cont[0]);
}
}
add(int a)
{
q_array[rear]=a;
rear++;
}
delt()
{
if(front==rear)
{
p("Queue Empty");
}
else
{
p("Queue[%d] = %d removed.", front, q_array[front]);
front++;
}
}
view()
{
int i;
for(i=front;i<=rear;i++)
p("\nQueue[%d] = %d", i, q_array[i]);
}

One serious problem here is
char cont[] = { 'y' };
...
s("%s", &cont[0]);
You've only reserved one byte but scanf will write at least 2 bytes, meaning that you are going to have a buffer overflow and then the overall behaviour is unpredictable. If you want to read a single character then use"%c" as a pattern but the problem here is that characters will be in the buffer for the next read, so you are going to have to clear the buffer.
It's much easier to do:
char line[1024];
fgets(line, sizeof line, stdin);
if(line[strlen(line)-1] == '\n')
line[strlen(line)-1] = 0;
if(strcmp(line, "Y") == 0 || strcmp(line, "y")==0)
It's a little more code but it's safer this way.
There are many queues, there are fifo, lifo, and depending on it you choose how to build it
When dealing with queues, it's better to use function names like push, pop and top because they are widely used among other programmers and queue libraries. Use
these names instead.
In your case, instead if remembering with front and rear you should use
memmove instead and use a variable len to count the current number of
elements in the node. Once you've popped one element, you gained new space for
more elements.
Also, try to use fewer global variables and more encapsulation: (in my example I am
not going to care about malloc returning NULL, I want to keep it short)
#include <string.h> /* for size_t */
typefed struct {
size_z len;
size_z max_size;
int *data;
} queue;
void queue_init(queue *q, size_t max_size)
{
q->len = 0;
q->max_size = max_size;
q->data = malloc(max_size * sizeof *(q->data));
/* this is a good trick!
* If you need to change the datatype of 'data',
* you only need to change the definition of it.
* This code is valid for any type */
}
int push(queue *q, int data)
{
if(q->len == q->max_size)
return 0; /* not enough space */
q->data[q->len++] = data;
return 1;
}
int top(queue *q, int *data)
{
if(q->len == 0)
return 0; /* no elements in the queue */
*data = q->data[0];
return 1;
}
int pop(queue *q, int *data)
{
if(top(q, data) == 0)
return 0;
memmove(q->data, q->data + sizeof *(q->data), q->len--);
return 1;
}
BTW:
#define p printf
#define s scanf
Just like Daniel Fischer said, this is ugly; don't do that.

Related

Cannot implement Linked List in the given code

I want to insert the data in ascending order based on the partNumber.
When the function is called in main, then the node is successfully added at the first position. But on calling the function second time, there is some problem in insertion and I am unable to figure it out. When I enter the values(in second call), I get the error
Process exited after 8.277 seconds with return value 3221225477
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int
main(int argc, char *argv[])
{
insertPart();
insertPart();
insertPart();
insertPart();
return 0;
}
void
insertPart()
{
Part *tempPart,
*traversePart,
*swapPart;
int counter = 0;
traversePart = inventory;
tempPart = (Part *) malloc(sizeof(Part *));
printf("Enter the Part Number\n");
scanf("%d", &(tempPart->partNumber));
getchar();
printf("Enter the Part Name\n");
fgets(tempPart->partName, 200, stdin);
printf("Enter the Part Quantity\n");
scanf("%d", &(tempPart->partQuantity));
getchar();
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
else {
while (traversePart->nextPart->partNumber < tempPart->partNumber) {
counter++;
traversePart = traversePart->nextPart;
if (traversePart->nextPart == NULL) {
break;
}
}
if (counter == 0) {
swapPart = inventory;
inventory = tempPart;
tempPart->nextPart = swapPart;
}
else if (traversePart->nextPart == NULL) {
traversePart->nextPart = tempPart;
}
else {
swapPart = traversePart->nextPart;
traversePart->nextPart = tempPart;
tempPart->nextPart = swapPart;
}
}
printf("Element added at position : %d", counter);
}
The problem is traversePart->nextPart->partNumber traversePart->nextPart is not referring to anything or it is not holding any of the address. When you insert first value if condition is true
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
inventory now holding the address of tempPart but while assigning values of tempPart you never assign an address to its nextvalue and it's not there because you only inserted the first value. For the second position
else{
while(traversePart->nextPart!=NULL)
{
traversePart=traversePart->nextPart;
}
if(traversePart->partNumber < tempPart->partNumber){
//here you can verify conditions
traversePart->nextPart = tempPart
}
}
You're intermixing fgets and scanf [and getchar]. Better to use just fgets and then apply strtol for numbers [or sscanf].
You're linked list code is a bit convoluted. It can be simplified.
Here's the refactored code. I've pulled some helper functions that I had lying around to do the prompting.
And, I added list printing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int getstr(char *buf,int buflen,const char *prompt);
long getnum_strtol(const char *prompt);
int
main(int argc, char **argv)
{
insertPart();
insertPart();
insertPart();
insertPart();
for (Part *cur = inventory; cur != NULL; cur = cur->nextPart)
printf("partNumber=%d partQuantity=%d partName='%s'\n",
cur->partNumber,cur->partQuantity,cur->partName);
return 0;
}
void
insertPart(void)
{
Part *tempPart;
Part *cur;
Part *prev = NULL;
int counter = 0;
#if 0
tempPart = (Part *) malloc(sizeof(Part *));
#else
tempPart = malloc(sizeof(*tempPart));
#endif
tempPart->partNumber = getnum_strtol("Enter the Part Number");
getstr(tempPart->partName,sizeof(tempPart->partName),"Enter the Part Name");
tempPart->partQuantity = getnum_strtol("Enter the Part Quantity");
tempPart->nextPart = NULL;
// find the tail/end of the list
for (cur = inventory; cur != NULL; cur = cur->nextPart) {
++counter;
// insert in sorted part order
if (cur->partNumber > tempPart->partNumber)
break;
prev = cur;
}
do {
tempPart->nextPart = cur;
// insert in the middle or end of list
if (prev != NULL) {
prev->nextPart = tempPart;
break;
}
// insert in new list or before first element of existing list
tempPart->nextPart = inventory;
inventory = tempPart;
} while (0);
printf("\nElement added at position : %d\n", counter);
}
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
if (prompt != NULL) {
printf("%s: ",prompt);
fflush(stdout);
}
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = &buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != '\n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,&cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case '\t':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
}
return num;
}
Here's the input file I used to test:
37
Hex Bolt
12
28
Machine Screw
6
23
Brad Nail
1000
27
Lock Nut
300
Here's the program output:
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 0
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 2
partNumber=23 partQuantity=1000 partName='Brad Nail'
partNumber=27 partQuantity=300 partName='Lock Nut'
partNumber=28 partQuantity=6 partName='Machine Screw'
partNumber=37 partQuantity=12 partName='Hex Bolt'

How to access an element in the structure which not the first - Qsort

I am trying to sort the following structure. I am using the qsort to order the books according to date publish in order of the newest first. I completely don't understand why the pointer can't access the date-published element.
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int int_cmp(const void *a, const void *b)
{
//const int *ia = (const int *)a;
//const int *ib = (const int *)b;
//return *ia - *ib;
return (*(int*)a - *(int*)b);
}
int main()
{
struct book* books = NULL; // no books at all initially so we initialize to NULL
// so we can simply use realloc
int numberofbooks = 0;
int programend = 0;
while (programend == 0)
{
printf("1. Add Book\n");
printf("2. View Books\n");
printf("3. Quit\n");
int command;
int i, j;
scanf("%d", &command);
if (command == 1)
{
getchar(); // consume Enter key (due su scanf)
// allocate memory for one more book
books = realloc(books, sizeof(struct book) * (numberofbooks + 1));
printf("Enter Name\n");
gets(books[numberofbooks].name);
printf("Enter Author\n");
gets(books[numberofbooks].author);
printf("Enter Year Published\n");
scanf("%d", &books[numberofbooks].year_published);
numberofbooks++; // increment number of books
printf(books.year_published);
}
else if (command == 2)
{
qsort(books->year_published, numberofbooks, sizeof(int), int_cmp);
for (i = 0; i < numberofbooks; i++)
{
printf("%d - %s by %s\n", books[i].year_published, books[i].name, books[i].author);
}
}
else if (command == 3)
{
programend = 1;
}
//else if and the else will prevent infinite loop when the user enters invalid choice in the beginning.
else if (command != 1 || command != 2 || command != 3)
{
printf("Invalid choice!\n");
}
else {return 0;}
}
free(books);
return 0;
}
I think the problem is the pointer in the qsort() but I don't know how to correct that. I tried using qsort(books, numberofbooks, sizeof(int), int_cmp); but the books weren't ordered as expected.
Here is an example of a multikey sort:
int
cmp_multikey(const void *a,const void *b)
{
const struct book *booka = a;
const struct book *bookb = b;
int cmp;
do {
// sort by year published
cmp = booka->year_published - bookb->year_published;
if (cmp)
break;
// sort by author
cmp = strcmp(booka->author,bookb->author);
if (cmp)
break;
// sort by title
cmp = strcmp(booka->name,bookb->name);
if (cmp)
break;
} while (0);
return cmp;
}
Invoke with:
qsort(books,numberofbooks,sizeof(struct book),cmp_multikey);
Some other tips ...
[As others have mentioned] Never use gets. Use a switch/case instead of an if/else ladder.
Try to avoid intermixing scanf and fgets.
Personally, I prefer to [always] use fgets. Here is a [safe] replacement for gets and a replacment for scanf("%d",&num);:
int
getstr(const char *prompt,char *buf,int buflen)
{
char *cp;
printf("%s",prompt);
fflush(stdout);
cp = fgets(buf,buflen,stdin);
if (cp == NULL) {
fprintf(stderr,"unexpected EOF\n");
exit(1);
}
// find newline
cp = strchr(buf,'\n');
// ensure we had enough space
if (cp == NULL) {
fprintf(stderr,"response too large for buffer\n");
exit(1);
}
// strip newline
*cp = 0;
}
int
getnum(const char *prompt)
{
char buf[1000];
int num;
getstr(prompt,buf,sizeof(buf));
num = atoi(buf);
return num;
}

How can i automatically increase memory allocation for a struct in C?

I am building a small program that takes name and age as input (stored in a struct) and spits out the output. One of the problems that I am facing is I have to enter the number of people I am going to store, something that I am sure I can solve with realloc() it's just not working. Here is what I got so far.
#include <stdio.h>
#include<stdlib.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *Ptr;
int i, num;
printf("Enter number of people");
scanf("%d", &num);
// Allocates the memory for num structures with pointer Ptr pointing to the base address.
Ptr = (struct info*)malloc(num * sizeof(struct info));
for(i = 0; i < num; ++i)
{
printf("Enter name and age:\n");
scanf("%s %d", &(Ptr+i)->name, &(Ptr+i)->age);
}
for(i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", (Ptr+i)->name, (Ptr+i)->age);
return 0;
}
I have tried to realloc inside the first for loop, but it wasn't working even if it makes sense to have it there. Have also tried to convert the loop to a while loop like this:
while(input != "stop)
{
allocate more memory
}
How can I use realloc to in order to skip having to enter the persons number before entering them?
realloc is the correct way. Just start with Ptr = NULL and num = 0 and on each input increase the number of elements by one.
Remember to limit the number of characters scanf can read, otherwise you may buffer overrun.
Also I find Ptr[i] way easier then (Ptr+i)->.
Also compare strings with strcmp not using !=. The != will compare pointers to strings, not strings themselves.
As I like reading the whole line, then scanning the line, I would do it like this:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *ptr = 0;
size_t num = 0;
for (;;) {
printf("Enter name and age. If you want to stop, type only 'stop'.\n");
char line[256];
if (fgets(line, sizeof(line), stdin) == NULL) {
fprintf(stderr, "fgets error");
exit(-1);
}
if (!strcmp("stop\n", line)) {
break;
}
struct info tmp;
if (sscanf(line, "%29s %d\n", tmp.name, &tmp.age) != 2) {
fprintf(stderr, "error parsing line\n");
exit(-1);
}
ptr = realloc(ptr, (num + 1) * sizeof(*ptr));
if (ptr == NULL) {
fprintf(stderr, "error allocating memory!\n");
exit(-1);
}
ptr[num] = tmp;
++num;
}
for (size_t i = 0; i < num ; ++i) {
printf("Name = %s, Age = %d\n", ptr[i].name, ptr[i].age);
}
free(ptr);
return 0;
}
If you are not sure of the no.of.elements you want to allocate and do it based on the users choice, then you can follow the below approach.
It starts with one element and the memory is reallocated as when the user wants to add new element.
#include <stdio.h>
#include<stdlib.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *Ptr=NULL;
int i=0, num;
char c='Y';
while(c=='Y'||c=='y') {
Ptr=realloc(Ptr,(i+1)*sizeof(struct info));
if(Ptr==NULL)
break;
printf("Enter name and age:\n");
scanf("%s %d",&Ptr[i].name,&Ptr[i].age);
printf("Do you want to cont?\n");
scanf(" %c",&c);
i++;
}
num=i;
for(i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", (Ptr+i)->name, (Ptr+i)->age);
free(Ptr);
return 0;
}
To answer exactly, you can first read the input to temp variables and check if you need to stop: Break the loop if so. Or continue and reallocate the 'storage' array by increasing it's size by one and copying the values you just read to the 'storage' array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info * infos = 0;
int num = 0;
char input_name[30];
int input_age;
while (1)
{
printf("Enter name and age:\n");
int r = scanf("%29s", input_name);
if (r == EOF || strcmp(input_name, "stop") == 0)
break;
scanf(" %d", &input_age);
infos = realloc(infos, sizeof(struct info) * (num + 1));
infos[num].age = input_age;
memcpy(infos[num].name, input_name, sizeof(char) * 30);
num++;
}
for(int i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", infos[i].name, infos[i].age);
return 0;
}
You should use a data struct like vector.
vector_init init vector.
vector_push push val to vector, if necessary, will realloc memory.
vector_output output the vector.
The following code could work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INIT_SIZE 1
struct info
{
int age;
char name[30];
};
struct vector {
struct info* p;
int n;
int index;
};
void vector_init(struct vector* ve) {
ve->n = INIT_SIZE;
ve->index = 0;
ve->p = malloc(sizeof(struct info) * ve->n);
}
void vector_push(struct vector* ve, struct info* tmp) {
if (ve->n == ve->index) {
ve->n *= 2;
ve->p = realloc(ve->p, sizeof(struct info) * ve->n);
}
ve->p[ve->index++] = *tmp;
}
void vector_output(const struct vector* ve) {
for (int i = 0; i < ve->index; ++i)
printf("Name = %s, Age = %d\n", ve->p[i].name, ve->p[i].age);
}
int main()
{
struct vector ve;
vector_init(&ve);
for (;;) {
struct info tmp;
printf("Enter name and age:\n");
scanf("%29s", tmp.name);
if (strcmp(tmp.name, "stop") == 0)
break;
scanf("%d", &tmp.age);
vector_push(&ve, &tmp);
}
vector_output(&ve);
return 0;
}

Is this approach using a dynamic array structure in C OK?

I am just a beginner in C looking for a dynamic array structure and came across this youtube tutorial.
The Code uses pointers to create a dynamic array without using heap memory allocation like malloc(). I just wonder, if this approach is Ok or it will likely become a bug, because memory can be overwritten?
The Code:
#include "stdio.h"
typedef struct S_RacingCar {
char name[8];
int speed;
} RacingCar;
const int MaxCars = 4;
void PrintList() {
printf("List Print...\n");
}
int AddCar(RacingCar *car) {
printf("Enter Name And Speed: ");
char input[16];
fgets( input, 15, stdin);
int ok = 0;
int res = sscanf(input, "%s %d", car->name, &car->speed);
if(res == 2) {
ok = 1;
printf("Added:%s Speed:%d\n\n",car->name,car->speed);
} else {
printf("Sorry, error parsing input\n\n");
}
return ok;
}
int main() {
RacingCar allCars[MaxCars];
int numCars = 0;
char command[16];
char input[16];
while( fgets( input, 15, stdin) ) {
sscanf(input,"%s",command);
if ( strncmp(command, "quit", 4) == 0) {
printf("\n\nBreaking...\n");
break;
} else if ( strncmp(command, "print", 5) == 0) {
PrintList();
} else if ( strncmp(command, "add", 3) == 0) {
if(numCars < MaxCars) {
numCars += AddCar( &allCars[numCars] );
} else {
printf("Sorry List Is Full!!\n\n");
}
}
}
return 0;
}
There is no dynamic array in your code
RacingCar allCars[MaxCars];
Here, the max size of array is already defined as MaxCars. The thing that might seem to confuse you is that from main the reference to the array is sent to other functions where the value is being added into the array.
To create a dynamic array in C, you use malloc, calloc or realloc .

Program doesnt write to file and crashes when loading

So i need to write and read to and from a binary file, but cant seem to do it, and when using readFromFile, the program crashes. I need help write to binary file, and then reading from it and resuming my work later after turning off the program.I have no idea what i am doing wrong, and i have googled for a long time now, but with no results. Here is the code of my program:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *subjName;
char *lectName;
char *lectSurname;
int credits;
int num_students;
}Subject;
typedef struct{
Subject **subjs;
int num_subjs;
}Subjects;
int numOfSubjs=0;
void listInput();
void listEdit();
void listDelete();
void listPrint();
int userChoice(int select);
int enterNumber(char *name);
void saveToFile(Subjects *subjects);
void readFromFile(Subjects *subjects);
int main() {
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 0;
subjects->subjs = NULL;
readFromFile(subjects);
int r=1;
while(r!=0){
int select=userChoice(select);
switch(select){
case 1:
listPrint(subjects);
break;
case 2:
listInput(&subjects);
break;
case 3:
listDelete(subjects);
break;
case 4:
listEdit(subjects);
break;
case 0:
r=0;
break;
}
}
saveToFile(subjects);
return 0;
}
int userChoice(int select){ // menu options
int choice,input=0;
printf("(1). View all the data\n");
printf("(2). Enter new data\n");
printf("(3). Delete data\n");
printf("(4). Edit data\n");
printf("(0). Exit\n");
printf("-----------------------------\n");
while(input!=1){
choice = enterNumber("menu");
if(choice>4 || choice<0){
printf("Invalid input \n");
}
else
input = 1;
}
return choice;
}
void listPrint(Subjects *subjects){ // print data
int i;
for(i=0; i< numOfSubjs; i++){
printf("%d, %s, %s, %s, %d, %d\n",i+1, subjects->subjs[i]->subjName, subjects->subjs[i]->lectName, subjects->subjs[i]->lectSurname, subjects->subjs[i]->credits, subjects->subjs[i]->num_students);
}
printf("Number of entries: %d \n", numOfSubjs);
}
char *getln() //dynamically allocate input string
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = 1;
while (ch) {
ch = getc(stdin);
if (ch == '\n')
ch = 0;
if (size <= index) {
size += 1;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
void saveToFile(Subjects *subjects){
FILE *data;
data = fopen("data.bin","wb");
printf("%s", subjects->subjs[0]);
for(int i=0; i<numOfSubjs; i++){
fwrite(&subjects->subjs[i],sizeof(Subject*),1,data);
}
fclose(data);
}
void readFromFile(Subjects *subjects){
FILE *data;
int i=0;
data = fopen("data.bin","rb");
while(!feof(data))
{
fread(&subjects->subjs[i],sizeof(Subject*),1,data);
i++;
}
fclose(data);
}
int isText(char *str,char *name){ // check if is text
for(int i = 0; i < strlen(str);i++){
if((str[i]<'A' || str[i]>'z') && str[i]!=' '){
printf("Error, %s must be a text \n",name);
return 0;
}
}
return 1;
}
int enterNumber(char *name){ // enter number and check if is number
int input=0, crash=0, num=0;
while(input!=1)
{
crash=0;
printf("Enter the number of %s\n", name);
scanf("%d", &num);
while(getchar()!='\n')
{
crash++;
}
if(crash>0 || num<0)
printf("Error, enter a not negative number of %s\n", name);
else if(crash==0)
input=1;
}
return num;
}
void listInput(Subjects **p_subjects){ // input new data
Subject *new_subj = malloc(sizeof(Subject));
new_subj->subjName = NULL;
new_subj->lectName = NULL;
new_subj->lectSurname = NULL;
new_subj->credits = 0;
new_subj->num_students = 0;
do{
printf("Enter the name of the subject \n");
new_subj->subjName = getln();
}while(!isText(new_subj->subjName,"Subject name"));
do{
printf("Enter the name of the lecturer \n");
new_subj->lectName = getln();
new_subj->lectName[0] &= '_';
}while(!isText(new_subj->lectName,"Lecturer's name"));
do{
printf("Enter the surname of the lecturer\n");
new_subj->lectSurname = getln();
new_subj->lectSurname[0] &= '_'; //Convert to uppercase if lowercase
}while(!isText(new_subj->lectSurname,"Lecturer's name"));
new_subj->credits = enterNumber("credits");
new_subj->num_students = enterNumber("students");
(*p_subjects)->subjs = realloc((*p_subjects)->subjs,sizeof(Subject*)*(++(*p_subjects)->num_subjs));
(*p_subjects)->subjs[(*p_subjects)->num_subjs-1] = new_subj;
numOfSubjs++;
printf("Added a new entry.\n\n");
}
void listDelete(Subjects *subjects){ // delete entries
int del;
if(numOfSubjs==0)
printf("Number of entries is 0, can't delete anything\n");
else{
printf("Enter 0 to exit. Number of subjects : %d \n", numOfSubjs);
while(1){
del = enterNumber("entry which you would like to delete");
if(del<=numOfSubjs && del>0){
for(int i = del-1; i<numOfSubjs-1; i++){
subjects->subjs[i]=subjects->subjs[i+1];
subjects->subjs = realloc(subjects->subjs,sizeof(Subject*)*(--subjects->num_subjs));
}
numOfSubjs--;
break;
}
if(del>numOfSubjs)
printf("Error, input a number between 1 and %d (or enter 0 to exit)\n", numOfSubjs);
else
break;
}
}
}
void listEdit(Subjects *subjects){ // edit entries
int choice=0, editEntry=0, editSubj=0;
if(numOfSubjs == 0)
printf("Number of entries is 0, can't edit anthing\n");
else{
while(1){
printf("Number of entry must be between 1 and %d \n", numOfSubjs);
choice = enterNumber("entry you would like to edit.");
if(choice>0 && choice<=numOfSubjs){
while(1){
editEntry = enterNumber("what would you like to edit\n 1 - Subject name\n 2 - Lecturer's name\n 3 - Lecturer's surname\n 4 - Number of credits\n 5 - Number of students");
if(editEntry>0 && editEntry <=5){
switch(editEntry){
case 1:
do{
printf("Enter the name of the subject \n");
subjects->subjs[choice-1]->subjName = getln();
}while(!isText(subjects->subjs[choice-1]->subjName,"Subject name"));
break;
case 2:
do{
printf("Enter Lecturer's name \n");
subjects->subjs[choice-1]->lectName = getln();
}while(!isText(subjects->subjs[choice-1]->lectName,"Lecturer's name"));
break;
case 3:
do{
printf("Enter Lecturer's surname \n");
subjects->subjs[choice-1]->lectSurname = getln();
}while(!isText(subjects->subjs[choice-1]->lectSurname,"Lecturer's surname"));
break;
case 4:
subjects->subjs[choice-1]->credits = enterNumber("credits");
break;
case 5:
subjects->subjs[choice-1]->num_students = enterNumber("students");
break;
}
}
break;
}
}
break;
}
}
}
&subjects->subjs[i], This is Undefined behavior. Accessing garbage value. You need to properly initialize it proper memory address. You ddin't do it anywhere.
(*subjects).subjs or subjects->subjs -> This is not pointing anywhere. It is NULL.
Also here you don't need the double pointer. A single pointer would do the thing you want to do.
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
For single pointer this would be like
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 10;
subjects->subjs = malloc(subjects->num_subjs * sizeof Subject);
subjects->subjs[0].subjName = malloc(40);
Each of the malloc should be checked with it's return Value. If it's NULL then it would be error to proceed further or access it.
And free() it accordingly when you are done working with it.
Some basic things:-
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
Now let's look a bit in the code.
Op asked why OP should initialize and isn;t subjects->num_subjs = 0;
subjects->subjs = NULL; not enough?
A pointer is a variable that is supposed to hold address. here Subject* will hold the address of the variables of type Subject.
Now here initially you initialized it.
You have allocated a memory and assigned it's address to the Subject* variable subjects.
Now let's see what else you do.
subjects->num_subjs = 0;
subjects->subjs = NULL;
You initialized it. And then you try to access it(subjects->subjs[i]). Can you tell me where it points to? (subject->subjs)?
Answer is nope. It is pointing to nowhere. It contains NULL value now. Don't you think you should tell it how many subject you want to hold and allocate accordingly? Yes you should and that's what I did precisely in the example shown.
Whenever you have a pointer variable ask yourself what it contains - and if the value is something you know about, not some random garbage value.

Resources