Storing user input whilst still asking questions - c

Firstly, i know the source code below is long and you're not really supposed to post code like this, but i really don't understand why it's not working or how i could explain my issue without posting it like this.
Im trying to store the answer to each of the questions asked in it and display them at the end of the script. The biggest problem im having is that i get the error
"subscripted value is neither array nor pointer nor vector scanf("%s", a[i].incdest);"
The program doesn't accept a[i].incdest. it does this for all of the array values.
it is also saying that in function main variable "comp1" is undeclared.
#include<stdio.h>
#include<string.h>
int c_s(char*, char*);
typedef struct
{
char constab[30];
char vicwit[15];
char witdet[200];
char incdest[300];
char comp1[15];
char comp2[200];;
} sheetstore;
#define ARRAYLEN 2
sheetstore a[ARRAYLEN];
FILE *fp;
int main()
{
int i, a;
char wit[10] = "witness";
char yes[10] = "yes";
char comp1[10];
fp = fopen("sheetstore.dat","a+");
printf("Hate crime reporting system\n\n\n");
printf("If the crime you are reporting is an emergency,\nplease call 999, do not proceed any further with this form\n\n\n\nPlease press enter to confirm you have read the above and continue\n");
char enter = 0;
while (enter != '\r' && enter != '\n') { enter = getchar(); }
for( i=0; i<ARRAYLEN ; i++)
{
printf("Which police constabulary did the offence take place in?\n\n");
scanf("%s", a[i].constab);
printf("Are you a victim or witness of the crime?\nPlease answer victim/witness\n\n");
scanf("%s", a[i].comp1);
int res1 = (strcmp (comp1, wit));
if(res1 == 0){
printf("Please enter the details including phone number and address of any other witnesses that were present\n");
}
scanf("%s", a[i].witdet);
else{
printf("Where did the incident take place?\nIf in a house please provide the full address including postcode\n");
scanf("%s", a[i].incdest);
}
fwrite(&a[i], sizeof(a), 1, fp);
}
fclose(fp);
fopen("sheetstore.dat", "r");
for(i=0; i<ARRAYLEN; i++)
{
fread(&a[i], sizeof(a), 1, fp );
printf("Which police constabulary did the offence take place in? : %s\n", a[i].constab);
printf("Are you a victim or witness of the crime? : %s\n", a[i].comp1);
printf("Please enter the details including phone number and address of any other witnesses that were present : %s\n", a[i].witdet);
printf("Where did the incident take place? : %s\n", a[i].incdest);
}
fclose(fp);
return 0;
}

the main issue that i saw in your code, is that you shadowed the array a (sheetstore a[ARRAYLEN];) by declaring an int with the same name in your main().
you also had a scanf stament mislocated.
i fixed your code and put in a comment for every change - now, i don't persume to check the functionality of your code but at least this will compile and hopefully will give you a better understanding where you were wrong - from here it is up to you:
#include<stdio.h>
#include<string.h>
int c_s(char*, char*);
typedef struct
{
char constab[30];
char vicwit[15];
char witdet[200];
char incdest[300];
char comp1[15];
char comp2[200];;
} sheetstore;
#define ARRAYLEN 2
sheetstore sheetArr[ARRAYLEN]; //change this 'a' to avoid shadowing by the decleration on 'int a' in main
FILE *fp;
int main()
{
int i, a;
char wit[10] = "witness";
char yes[10] = "yes";
char comp1[10];
fp = fopen("sheetstore.dat","a+");
printf("Hate crime reporting system\n\n\n");
printf("If the crime you are reporting is an emergency,\nplease call 999, do not proceed any further with this form\n\n\n\nPlease press enter to confirm you have read the above and continue\n");
char enter = 0;
while (enter != '\r' && enter != '\n') { enter = getchar(); }
for( i=0; i<ARRAYLEN ; i++)
{
printf("Which police constabulary did the offence take place in?\n\n");
scanf("%s", sheetArr[i].constab);//change name from 'a'
printf("Are you a victim or witness of the crime?\nPlease answer victim/witness\n\n");
scanf("%s", sheetArr[i].comp1);//change name from 'a'
int res1 = (strcmp (sheetArr[i].comp1, wit));//compare with the value set in the struct
if(res1 == 0){
printf("Please enter the details including phone number and address of any other witnesses that were present\n");
/*this scanf should be inside the brackets of 'if(res1 == 0)' */
scanf("%s", sheetArr[i].witdet);//change name from 'a'
}
else{
printf("Where did the incident take place?\nIf in a house please provide the full address including postcode\n");
scanf("%s", sheetArr[i].incdest);//change name from 'a'
}
fwrite(&sheetArr[i], sizeof(sheetstore), 1, fp);//write a single struct
}
fclose(fp);
fopen("sheetstore.dat", "r");
for(i=0; i<ARRAYLEN; i++)
{
fread(&sheetArr[i], sizeof(sheetstore), 1, fp );//read a single struct
printf("Which police constabulary did the offence take place in? : %s\n", sheetArr[i].constab);
printf("Are you a victim or witness of the crime? : %s\n", sheetArr[i].comp1);
printf("Please enter the details including phone number and address of any other witnesses that were present : %s\n", sheetArr[i].witdet);
printf("Where did the incident take place? : %s\n", sheetArr[i].incdest);
}
fclose(fp);
return 0;
}

