C structures displaying numbers rather than user data - c

Kindly help me debug this code. It is not displaying the correct data. The following program is supposed to get book details from the user, dynamically allocate memory to them and display them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int main()
{
struct books *b;
b = (struct books*)malloc(sizeof(struct books));
int command, flag = 0;
int n=0, i;
while(flag == 0)
{
printf ("1. Add Book\n");
printf ("2. View Books\n");
printf ("3. Quit\n");
scanf("%d", &command);
if (command == 1)
{
printf ("Enter Name\n");
//scanf("%d", &(b+i)->name);
scanf(" ");
gets((b+i)->name);
printf ("Enter Author\n");
//scanf("%d", &(b+i)->author);
scanf(" ");
gets((b+i)->author);
printf ("Enter Year Published\n");
scanf("%d", &(b+i)->year_published);
n=n+1;
i=n;
} else if (command == 2)
{
for(i=0; i<n; i++)
{
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
}
} else if (command == 3)
{
flag = 1;
} else
{
printf ("Invalid choice!\n");
}
}
}
The following is problem5.h header file that has the structure books. Initially I didn't declare the variables in array since I didn't want to use much memory. But I had to due to many errors.
#define PROBLEM3_H_INCLUDED
typedef struct books{
char *name[30];
char *author[30];
int year_published;
};
#endif // PROBLEM3_H_INCLUDED
When I print I am getting random numbers instead of the data the user entered.

The overall design of your code is wrong.
This is basically what you want.
I made following changements:
using meaningful variable names
changed struct book so the structure can contain one book. Also renamed it from struct books to struct book because the structure contains only one book.
allocating memory properly
using books[numberofbooks].x instead of the less readable *(books + numberofbooks)->x
More explanations in the comments.
#include <stdio.h>
#include <stdlib.h>
struct book {
char name[30];
char author[30];
int year_published;
};
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;
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
}
else if (command == 2)
{
for (int 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
{
printf("Invalid choice!\n");
}
}
}
There is still room for improvement though:
error checking for realloc
error checking for interactive I/O
not using the deprecated and dangerous gets
and certainly a few other things

b = (struct books*)malloc(sizeof(struct books));
Here, you are allocating memory for only one instance of struct books , But you are accessing multiple instances of struct books.
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
For i>=1 (b+i) is not defined, because you did not allocate memory for it. You have allocated memory for only (b+0).
int n=0, i;
gets((b+i)->name);
Here, i has not been initiliazed.

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;
}

Buffer overflow or something else

