How to make a member of a struct dynamic - c

Say I have a struct of something and I want to make its members dynamic. I think the members should be something like this
char* id;
.....
following by a malloc to each member like this
books->id=(char*) malloc(size);
thou it seems when I try it my program crashed so I'm trying to understand what am I doing wrong
This is the part that I think that is relevant to my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxsize 512
typedef struct Books {
char *id;
char title[maxsize];
char author[maxsize];
char pages[maxsize];
char year[maxsize];
char subject[maxsize];
} book;
char* filename;
int libsize=4;
int bookcount=1;
...
int main(int argc, char* argv[]){
if (argc < 1)
return -1;
filename=argv[1];
FILE* fptr;
char tempstring[maxsize],* token;
int i=0,ch;
book *books;
fptr=fopen(filename,"r");
if(fptr==NULL)
return-1;
//this count how many books are in the file
while(ch!= EOF){
ch=fgetc(fptr);
if(ch == '\n')
++bookcount;
}
fclose(fptr);
while(libsize<bookcount){
libsize *= 1.5;
}
books = (book*) malloc(libsize*sizeof(book));
if(books==NULL)
exit(-1);
books->id=(char*)malloc(100);
fptr=fopen(filename,"r");
if(fptr==NULL)
return-1;
//this gets all the books into the book array
for(i=0;i<bookcount;i++){
fgets(tempstring,maxsize,fptr);
token=strtok(tempstring,",");
strcpy(books[i].id,token);
token=strtok(NULL,",");
strcpy(books[i].title,token);
token=strtok(NULL,",");
strcpy(books[i].author,token);
token=strtok(NULL,",");
strcpy(books[i].pages,token);
token=strtok(NULL,",");
strcpy(books[i].year,token);
token=strtok(NULL,",");
strcpy(books[i].subject,token);
}
fclose(fptr);
printf("to add a book press 1\n");
printf("to delete a book press 2\n");
printf("to find a book press 3\n");
printf("to print all books press 4\n");
printf("to save library in a file press 5\n");
printf("to add books from a file press 6\n");
printf("to exit press 0\n");
pick(books);
return 1;
}
void pick(book books[]){
char input;
scanf("%c",&input);
switch (input){
case '1':
addbook(books);
break;
case '2':
delbook(books);
break; //pretty sure break isnt needed but it works so...eh
case '3':
srchbook(books);
break;
case '4':
printbooks(books);
break;
case '5':
printbooksf(books);
break;
case '6':
addbookf(books);
break;
case '0':
free(books);
exit (1);
case '\n':
pick(books);
default:
printf("please enter a valid command\n");
pick(books);
break;
}
}
edit2: added more of the code
edit3: found what was the problem what i did was trying to get to the pointer itself (i think) so the system flipped when i try to did it.
what i should have done was getting to each member array of the struct like that
for(i=0;i<bookcount;i++){
books[i].id=(char*)malloc(charcount);
books[i].title=(char*)malloc(charcount);
books[i].author=(char*)malloc(charcount);
books[i].pages=(char*)malloc(charcount);
books[i].year=(char*)malloc(charcount);
books[i].subject=(char*)malloc(charcount);
}
and not
books->id .....