In addition to some useful comments posted above (meaningful variable names, line width not to be too long for readability), in general sense, your problem is due to two thing: in the body of the main function you declare an int a which is used instead of your global array a[ARRAYLEN]. Hence, you cannot refence a[i].incdet etc. Just comment or remove the int a from the main function. Secondly, your scanf("%s", a[i].witdet); should be in the body of the if statement above according to the program logic. I you do these two changes, the code will compile. However if you pass -Wall -Werror to the compiler, it will yields an error like error: unused variable ‘yes’ [-Werror=unused-variable]
char yes[10] = "yes";. Just comment this line to avoid using uncessary memory space on the stack.

The following proposed code:
corrects the first 50+ lines of your code.
Please correct your posted code so it cleanly compiles
for flexibility, separates the definition of the struct from the typedef of the struct
properly checks for error indications from system functions
honors the right margin (usually 72 or 80 characters)
replaces the CPU cycle intensive calls to printf() with calls to puts() when appropriate
This is only a guide for the first 50 lines of the OPs code. It is not a complete code replacement.
and now the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// prototypes
int c_s(char*, char*);
struct sSheet
{
char constab[30];
char vicwit[15];
char witdet[200];
char incdest[300];
char comp1[15];
char comp2[200];
};
typedef struct sSheet sheetstore;
#define ARRAYLEN 2
sheetstore a[ARRAYLEN];
FILE *fp;
int main( void )
{
int i;
char wit[10] = "witness";
//char yes[10] = "yes";
char comp1[10];
fp = fopen("sheetstore.dat","a+");
if( !fp )
{
perror( "fopen for appending to 'sheetstore.dat' failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
puts("Hate crime reporting system\n\n\n");
puts("If the crime you are reporting is an emergency,\n"
"please call 999, "
" do not proceed any further with this form\n\n\n\n"
"Please press enter"
" to confirm you have read the above and continue\n");
int enter = 0;
while (enter != '\r' && enter != '\n')
{
enter = getchar();
}
for( i=0; i<ARRAYLEN ; i++)
{
puts("Which police constabulary did the offence take place in?\n\n");
if( scanf("%29s", a[i].constab) != 1)
{
fprintf( stderr, "scanf for which police constabulary failed" );
fclose( fp ); // cleanup
exit( EXIT_FAILURE );
}
// implied else, scanf successful

Related

how to check variable validity and how to send array of structure to function?

I'm working in library system, I've a lot of things going on:(. In addBook function I'm trying to add book information into Array of structure. First I don't know how to set a statement to check all the validity of title, author, isbn and others. I tried to write a statement but it wont work so I removed it! and didn't call the functions since I don't know how to make them work! secondly I want to send the book information to a file so I can store them inside the file and sort alphabetically. whenever I try to send the array and check the txt file it print the address please help :( I'm trying to keep it simple as possible as I can
#include <stdio.h>
#include <stdlib.h>
#define MAX_ISBN 11
#define MIN_ISBN 9
#define MAX_YEAR 2021
#define MIN_YEAR 1500
#define MAX_DAY 31
#define MIN_DAY 1
#define MAX_MONTH 12
#define MIN_MONTH 1
#define MIN_ISBN 9
#define MAX_Title 80
#define MAX_Author 80
struct Book{
int ISBN[MAX_ISBN], Edition[500], Year[MAX_YEAR],DD[MAX_DAY], MM[MAX_MONTH];
char Title[MAX_Title];
char Author[MAX_Author];
};
/*Check_Title function will check user input if it's a valid title or not! */
int Check_Title(char *Title){
int valid_Title = 1;
int len = 0;
int i= 0;
len = strlen(Title);
for(i =0; i <len ; i++)
{
if( Title[i] == "##$%^&*()}{[ ]")
return 0;;
}
return 1;
}
/*Check_Author function will check user input if it's a valid Author name or not! */
int Check_Author(char *Author){
int valid_Name = 1;
int len = 0;
int i= 0;
len = strlen(Author);
for(i =0; i <len ; i++)
{
if( !(isalpha(Author[i])) && (Author[i] != ' '))
{
valid_Name = 0;
break;
}
}
return valid_Name;
}
int Check_Date(int *DD, int *MM,int *YYYY){
if(DD[MAX_DAY] > MAX_DAY || DD[MIN_DAY]< MIN_DAY)
return 0;
if(MM[MAX_MONTH] >31 || MM[MIN_DAY]<1)
return 0;
if(YYYY[MAX_YEAR]>MAX_YEAR || YYYY[MIN_YEAR]<MIN_YEAR)
return 0;
return 1; //if statement true return 1
}
int Check_ISBN(int *ISBN){
if(ISBN[MAX_ISBN] > MAX_ISBN || ISBN[MIN_ISBN] < MIN_ISBN);
return 0;
return 1; //if ISBN VALID
}
// This function is used to check file existence, every time if it's called
//the following functions is user choice to either add a book, delete, view, and view by year -> Switch cases
void addBook(){
system("cls"); //clearing black screen
int Title_Validity = 0, Name_Validity = 0, ISBN_Validity, Date_Validity = 0,n;
struct Book *insert = NULL;
FILE* ptr = fopen("stored.txt","w");
if (ptr == NULL){
printf("Error opening the file! \n");
exit(1);}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
printf("\n\t\t ========================================================================");
printf("\n\t\t ADD NEW BOOK ");
printf("\n\t\t ========================================================================");
printf("\n\n\t\t\tENTER YOUR DETAILS BELOW:");
printf("\n\t\t\t---------------------------------------------------------------------------\n");
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
printf("\t\tHow many Books would you like to insert? ");
scanf("%d", &n);
for(int i = 0; i<n; i++){
insert = (struct Book*)calloc(n,sizeof(struct Book));
//Inputing Title & Check Title validity
//do{
printf("\n\t\t\tBook Title : ");
fflush(stdin);
fgets(insert[i].Title, MAX_Title, stdin);
/*Title_Validity = Check_Title(&insert[MAX_Title].Title);
if(Title_Validity){
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_");
printf("\t\t\t\t\t\t \t\t Invalid Input ! please try again! \n\t\t\t and make sure to not use any digits or special characters! \n ");
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_*_");
}
}while(Title_Validity);*/
//Inputing Author
printf("\n\t\t\tBook Author : ");
fflush(stdin);
fgets(insert[i].Author, MAX_Author, stdin);
//Inputing ISBN
//do{
printf("\n\t\t\tBook ISBN : ");
scanf("%d", &insert[i].ISBN);
// fflush(stdin);
//fgets(insert[i].ISBN, MAX_ISBN, stdin);
/* ISBN_Validity = Check_ISBN(&insert[MAX_ISBN].ISBN);
if(ISBN_Validity == 0){
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_");
printf("\t\t\t\t\t\t \t\t Invalid Input ! please try again! \n\t\t\t and make sure to not to not accedes the range 9~11! \n ");
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_*_");
}
}while(ISBN_Validity!=0);*/
//Inputing Edition
printf("\n\t\t\tBook Edition (only digits acceptable) : ");
scanf("%d", &insert[i].Edition);
//Inputing Date
printf("\n\t\t\tBook Date [DD MM YYYY] : ");
scanf("%d%d%d", &insert[i].DD,&insert[i].MM,&insert[i].Year);
printf("\n\t\t ========================================================================");
printf("\n\t\t The book %s has been added to the library.", insert[i].Title );
printf("\n\t\t ========================================================================");
}
//
Sort_Save(n,&insert[x].Title,&insert[x].Author,&insert[x].ISBN,&insert[x].Edition,&insert[x].DD,&insert[x].MM,&insert[x].Year);
return;
}
void Sort_Save(int n,char Title[MAX_Title],char Author[MAX_Author], int ISBN[MAX_ISBN], int Edition[], int day[MAX_DAY], int month[MAX_MONTH], int year[MAX_YEAR]){
int i;
struct Book *st;
FILE* fptr = fopen("sorted.txt", "w");
if(fptr == NULL){
printf("Error opening file! \n");
exit(1);
}
for(i=0; i<n; i++){
fprintf(fptr,"%s %s %d %d %d %d %d",st[i].Title,st[i].Author,st[i],st[i].ISBN,st[i].Edition,st[i].DD,st[i].MM,st[i].Year);
fprintf(fptr,"\n");
}
printf("\n");
fclose(fptr);
}
Since you're asking the users how much books they want to add, you have to allocate the block of memory only once, best right after (before the loop) and certainly not again and again in the loop, where it gets initialized with '0' (zero, that's what calloc does).
And opening a file with the mode "w" truncates that file to zero length, i don't think that this is what you want. And why do you open it, when you do not access it, neither for reading nor for writing?
After scanning, you call the Sort_Save function with a bunch of useless parameters (where does the variable 'x' come from?). You should declare the function like this:
int sortSave(struct Book *books, size_t size)
and pass the allocated block (insert) with the specified size (n).
If you want to sort your library, then you should open the existing database for read first ("r"), then read all the stored values into an array, append the new data to that array, call 'qsort' (see man qsort), specify your compare function (where you specify by which parameter your library should be sorted), close the file, open it again in write mode ("w") and finally write all your (sorted) data into that file.
Do not to forget to flush and close the file, nor to free the allocated blocks of memory.
Edit:
As a hint, seperate code from design. First make sure your code works as expected, then add all the fancy stuff, best as a seperate function.

C compiler error: undefined reference to function

After I execute the exe I get this error :
undefined reference to `StudentScan'
error: ld returned 1 exit status|
Note: I'm bad and new to coding so don't mind my bad coding please^^
Note2: I'm just messing with random functions.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main() {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
return 0;
}
The posted code has defined StudentScan() within main(). But nested function definitions are not allowed in C. This should generate a compiler warning, such as:
warning: ISO C forbids nested functions [-Wpedantic]
void StudentScan(int i, struct student list[])
Pay attention to all compiler warnings and fix them. If no warning is seen when compiling this code, turn up the level of compiler warnings. On gcc, I suggest to always use at least gcc -Wall -Wextra, and I always add -Wpedantic. The -Wpedantic is needed with gcc to see a warning for this. Some compilers, and gcc is one of these, do support nested function definitions as a compiler extension. Still, this feature is nonstandard, and it is best to not rely on it.
The fix is simple: move the definition of StudentScan() out of main():
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
Also note that you should always specify maximum widths when reading strings using scanf() family functions with %s or %[] to avoid buffer overflow. For example:
scanf("%19s", list[i].firstName);
Note that 19 is used, even though the firstName field is an array of 20 char values. Remember that one space must be reserved for the \0 terminator. And since you are using %s to read a string into the AverageNum field, you should also have:
scanf("%1s", list[i].AverageNum);
That is, this field can only hold one digit. If the intention is to hold two digits, this field must be changed within the struct to: char AverageNum[3].
And while we are discussing scanf(), note that this function returns the number of successful assignments made during the function call. If no assignments are made, 0 is returned. This return value should always be checked. Consider: if the user mistakenly enters a letter when a digit is expected, nothing is stored in the intended variable. This may lead to undefined behavior. You may try something like this to validate numeric input:
printf ("\nEnter the host of students: ");
while (scanf ("%d ", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
This code asks the user to enter input again if a number is not entered when expected. Note that if the user does enter a non-digit, this character remains in the input stream and must be cleared before attempting to process more user input. The while loop is a typical construction which accomplishes this task.
Edit
Based on comments made by the OP, here is a modified version of the posted code. This version uses a float value instead of a character array for the AverageNum field of the struct. A floating-point type may be more useful than an integer type for storing averages. It is usually best to use double for floating-point values, but in this case it looks like AverageNum has little need for precision (the char array was intended to hold only two digits); float is probably sufficient for this use. If a different type is desired, it is simple enough to modify the code below.
Some input validation is implemented, but note that more could be done. The user is prompted to enter a number when non-numeric input is found where numeric input is expected. The input stream is cleaned with the while loop construction after such an input mistake; it would be good to remove this code to a separate function called clear_input(), for example.
If the user signals end-of-file from the keyboard, scanf() will return EOF; the code below chooses to exit with an error message rather than continue with malformed input in this case. This could also occur with input redirected from a file, and this condition may need to be handled differently if such input is expected.
The loop that populated the list[] array seemed to be operating inefficiently, asking for AverageNum twice in each pass. This has been streamlined.
Note that the call to malloc() can be rewritten as:
studentp = malloc(length * sizeof *studentp);
This is a very idiomatic way of writing such an allocation. Here, instead of using an explicit type as the operand of sizeof, that is, instead of sizeof (struct student), the variable which holds the address of the allocation is used. sizeof only uses the type of the expression *studentp, so this variable is not dereferenced here. Coding this way is less error-prone and easier to maintain when types change during the maintenance life of the code.
Yet, it is unclear why memory is allocated for studentp in the first place. In the posted code, both the firstName and AverageNum fields are filled for members of the dynamically allocated studentp in calls to StudentScan() in a loop; the same loop fills the AverageNum field of the members of list[] (a different array of structs) with different input. There seems to be no need for one of these arrays of student structs; I have commented-out the dynamically allocated array in favor of the statically allocated version.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
float AverageNum;
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
// struct student *studentp;
printf ("\nEnter the host of students: ");
while (scanf ("%d", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
struct student list[length];
/* This is fine */
// studentp = malloc(length * sizeof (struct student));
/* But this is better */
// studentp = malloc(length * sizeof *studentp);
// if (studentp == NULL)
// {
/* Not wrong, but... */
// printf("Out of memory!");
// return 0;
// fprintf(stderr, "Allocation failure\n");
// exit(EXIT_FAILURE);
// }
for(i = 0; i < length; i++) {
StudentScan(i, list);
}
/* Code to display results here */
// free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{
putchar('\n');
printf("Enter first name: ");
if (scanf("%19s", list[i].firstName) != 1) {
puts("Input error");
exit(EXIT_FAILURE);
}
printf("Enter average number: ");
while (scanf("%f", &list[i].AverageNum) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
}
You have to remove the scan function from the main. Also there is not a printstudent function you are declaring. You must remove /n from the printf and the scanf functions and place them accordingly. You can then test if your data are being added correctly in your struct with a simple loop.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
int main() {
int i=0;
int length;
struct student *studentp;
printf ("Enter the host of students:");
scanf ("%d", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
printf("Enter first name :");
scanf("%s", list[i].firstName);
printf("Enter average number: ");
scanf("%1s", list[i].AverageNum);
}
for(i = 0; i< length; i++){
printf("number of host is: %d , his/her first name: %s , his/her avg number: %s \n", i, list[i].firstName, list[i].AverageNum);
}
free (studentp);
return 0;
}

How to do input validation using a struct variable array in C

I've made a small program to write Student names and final grades to a file and then read that file and print it. I'm still new to C and I'm playing with input validation, but I'm running into a problem when it comes to using it with a struct. When I run my function it checks for cases just fine, but it does not store the right input into studentFinalGrades. So when I go to print the file, it never stored the input for final grades. Any ideas on how I can fix this? Or advice on how to do input validation another way?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
//struct of students
struct students
{
char name[50];
char lastName[50];
char studentFinalGrade[50];
};
//myfunctions (at bottom of main)
char check_letterGrade(void);
void clear_input_buffer(void);
int main()
{
// in check_letterGrade
char input;
if (input != '\n')
{
clear_input_buffer();
}
//dynamic array
struct students a[2],b[2];
FILE *fptr;
int i;
//opens file.txt
fptr=fopen("file.txt","wb");
//Loop to enter in all student data and grades at once (only did 5 students because it takes forever to fill it out)
for (i=0;i<2;++i)
{
fflush(stdin);
printf("Enter Student Name: ");
scanf("%s",&a[i].name);
printf("Enter Student Last Name: ");
scanf("%s",&a[i].lastName);
printf("What is students Final Grade?:");
check_letterGrade();
// scanf("%s",&a[i].studentFinalGrade);
}
//writes user input to a file and then closes file
fwrite(a,sizeof(a),1,fptr);
fclose(fptr);
//opens and reads file
fptr=fopen("file.txt","rb");
fread(b,sizeof(b),1,fptr);
//Printing all Studens names and grades entered into the file.
int j = 0;
for (i=0;i<2;++i)
{
j ++;
printf("\nStudent %d :\n",j);
printf("Name: %s\nLast Name: %s\nFinal Grade: %s\n\n", b[i].name,b[i].lastName,b[i].studentFinalGrade);
}
fclose(fptr);//close file when done reading.
}//end main
//function to check user validation on correct letter grades entered.
char check_letterGrade(void)
{
char input;
int ch;
//If input is not all of these things then it will tell user to please enter a correct letter grade
// it will then check for new line (which should clear from the buffer and allow new entry) hopefully
while (scanf("%s", &input) != 1 || (input != 'A' && input != 'B'&& input != 'C'&& input != 'D'&& input != 'F'))
{
if (input != '\n') // only take leftover input if there is leftover input
{
while ((ch = getchar()) != '\n') ;
}
printf("Please enter a correct letter grade: ");
}
return input;
}
//clears buffer
void clear_input_buffer(void)
{
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
You don't get studentFinalGrades because you never store it anywhere. You made a function called check_letterGrade which return a single char that contains the grade. However, when you call that function from main, you never do anything with that return value. I suspect you meant to write something like:
a[i].studentFinalGrade = check_letterGrade();
You also need to change the definition of your struct. There you define studentFinalGrade as char[50], but you probably just mean char since you only need a single letter, right?
I realize you are new to C, but your program really contains a lot of strange stuff. Actually, I'm surprised the above code even compiled for you, as scanf("%s",&a[i].name) ought to have given you a syntax error. You may want to invest in a book to learn C and work out the examples first.

Segmentation fault and realloc(): invalid next size: [duplicate]

This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
I have a program and gets information from the keyboard and puts them into a struct and then write the struct to a file.
However, when I'm reallocating memory for the second time it seems to fail for no reason. Also, if I enter more than 1 person's information, the program fails in the end with a seg fault. The program runs fine if I enter just 1 person's information.
Thanks.
// Program
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct person person;
struct person {
char fname[20];
char lname[20];
int num;
};
int main(void){
int size = 0;
int count = 0;
person* listofperson = NULL;
char answer = 'n';
FILE* myfile;
do{
char* buf = (char*)malloc(sizeof(char)*50);
printf("Please enter the person's first name: \n");
fgets(buf, 50, stdin);
if(count == size){
size += 2;
listofperson = (person*)realloc(listofperson, (size_t)(sizeof(person)*size));
}
strncpy((listofperson+count)->fname, buf, 50);
printf("Please enter the person's last name: \n");
fgets(buf, 50, stdin);
strncpy((listofperson+count)->lname, buf, 50);
printf("Please enter the person's number: \n");
fgets(buf, 50, stdin);
sscanf(buf, "%d", &((listofperson+count)->num));
free(buf);
count++;
printf("Do you want to enter another one?\n");
answer = getchar();
getchar();
}while(tolower(answer) != 'n');
myfile = fopen("myfile", "a");
for(int i = 0; i < count; i++){
fprintf(myfile, "%s", (listofperson+i)->fname );
fprintf(myfile, "%s", (listofperson+i)->lname );
fprintf(myfile, "%d\n", (listofperson+i)->num );
}
fclose(myfile);
myfile = NULL;
free(listofperson);
}
For one thing, the people who are saying that realloc() doesn't work with a NULL pointer aren't speaking the truth. The behavior is documented here for C++ and here for C, it just works like malloc() in the case of a NULL pointer passed. Although I would agree that it is bad practice to assign memory that way.
You are not checking for errors in your malloc() and realloc() calls, they are not guaranteed to succeed, so you shouldn't assume they will.
In this case you shouldn't name your point to a person node "list of people", as this convention may be confused with a linked list. I would strongly reccomend you attempt to implement a linked lists for this programming case, since that is basically how you are working with your data anyways. For a tutorial on linked lists, see this link.
You should change the name of the file in fopen() to include a .txt extension. Otherwise the system will not know what the file type is.
change
struct person {
char fname[20];
char lname[20];
int num;
};
to
struct person {
char fname[50];
char lname[50];
int num;
};
Which is too small, it's already pointed out by ouah. It is necessary to align the value of one.
The error message indicates that the memory is destroyed beyond the area secured.

C programming - Scanf/gets unexpected behaviour

The program is supposed to do the following:
Add Major details
Add University details
Add major to university
Update major cost
Search for a major
Before completing the main function I'm facing a problem:
When I use scanf instead of gets in the functions, It asks 2 questions without letting me to fill the previous one. ex: Enter university's name: Enter university's address:
And when I used gets I faced the same problem.
If there's any other mistake please hint me
Thanks in advance!
#include <stdio.h>
#include <string.h>
//Define Structures
typedef struct {
char name[30];
char department[30];
int nb_students;
int credits;
float cost;
char adv_name[15];
}Major;
typedef struct {
char name[50];
char address[30];
Major uni_majors[50];
int nb_majors;
}University;
// Define Functions Prototypes
Major majors_function();
University university_function();
void AddMajor(Major *major,University *university);
University UpdateMajor(char nameMajor[], University U, float newCost);
void SearchMajor(Major major,University university);
int main(int argc, const char * argv[])
{
Major new_major;
University new_university;
new_major = majors_function();
new_university = university_function();
return 0;
}
// Fills The Major Details Function
Major majors_function() {
Major major;
printf("Enter Major name: ");
gets(major.name);
printf("Enter Department name: ");
gets(major.department);
printf("Enter number of students: ");
scanf("%d",&major.nb_students);
printf("Enter number of credits: ");
scanf("%d",&major.credits);
printf("Enter the cost of credit: ");
scanf("%f",&major.cost);
printf("Enter the Advisor's Last Name: ");
scanf("%s",major.adv_name);
return major;
}
// Fills the university details Function
University university_function() {
University university;
printf("Enter university's name: ");
gets(university.name);
printf("Enter university's address: ");
gets(university.address);
printf("Enter number of majors in this univeristy: ");
scanf("%d",&university.nb_majors);
return university;
}
// Adds Major to a university
void AddMajor(Major *major,University *university) {
university->nb_majors = 0;
if(university->nb_majors <50) {
university->uni_majors[university->nb_majors] = *major;
}
else
printf("No Available space");
university->nb_majors++;
}
// Update Major's Cost
University UpdateMajor(char nameMajor[], University U, float newCost) {
if(strcmp(nameMajor,U.uni_majors->name)) {
U.uni_majors->cost = newCost;
}
return U;
}
// Searches for a major in a university
void SearchMajor(Major major,University university) {
if(strcmp(university.uni_majors->name,major.name))
printf("The total cost of this major is %.2f",(major.cost*major.credits));
else
printf("There is no such major!");
}
When using scanf to scan strings or characters. you might want to skip leading whitespace (like newlines). This can simply be done by asking scanf to skip whitespace, by adding a single space in front of the format code, like
scanf(" %s",major.adv_name);
/* ^ */
/* | */
/* Note space */
You might want to read more about scanf and its siblings on e.g. this reference page.
NEVER NEVER NEVER NEVER NEVER NEVER NEVER NEVERN NEVER NEVER use gets, not for homework assignments, even for toy code. It was deprecated in the 1999 standard and has been removed from the 2011 standard. It will introduce a major point of failure in your program. Use fgets instead:
fgets( major.name, sizeof major.name, stdin );
and check the return value to make sure it succeeded.
Alternately, you can use scanf, but you'll want to specify the max buffer size in the conversion specifier:
scanf( "%29s", major.name ); // leave 1 space for the 0 terminator
The only problem with this is that the size has to be hardcoded; you can't pass it as an argument like you do with printf. Alternately, you can build the format string at runtime, like:
char fmt[5]; // good for %0s to %99s
sprintf( fmt, "%%%zus", sizeof major.name );
...
scanf( fmt, major.name );
Frankly, you're better off using fgets for everything, including the numeric inputs.
char inbuf[10];
char *chk;
// Read the number of students as text, then convert with the
// strtol library function; allows us to catch and reject
// non-numeric input.
printf( "Enter number of students: " );
fflush( stdout );
if ( fgets( inbuf, sizeof inbuf, stdin ) != EOF )
{
int tmp = (int) strtol( inbuf, &chk, 10 );
if ( isspace( *chk ) || *chk == 0 )
{
major.nb_students = tmp;
}
else
{
fprintf( stderr, "%s is not a valid number\n", inbuf );
}
}

Resources