I am creating a program, about seat reservations. I was asked to use unsigned short and unsigned int for some of the variables, so that is why they are set like that.
I have a program that works ok. But when I transfer everything inside a function, everything seems to work ok, but inside my structure weird values start to be saved all over the place..
I only want to save the values of the file (from line 2 -> the end of file).
Because I have a structure that to be initialized I have first to read the txt file and numberofseats, I have am declaring this variable (passenger) 2 times..inside the function (local var) and in the main body..
Maybe this causes the problem?
If I don't use a function everything work fine!
So the problematic code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j,numberofseats,temp;
char platenr[8],selection,buff[60];
char firstname[20];
char lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
void readfile( void)
{
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);}
else
{
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s and number of seats is: %d", platenr, numberofseats);
PASSENGERS passenger[numberofseats];
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo)!=0)
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
printf("%s",passenger[temp-1].fullname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
}
}
int main(void)
{
readfile();
PASSENGERS passenger[numberofseats];
A variable called x in function foo has nothing to do with a variable called y in function bar. In other words: passenger in main and passenger in readfile are different variables. Changing one will not impact the other.
What you want is probably more like this:
int main(void)
{
PASSENGERS passenger[numberofseats];
readfile(passenger);
^^^^^^^^^
Pass array as a pointer
....
}
and
void readfile(PASSENGERS* passenger)
{
....
// REMOVE THIS: PASSENGERS passenger[numberofseats];
}
Beside that notice:
// Global variables gets zero initialized
int i,j,numberofseats,temp;
^^^^^^^^^^^^
Becomes zero at start up
but still you use it in main:
PASSENGERS passenger[numberofseats];
That is probably no what you really want.
Since you try to read the number of seats in the function, it seams you really want to use dynamic memory allocation. Like:
PASSENGERS* readfile()
{
.....
.....
PASSENGERS* p = malloc(numberofseats * sizeof(PASSENGERS));
.....
.....
return p;
}
int main(void)
{
PASSENGERS* passenger = readfile();
.....
.....
free(passenger);
return 0;
}
If you don't want dynamic allocation, you must move the input of numberofseats into main so it is done before declaring the array.
The problem is that you are declaring a local array in the function readfile(), and once this function terminates, it is lost. You need to be able to return the changes to main(). For that you have some options. One is that you may declare the array in main(), and change your function to void readfile(PASSENGERS passenger[]). In this case, you will do something like this:
int main()
{
PASSENGERS passenger[numberofseats];
readfile(passenger);
// more code
You will be basically passing a pointer to the memory location of the elements stored in the array, local to main(), and the function will fill the array, effectively returning the changes.
Another option is to dynamically allocate an array (with malloc() family) in the function, and make it return a pointer like PASSENGERS *readfile(void). This option may be more suitable if the number of seats is not known at compile time, so you need to dynamically grow or shrink the array when necessary. This option however, leaves you the burden of managing the memory manually, like free()'ing the allocated memory when you are done.
Since you say that you will read numberofseats from the file, the latter would be the better idea, so your code will look something like this:
PASSENGERS *readfile(void)
{
FILE *businfo;
PASSENGERS *passenger;
businfo = fopen ("bus.txt","r");
// do the checks, read the numberofseats
passenger = malloc(numberofseats * sizeof *passenger);
// read the values, fill the array
fclose(businfo); // do not forget to close the file
return passenger;
}
int main()
{
PASSENGERS *passenger = readfile();
// more code
free(passenger);
return 0;
}
Ok, so what I did, before starting to work on dynamic allocation is specify the max number of seats in the start of main, and from there I finished my code as follows. I have 2 warning messages though in lines 43, 109 that can't seem to be able to fix.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int i,j,numberofseats,temp;
char platenr[8],selection;
char firstname[20],lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
void readfile(PASSENGERS passenger[])
{ char buff[60];
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);}
else
{
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s, and Number of Seats is: %d.", platenr, numberofseats);
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo)!=0)
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
}
}
void countfreeseats(PASSENGERS passenger[]){
int freeseats = 0;
for (j=0; j<numberofseats; j++)
{
strcmp(passenger[j].fullname,"\0")==0 ? freeseats = freeseats + 1 : freeseats ;}
printf ("There are %d Free Seats in this Bus. \n", freeseats);
printf("Seats that are Available are:\n");
for (j=0; j<numberofseats; j++)
{if (strcmp(passenger[j].fullname,"\0")==0)
printf ("%u\n", passenger[j].seatnr);
}
freeseats = 0;
}
void changeData(PASSENGERS *target){
unsigned short tempdigit;
printf("Enter Passenger's first name:");
scanf("%s",firstname);
printf("Enter Passenger's last name:");
scanf("%s",lastname);
strcpy(target->fullname,firstname);
strcat (target->fullname, " ");
strcat(target->fullname,lastname);
printf("Enter Passenger's phone Nr:");
scanf("%s",phone);
i=0;
for (p=phone;*p!='\0';p++)
{
(target->phonenr[i])=*p -'0';
i++;
}
}
void searchpassenger(PASSENGERS passenger[], char selection)
{ char tempsel,tmpfirst[20],tmplast[20];
unsigned short tempphone[10];
if (selection == '1')
{ printf("Enter Passenger's first name:");
scanf("%s",tmpfirst);
printf("Enter Passenger's last name:");
scanf("%s",tmplast);
strcat (tmpfirst, " ");
strcat(tmpfirst,tmplast);
for (j=0;j<numberofseats;j++)
if (strcmp(passenger[j].fullname,tmpfirst)==0)
printf ("Passenger %s has Seat Nr #: %u\n",tmpfirst,passenger[j].seatnr);
}
else if (selection == '2')
{ printf("Enter Passenger's Phone Nr:");
scanf("%s",phone);
i=0;
for (p=phone;*p!='\0';p++)
{
(tempphone[i])=*p -'0';
i++;
}
for (j=0;j<numberofseats;j++)
{if (strcmp(tempphone,passenger[j].phonenr)==0)
printf("Passenger %s has Seat Nr %hd already Booked",passenger[j].fullname,passenger[j].seatnr);
}
}
}
void cancelSeat(PASSENGERS *target){
strcpy(target->fullname,"\0");
for (i=0;i<10;i++)
target->phonenr[i]=0;
printf("Seat Nr %d is now Free",temp);
}
void showList(PASSENGERS passenger[])
{
printf("The following Seats are Booked: \n Name, PhoneNr, SeatNr\n\n"); /*Emfanisi minimatos*/
for (i=0; i<numberofseats; i++)
if (strcmp(passenger[i].fullname,"\0")!=0)
{
printf("%s, ",passenger[i].fullname);
for (j=0;j<10;j++)
{printf("%hu",passenger[i].phonenr[j]);}
printf(", %u\n",passenger[i].seatnr);
}
}
void writeFile(PASSENGERS passenger[])
{
FILE * output; /* Dilosi onomatos arxeiou */
output = fopen("output.txt","w"); /*dimiourgia i eggrafi pano se iparxon arxeio me onoma output.txt, mesw tis parametrou w*/
fprintf(output,"%s %d \n",platenr,numberofseats); /* mesw tis fprintf eksagogi pinakidas kai epikefalidas "Diagramma leoforeiou" sto arxeio output.txt. Allagi grammis opou xreiazetai*/
for (i=0; i<numberofseats; i++)
{if (strcmp(passenger[i].fullname,"\0")!=0)
{
fprintf(output,"%s ",passenger[i].fullname);
fprintf(output,"%u ",passenger[i].seatnr);
for (j=0;j<10;j++)
fprintf(output,"%hu",passenger[i].phonenr[j]);
fprintf(output,"%s","\n");
}
}
fclose(output); /* Kleisimo arxeiou*/
printf("File Saved as Output.txt");
}
int main(void)
{
PASSENGERS passenger[53];
readfile(passenger);
do{
printf("\n\nNeo Sistima Katagrafis Thesewn Leoforeiou\n");
printf("Please make a selection:\n\n");
printf("0. Exit\n");
printf("1. Empty Seats \n");
printf("2. Book Specific Seat \n");
printf("3. Advanced Search of Booked Seats\n");
printf("4. Cancel Seat Booking\n");
printf("5. Show List of Booked Seats\n");
scanf(" %c",&selection);
if (selection=='1')
countfreeseats(passenger);
else if (selection=='2')
{
printf("Please give seat nr (between 1 and %d) that you want to book:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")!=0)
printf("Error: Seat is already booked");
else
changeData(&passenger[temp-1]);
}
else if (selection=='3')
{
char tempsel;
printf("Do you want to search with Name (1) or Phone Nr (2)?\n");
scanf(" %c",&tempsel);
searchpassenger(passenger,tempsel);
}
else if (selection=='4')
{
printf("Please give Seat Nr (between 1 and %d) that you want to Cancel Booking:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")==0)
printf("Error: Seat is already free");
else
cancelSeat(&passenger[temp-1]);
}
else if (selection=='5') /*Menu 6 - Emfanisi listas kratimenon thesewn taksinomimenon kata ayksonta arithmo*/
{
showList(passenger);
}
} while (selection!='0');
{
writeFile(passenger);
}
}