You only malloc memory for id once. You need to do it for each book:
Like:
// books->id=(char*)malloc(100); Remove this line
fptr=fopen(filename,"r");
if(fptr==NULL)
return-1;
//this gets all the books into the book array
for(i=0;i<bookcount;i++){
fgets(tempstring,maxsize,fptr);
token=strtok(tempstring,",");
books[i].id=(char*)malloc(100); // Add this line
strcpy(books[i].id,token);
BTW
This code seems strange:
while(libsize<bookcount){
libsize *= 1.5;
}
books = (book*) malloc(libsize*sizeof(book));
why not simply do:
books = (book*) malloc(bookcount*sizeof(book));
(note: you don't need to cast malloc)

Related

How to go back from switch menu

I want to make a menu that classifies animals into insects, birds, mammals and fishes with specific characteristics for each of these (using composite variables). I thought I'd use a nested switch case(one switch for the category of the animals and another switch for each category to perform the actions). The problem is, after I've entered a new entry for instance, I wanna have the option to go back and pick another action or even go back and pick another category. How can I do that? I tried with a do-while but I'm just getting an endless loop.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct{
unsigned int noLegs, lifeSpan;
char *name;
}insect;
typedef struct{
float speed, length;
char *habits, *name;
}bird;
typedef struct{
float weight, height;
char *food, *name;
}mammal;
typedef struct{
float weight, depth, salt;
char *name;
}fish;
int main(int argc, char **argv)
{
char choice, action;
bool running = true;
bool returnBack = true;
insect *i = (insect *)malloc(sizeof(insect));
if(!i)
{
printf("Failed to allocate memory.\n");
return -1;
}
while(running)
{
printf("Please choose a category:\n");
printf("1. Insects\n2. Birds\n3. Mammals\n4. Fishes\n5. Exit\n");
scanf(" %c", &choice);
switch(choice)
{
case '1':
printf("You've chosen: Insects\n");
while(returnBack)
{
printf("Please choose an action:\n");
printf("a. Add entry\nb. Delete entry\nc. Replace entry\nd. Lookup entries\ne. Back\n");
scanf(" %c", &action);
switch(action)
{
case 'a':
printf("What entry would you like to add?\n");
i->name = (char *)malloc(sizeof(char));
scanf("%s", i->name);
printf("How many legs does a %s have?\n", i->name);
scanf("%u", &(i->noLegs));
printf("What is the lifespan of a %s?\n", i->name);
scanf("%u", &(i->lifeSpan));
break;
case 'b':
printf("Which entry would you like to delete?\n");
break;
case 'c':
printf("Which entry would you like to replace?\n");
break;
case 'd':
printf("Which entry would you like to replace?\n");
break;
case 'e':
returnBack = false;
break;
default:
printf("Invalid action.\n");
}
}
break;
case '2':
printf("You've chosen: Birds\n");
break;
case '3':
printf("You've chosen: Mammals\n");
break;
case '4':
printf("You've chosen: Fishes\n");
break;
case '5':
running = false;
break;
default:
printf("Invalid choice.\n");
}
}
return 0;
}
As said by alex01011, you just need a while over the whole switch
When the user selects 5 running becomes FALSE and the loop exits.
One thing though, you forgot to clear the whitespace in the first scanf()
#include <stdio.h>
#include <stdlib.h>
#define TRUE (1==1)
#define FALSE (!TRUE)
/* ...
* ALL THE STRUCTS
*/
int main(int argc, char **argv)
{
char choice, action, running = TRUE;
insect *i = (insect *)malloc(sizeof(insect));
// CHECK ON MALLOC RETURN
while(running)
{
printf("Please choose a category:\n");
printf("1. Insects\n2. Birds\n3. Mammals\n4. Fishes\n5. Exit\n\n");
scanf(" %c", &choice); // <-- The leading space was missing
switch(choice)
{
/* ...
* PREVIOUS CASES
*/
case '5':
running = FALSE;
break;
default:
printf("Invalid choice.\n");
}
}
return 0;
}

Checking if an array of structures is 'empty' in 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.

.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 ).

Process Returned -1073741819 (0xc0000005) Code::Blocks