How do I add a contact to a phonebook program in C?

For my intro to programming class, we have to code a phonebook in C that lets users add contacts, as well as delete and display them. It also has to allocate and free memory as necessary (I tried to do this, but I honestly don't really know what I'm doing).
Anyway, I cannot figure out how to add a contact to the phonebook. I've pasted the relevant part of the program so far. It compiles, but it crashes every time I try to add a contact. Once I get this figured out, I think I can get the rest of the functions without too much trouble. If anyone could help me out, I'd really appreciate it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct entry {
char fname[20];
char lname[20];
char pnumber[20];
} entry;
// function prototypes
void addentry(int, entry*, char addfname[20], char addlname[20], char addpnumber[20]);
main() {
int selection = 0;
int inputtest = 1;
int pnum = 0; // keeps track of number of contacts
char addfname[20] = { '\0' };
char addlname[20] = { '\0' };
char addpnumber[20] = { '\0' };
entry *pcontacts;
pcontacts = (entry*)calloc(1, (sizeof(entry)));
if (pcontacts == NULL) {
printf("No memory is available.");
free(pcontacts);
return 0;
}
while (1) {
do {
printf("\nPhonebook Menu\n\n");
printf("1:\tAdd contact\n");
printf("2:\tDelete contact\n");
printf("3:\tDisplay contacts\n");
printf("4:\tExit\n");
printf("\nChoose an action (1-4): ");
scanf("%d", &selection);
if (selection < 1 || selection > 4) {
printf("Invalid input. Please enter an integer between 1 and 4.\n");
inputtest = 0;
}
if (selection == 4) {
free(pcontacts);
printf("\nThank you for using this phonebook.");
return 0;
}
switch (selection) {
case 1:
pnum++;
printf("\nEnter first name: ");
scanf("%s", addfname);
printf("Enter last name: ");
scanf("%s", addlname);
printf("Enter phone number (no spaces): ");
scanf("%s", addpnumber);
addentry(pnum, pcontacts, addfname[20], addlname[20], addpnumber[20]);
break;
}
} while (inputtest == 1);
}
}
void addentry(int pnum, entry *pcontacts, char addfname[20], char addlname[20], char pnumber[20]) {
pcontacts = (entry*)malloc(pnum * (sizeof(entry)));
if (pcontacts != NULL) {
strcpy(*pcontacts[pnum - 1].fname, addfname);
printf("\nContact has been added.");
} else {
printf ("No memory is available.\n");
}
}
You get strings from standard input with scanf, but you should tell scanf the maximum number of bytes to store to the destination arrays to avoid buffer overruns:
scanf("%19s", addfname);
...
scanf("%19s", addlname);
...
scanf("%19s", addpnumber);
The way you call addentry is incorrect:
addentry(pnum, pcontacts, addfname[20], addlname[20], addpnumber[20]);
You actually try to read the byte just after the end of addfname, addlname and addpnumber. You should instead pass the arrays themselves, that will be passed to the function addentry as pointers to their first bytes:
addentry(pnum, pcontacts, addfname, addlname, addpnumber);
addentry should reallocate the array with realloc. It should be passed a pointer to the array pointer to it can update the pointer in main.
addentry does not copy the strings correctly: it only copies one, but with a syntax error.
Here is a corrected version:
void addentry(int, entry**, char addfname[20], char addlname[20], char addpnumber[20]);
int main(void) {
int selection = 0;
int inputtest = 1;
int pnum = 0; // keeps track of number of contacts
char addfname[20];
char addlname[20];
char addpnumber[20];
entry *pcontacts = NULL;
for (;;) {
do {
printf("\nPhonebook Menu\n\n");
printf("1:\tAdd contact\n");
printf("2:\tDelete contact\n");
printf("3:\tDisplay contacts\n");
printf("4:\tExit\n");
printf("\nChoose an action (1-4): ");
scanf("%d", &selection);
if (selection < 1 || selection > 4) {
printf("Invalid input. Please enter an integer between 1 and 4.\n");
inputtest = 0;
}
if (selection == 4) {
free(pcontacts); /* OK for NULL */
printf("\nThank you for using this phonebook.");
return 0;
}
switch (selection) {
case 1:
printf("\nEnter first name: ");
scanf("%19s", addfname);
printf("Enter last name: ");
scanf("%19s", addlname);
printf("Enter phone number (no spaces): ");
scanf("%19s", addpnumber);
addentry(pnum, &pcontacts, addfname, addlname, addpnumber);
pnum++;
break;
}
} while (inputtest == 1);
}
}
/* add an entry at position pnum */
void addentry(int pnum, entry **pp, char addfname[20], char addlname[20], char pnumber[20]) {
entry *pcontact = *pp;
pcontacts = realloc(pcontacts, (pnum + 1) * sizeof(entry));
if (pcontacts != NULL) {
*pp = pcontacts; /* update pointer in main */
strcpy(pcontacts[pnum].fname, addfname);
strcpy(pcontacts[pnum].lname, addlname);
strcpy(pcontacts[pnum].pnumber, addpnumber);
printf("\nContact has been added.");
} else {
printf ("No memory is available.\n");
}
}