I'm kind of new to programming C with Code::Blocks(Version 12.11), started this semester in my college, but I manage.
I recently learned in class about pointers, memory allocation and dynamic arrays(none are my forte), and I incorporated them in my program(and it compiles)
Now the problem comes when I run the Program and go to Menu -> Add a Product, the program terminâtes when I input a price and I receive "Process Returned -1073741819 (0xc0000005)".
I did some research and found out it's an access violation but I don't really understand how to correct it.
Regards
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxCharName 64
#define maxCharUserPass 8
#define maxCharId 5
// Product Structure
typedef struct{
char name[maxCharName];
char idCode[maxCharId];
float price;
float stock;
}product;
// DataBase of Products
typedef struct{
int sizeT;
product *array;
} TProducts;
TProducts a;
// Press any Key on the Keyboard to Proceed
void pressKeyToContinue(){
puts("\n\n\n Please Press any Key to Continue...");
getchar();
}
// Start Page
void startPage(){
puts("\n\n\n -- Welcome to WeePro Manager --\n\n");
puts(" -- Version 1.0 --\n\n\n\n");
puts(" -- Developped By: Nick --");
pressKeyToContinue();
system("cls");
}
// Program Terminator
void shutdown(){
puts("\n\n\n Good-Bye");
pressKeyToContinue(); // Awaits User Input
exit(0);
}
// Asks User Information for Verification
int userLogin(){
char userName[maxCharUserPass] = "WPuser";
char inputUserName[maxCharUserPass];
char passWord[maxCharUserPass] = "12345";
char inputPassWord[maxCharUserPass];
printf("Username? ");
scanf("%s",inputUserName); fflush(stdin);
printf("Password? ");
scanf("%s", inputPassWord); fflush(stdin);
system("cls");
if((strcmp(userName, inputUserName) == 0)&&(strcmp(passWord, inputPassWord) == 0)){
return 1;
}else{ return 0;}
}
// Lists All Products With their Respective Information
void listAll(){
int idx = 0;
puts("List:");
while((idx < a.sizeT)&&(a.array[idx].name != NULL)){
printf(":::%s ( id: %s )", a.array[idx].name, a.array[idx].idCode);
printf("Price: %6.2f eur/g", a.array[idx].price);
printf("Stock: %6.2f g", a.array[idx].stock);
idx++;
}
pressKeyToContinue();
system("cls");
}
// Input Product ID Code
char* inputIdCode(){
char* tempIdCode;
puts("ID Code?");
scanf("%s", tempIdCode);
system("cls");
return tempIdCode;
}
// Search By ID Code
int searchIdCode(){
int idx = 0;
char* tempIdCode;
tempIdCode = inputIdCode();
do{
if(strcmp(a.array[idx].idCode, tempIdCode) == 0){
return idx;
}else{
idx++;
}
}while(idx < a.sizeT);
puts("No Product With Such an ID Code!");
return -1;
}
// Input Product Name
char *inputProductName(int length){
char name[maxCharName];
puts("Product Name?");
scanf("%s", name); fflush(stdin);
system("cls");
return name;
}
// Input Product Price
float inputProductPrice(int length){
float price;
puts("Product Price?");
scanf("%f", price); fflush(stdin);
system("cls");
return price;
}
// Input Product Stock
float inputProductQuantity(int length){
float quantity;
puts("Product Stock?");
scanf("%f", quantity); fflush(stdin);
system("cls");
return quantity;
}
/////////////////
// Add Product //
/////////////////
// New Product Adder
void addProduct(){
char* tempStr;
float temp;
if(a.sizeT == 0){
a.sizeT = 1;
a.array = (product*)malloc((a.sizeT)*sizeof(product));
}else{
a.sizeT++;
a.array = (product*)realloc(a.array, (a.sizeT)*sizeof(product));
}
tempStr = inputProductName(a.sizeT);
strcpy(a.array[a.sizeT].name, tempStr);
temp = inputProductPrice(a.sizeT);
temp = inputProductQuantity(a.sizeT);
system("cls");
}
void transaction(){}
////////////////////
// Delete Product //
////////////////////
// Delete Product
void deleteProduct(){
int idx, idxPro;
char* tempIdCode;
puts("Delete Which Product?\n");
tempIdCode = inputIdCode();
idxPro = searchIdCode(tempIdCode);
idx = idxPro + 1;
while(idx < a.sizeT){
a.array[idx] = a.array[idx+1];
idx++;
}
a.array = realloc(a.array, (a.sizeT-1)*sizeof(product));
}
//Product Information Modifier
void modifyProduct(){
char choice;
int tabLength;
do{
puts("Modify What?\n");
puts(" -> [N]ame\n");
puts(" -> [P]rice\n");
puts(" -> [S]tock\n\n");
puts(" -> [R]eturn to Previous Menu"); // Prints the Menus' Options
scanf("%c", &choice);
choice = toupper(choice); // Save Users' Choice And Up Case
fflush(stdin);
switch(choice){
case 'N':
system("cls");
tabLength = searchIdCode();
inputProductName(tabLength);
break;
case 'P':
system("cls");
tabLength = searchIdCode();
inputProductPrice(tabLength);
break;
case 'S':
system("cls");
tabLength = searchIdCode();
inputProductQuantity(tabLength);
break;
case 'R':
system("cls");
returnToMenu2();
break;
default:
puts("Something Went Wrong!\n");
pressKeyToContinue();
system("cls");
}
}while(choice != 'o');
}
// Sub-Menu Interface
void menu(){
char choice;
do{
puts("Please Make Your Selection.\n");
puts(" -> [A]dd a New Product\n");
puts(" -> [M]odify a Product\n");
puts(" -> [D]elete a Product\n\n");
puts(" -> [R]eturn to Main Menu"); // Prints the Menus' Options
scanf("%c", &choice); fflush(stdin);
choice = toupper(choice); // Save Users' Choice And Up Case
switch(choice){
case 'A':
system("cls");
addProduct();
break;
case 'M':
system("cls");
modifyProduct();
break;
case 'D':
system("cls");
deleteProduct();
break;
case 'R':
system("cls");
returnToMenu1();
break;
default:
puts("Something Went Wrong!\n");
pressKeyToContinue();
system("cls");
}
}while(choice != 'o');
}
// Return To Ma
> Blockquote
in Menu
void returnToMenu2(){
menu();
}
// Main Menu
void controlPanel(){
char choice;
do{
puts("Please Make Your Selection.\n");
puts(" -> [T]ransaction\n");
puts(" -> [M]enu\n");
puts(" -> [L]ist\n");
puts(" -> [S]hutdown"); // Prints the Panels' Options
scanf("%c", &choice); fflush(stdin);
choice = toupper(choice); // Save Users' Choice And Up Case
switch(choice){
case 'T':
system("cls");
transaction();
break;
case 'M':
system("cls");
menu();
break;
case 'L':
system("cls");
listAll();
break;
case 'S':
system("cls");
shutdown();
break;
default:
puts("Something Went Wrong!\n");
pressKeyToContinue();
system("cls");
}
}while(choice != 'o');
}
// Return To Main Menu
void returnToMenu1(){
controlPanel();
}
int main(){
int loginSuccess=1;
//loginSuccess = userLogin();
switch(loginSuccess){
case 0:
shutdown();
break;
case 1:
startPage();
controlPanel();
break;
}
}
An attempt is being made to write to randon memory, via the uninitialized pointer tempIdCode:
char* inputIdCode(){
char* tempIdCode;
puts("ID Code?");
scanf("%s", tempIdCode);
system("cls");
return tempIdCode;
}
You need to allocate memory for tempIdCode before attempting to write to it. You must use malloc() here (and not return the address of a local array):
char* tempIdCode = malloc(20);
if (tempIdCode)
{
/* The format specifier "%19s" instructs scanf()
to read at most 19 characters, one less than
allocated to allow for terminating null character
written by scanf(), to prevent potential buffer
overrun. */
scanf("%19s", tempIdCode);
}
The caller of the function must explicitly check for a return NULL pointer. The caller must also free() the allocated memory.
This is a killer:
// Input Product Name
char *inputProductName(int length){
char name[maxCharName];
puts("Product Name?");
scanf("%s", name); fflush(stdin);
system("cls");
return name;
}
The reference returned by this function points to an already freed block of memory on the stack, as char name is only valid as long the program is inside the function name is declared in.
When leaving the function name is freed automagically, so any dereferencing of the function's result leads to UB, as it most propably will be accessing unallocated memory.
To solve this you might like to pass in a buffer, where to read the data into:
// Input Product Name
char * inputProductName(int length, char * name){
puts("Product Name?");
scanf("%s", name); fflush(stdin);
system("cls");
return name;
}
and call it like this:
// New Product Adder
void addProduct(){
char* tempStr;
float temp;
if(a.sizeT == 0){
a.array = malloc((a.sizeT)*sizeof(product));
}else{
a.array = realloc(a.array, (a.sizeT)*sizeof(product));
}
a.sizeT++;
inputProductName(a.sizeT, a.array[a.sizeT].name);
...

C program switch statement

I'm new to programming in C. I have a quick question about Switch Statements.
I have a menu that presents a list of options like so:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct Video {
char name[1024]; // Yvideo name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct Video Collection[MAX];
int tail = 0;
//-- Forward Declaration --//
void printall();
void insertion();
void savequit();
void load();
void branching(char);
void menu();
int main()
{
char ch;
load(); // load save data from file
printf("\n\nWelcome\n");
do {
menu();
fflush(stdin); // Flush the standard input buffer
ch = tolower(getchar()); // read a char, convert to lower case
branching(ch);
} while (ch != 'q');
return 0;
}
void menu()
{
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("i: Insert a new favorite\n");
printf("p: Review your list\n");
printf("q: Save and quit\n");
printf("\n\nPlease enter a choice (i, p, or q) ---> ");
}
void branching(char option)
{
switch(option)
{
case 'i':
insertion();
break;
case 'p':
printall();
break;
case 'q':
savequit();
break;
default:
printf("\nError: Invalid Input. Please try again...");
break;
}
}
so far entering 'i' (for inserting a new entry) and q (for save and quit) work perfectly. However every time I enter 'p' I get the default case. (Error: Invalid Input. Please try again...). What is it that I am doing wrong? I believe the syntax for the switch is correct? I've tried changing the 'p' to a different letter and I still got the the default case. Here is my printall() method if that helps...
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nName: %s", Collection[i].name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
What about something like:
char b[5];
do {
menu();
if(fgets(b,5,stdin)==NULL)
return -1;
ch = tolower(b[0]); // read a char, convert to lower case
while(strlen(b)>=4&&b[3]!='\n'){
check=fgets(b,5,stdin);
if(check==NULL)
return -1;
}
branching(ch);
} while (ch != 'q');
You can output the invalid char in your default case. That may help you understand how your input are handled.
default:
printf("\nError: Invalid Input ('%c'). Please try again...", option);
break;
fflush(stdin) is undefined as fflush is define only for output streams. To clear the newline char, you can simply use another getchar().
Try this for the loop part:
do {
menu();
ch = tolower((unsigned char)getchar());
getchar();
branching(ch);
} while (ch != 'q');

Resources