C ints are being changed into large numbers

I have a program that reads data from a text file and puts the data into a structure to make a "person". All works apart from the integers that get read are not the correct value. They come out as very large numbers.
Thanks for your help.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "structs.h"
int main(void)
{
FILE *fp = NULL;
char userInput = ' ';
struct strPerson people[1];
int i;
int aPeople = 2;
int menuSelect;
while (fp == NULL)
{
fp = fopen("test", "r"); // Open File To Read
if (fp == NULL)
{
perror("Error While Loading File\n");
}
else
{
for(i = 0; i < aPeople; i++)
{
fscanf(fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%d%d%d%d%d%d%d%d%d%d",
people[i].perSurname,
people[i].perForname1,
people[i].perForname2,
people[i].perGender,
people[i].perUni.perAwardTitle,
people[i].perHomeAddress.perHAddress1,
people[i].perHomeAddress.perHAddress2,
people[i].perHomeAddress.perHAddress3,
people[i].perHomeAddress.perHAddress4,
people[i].perLocalAddress.perHAddress1,
people[i].perLocalAddress.perHAddress2,
people[i].perLocalAddress.perHAddress3,
people[i].perLocalAddress.perHAddress4,
people[i].perUni.perDOE.nDay,
people[i].perUni.perDOE.nMonth,
people[i].perUni.perDOE.nYear,
people[i].perUni.perDOG.nDay,
people[i].perUni.perDOG.nMonth,
people[i].perUni.perDOG.nYear,
people[i].perUni.perRegNumber,
people[i].strDOB.nDay,
people[i].strDOB.nMonth,
people[i].strDOB.nYear);
}
system("clear");
}
}
while (userInput != 'g')
{
system("clear");
printf(" |User System|\n"
"|------------------------------|\n"
"|------------------------------|\n"
"|A) Save Current Data To A File|\n"
"|B) Enter Details |\n"
"|C) View Details |\n"
"|D) Amend Details |\n"
"|E) Search by Award Title |\n"
"|F) Search by Surname |\n"
"|G) Shut Down |\n"
"|------------------------------|\n");
printf("Enter Function: ");
userInput = getchar();
getchar();
if (userInput == 'c')
{
for(i = 0; i < aPeople; i++)
{
printf("%d) %s %s\n", i + 1, people[i].perForname1, people[i].perSurname);
}
printf("Select Person To View Details: ");
scanf("%d", &menuSelect);
getchar();
printf("Name: %s %s %s\n",people[menuSelect-1].perForname1,
people[menuSelect-1].perForname2,
people[menuSelect-1].perSurname);
printf("DOB: %d %d %d\n", people[menuSelect-1].strDOB.nDay,
people[menuSelect-1].strDOB.nMonth,
people[menuSelect-1].strDOB.nYear);
getchar();
}
}
}
You did not provide the definition of struct strPerson.
Yet it is obvious that you are not passing the address of the integers you attempt to parse with fscanf. This invokes undefined behaviour, and it is quite surprising that your program actually runs at all.
You should compile with warnings enabled to detect such common mistakes: gcc -Wall -W -Werror is your friend.
Furthermore, you should test the return value of fscanf to verify how many fields have been parsed. Any field not parsed has an indeterminate value.
Also you are attempting to parse 2 structures, but the array of structures only has 1 entry.

Resources