I'm trying to write a simple phone book program. I have completed the first function and according to I observe it works without error. However, in second function (which is ""display()"") I can't show to user after I enter person knowledge. I'm working with binary mode. What the problem is in second function I couldn't understand. If you examine and help I'll be satisfied. Thanks in advance.
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() function
#include <malloc.h> // "malloc" library contains of malloc() function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
#include <io.h> // "io" library contains of filelength() function
struct personKnowledge
{
char name[32];
char surname[32];
char number[32];
};
FILE *ptrFILE,*ptrFILE1;
long int recordLength,totalRecordLength,location;
static int counter = 0;
int number,totalRecordNumber;
void newRecord();
void display();
void deletE();
void add();
void update();
int main()
{
int choice;
do
{
printf("\n\t\t --- Phone Book Program ---");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord();
break;
}
case 2:
{
display();
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
return 0;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
break;
}
}
} while (choice >= 1 && choice <= 6);
return 0;
}
void newRecord()
{
if ((ptrFILE = fopen("Phone Book.dat", "wb")) == NULL)
{
printf("The file couldn't open\n");
exit(0);
}
system("cls"); // Screen is being cleaned
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
recordLength = sizeof(p); // size of p
printf("|| For the %d. person ||\n", counter+1);
printf("\n\Express person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Express %s's surname: ", p->name);
gets(p->surname);
printf("Express %s's number: ", p->name);
gets(p->number);
fwrite(&(*p), recordLength, 1, ptrFILE);
printf("\nPlease wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed succesfully. *-*\n");
free(p);
counter++;
fclose(ptrFILE);
}
void display()
{
if ((ptrFILE = fopen("Phone Book.dat", "rb")) == NULL)
{
printf("The file couldn't open\n");
exit(0);
}
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
fflush(stdin);
recordLength = sizeof(s);
totalRecordLength = filelength(fileno(ptrFILE));
totalRecordNumber = totalRecordLength / recordLength;
printf("\n\nExpress person record number which you search: ");
scanf("%d", &number);
location = (number - 1)*recordLength;
fseek(ptrFILE, location, SEEK_SET);
fread(&(*s), recordLength, 1, ptrFILE);
printf("\n*-* Person knowledge which you search *-*\n");
Sleep(750);
printf("Name: %s\n", s->name);
printf("Surname: %s\n", s->surname);
printf("Number: %s\n", s->number);
free(s);
fclose(ptrFILE);
}
recordLength = sizeof(p);
is wrong, this is the size of the pointer which is normally 4 on a 32 bit system and 8 on a 64 bit syste.
you need
recordLength = sizeof(*p);
or
sizeof(struct personKnowledge);
which gives you the size of the structure pointed by p.
Related
I've been writing a small program that will allow the user to read a file, create a small "database" and the ability to create / delete entries, etc. When I try to use the
realloc()
function, it crashes.
Not sure if I am doing something wrong, probably am though, since I'm rather new to C.
So, I try to do it this way:
StudentDB database;
//More code in between, that does include malloc()
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
//It crashes when it gets to that part.
What I am trying to do is use the realloc() function for a pointer that's inside a struct.
This is the entire program so far:
#include <stdio.h>
#include <stdlib.h>
typedef struct Lesson {
char *name;
int semester;
float grade;
} Lesson;
typedef struct Student {
char *name;
char *surname;
int id;
int numberOfLessons;
Lesson *lesson;
} Student;
typedef struct Database {
int numberOfStudents;
Student *student;
} StudentDB;
static int maxNameSize = 100;
static int autoclear = 1;
void addStudent(FILE *studentFile, StudentDB *database) {
database->numberOfStudents++;
printf("\nAdded +1 to number of students");
database->student = realloc(&database->student, 10);
//
// printf("Name of the student: ");
// scanf("%s", database.student[database.numberOfStudents].name);
}
void clear() {
if(autoclear) {
system("cls");
}
}
Lesson getNextLesson(FILE *studentFile) {
Lesson lesson;
lesson.name = malloc(maxNameSize * sizeof(char));
if(!lesson.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", lesson.name);
fscanf(studentFile, "%d", &lesson.semester);
fscanf(studentFile, "%f", &lesson.grade);
printf("\n\t%s %d || %.2f\n", lesson.name, lesson.semester, lesson.grade);
return lesson;
}
Student getNextStudent(FILE *studentFile) {
Student student;
student.name = malloc(maxNameSize * sizeof(char));
if(!student.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.name);
student.surname = malloc(maxNameSize * sizeof(char));
if(!student.surname) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.surname);
fscanf(studentFile, "%d", &student.id);
fscanf(studentFile, "%d", &student.numberOfLessons);
printf("%d || %s %s || %d\n", student.id, student.name, student.surname, student.numberOfLessons);
int lesson;
student.lesson = malloc(student.numberOfLessons * sizeof(Lesson));
for(lesson = 0; lesson < student.numberOfLessons; lesson++) {
student.lesson[lesson] = getNextLesson(studentFile);
}
return student;
}
void loadStudents() {
}
void run(FILE *studentFile, StudentDB *database) {
int answer;
do {
clear();
answer = menu();
switch(answer) {
case 1: {
break;
}
case 2: {
break;
}
case 3: {
addStudent(studentFile, &database);
break;
}
case 4: {
break;
}
}
} while(answer < 0 || answer > 9);
}
int menu() {
int answer;
printf("1. Load students records from file\n");
printf("2. Save students records to file\n");
printf("3. Add a student record\n");
printf("4. Delete a student record by student id\n");
printf("5. Display a student record by student id\n");
printf("6. Display a student record by student surname\n");
printf("7. Display all student records\n");
printf("8. Find the lesson average for all students\n");
printf("9. Exit\n");
printf("Enter the number of the thing you would like to do: ");
// scanf("%d", &answer);
return 3;
}
void programInfo() {
printf("\n\n====================================================\n\tProgram Info\n\n This program was created by KKosyfarinis\n\n KKosyfarinis#uth.gr\n====================================================\n\n");
}
void readData(FILE *studentFile, StudentDB *db) {
int i;
printf("Running the loop\n");
for(i = 0; i < db->numberOfStudents; i++) {
printf("=====================\n\n\tStudent #%d\n", i);
db->student[i] = getNextStudent(studentFile);
printf("\n\tCompleted\n\n=====================\n");
}
clear();
}
void saveStudents() {
}
void main() {
system("color 02");
system("#echo off");
FILE *studentFile;
StudentDB database;
studentFile = fopen("students.txt", "r+w");
int numberOfStudents;
//Set the number of students
fscanf(studentFile, "%d", &database.numberOfStudents);
//Prints the number of students
printf("Number of students: %d\n", database.numberOfStudents);
//Set the memory allocation
database.student = malloc(database.numberOfStudents * sizeof(Student));
if(!database.student) {
printf("The memory allocation has failed. Exiting the program!");
exit(0);
}
//Read the students
readData(studentFile, &database);
programInfo();
run(studentFile, &database);
}
Thanks in advance for any help!
You're two code blocks have differing lines. One of which (the larger one) is incorrect. You are passing in a dereference to the student pointer? That's not needed, just pass the pointer itself.
database->student = realloc(&database->student, 10);
Should be:
database->student = realloc(database->student, 10);
You are also not passing in a realistic size, but your first code sample was. Does the following line not work?
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
That was just copied from your question. I'm confused as to what you have/have not tried and which one gives you the error.
Also, in the future provide more of a minimal example that still produces the error. There's also a chance you would figure out the issue while stripping the code down.
What with this line ?
addStudent(studentFile, &database);
in run function ? Where pointer to local variable is taken and passed to addStudent function
void run(FILE *studentFile, StudentDB *database) {
...
case 3: {
addStudent(studentFile, &database); // <-- get pointer to local variable
i think this code cannot work even with Nick's changes without this modification
addStudent(studentFile, database);
I am writing a phone book program. I completed first function.
However, in second function (("" display() function "")) there is something wrong which is I couldn't find.
In display() function, I'm taking another name which is searched by user and comparing it with names into file to show that person's knowledge (Just one person) on the screen. But it doesn't work. How can I solve this problem?
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
#include <string.h> // "string" library contains of strcmp() function which compares string statements
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
char sName[16];
};
void newRecord(FILE *);
void display(FILE *);
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
if ((ptrFILE = fopen("Phone Book.txt", "w+")) == NULL)
{
printf("The file couldn't open\n");
}
do
{
printf("\n\t\t --- Phone Book Program ---");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord(ptrFILE);
break;
}
case 2:
{
display(ptrFILE);
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(EXIT_SUCCESS);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
}
}
} while (choice >= 1 && choice <= 6);
fclose(ptrFILE);
return 0;
}
void newRecord(FILE *ptrFILE)
{
static int counter = 0;
system("cls"); // Screen is being cleaned
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
if (counter == 0)
{
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t------------------------\n");
}
fprintf(ptrFILE, "\n%-33s%-33s%-38s\n", p->name, p->surname, p->number);
printf("Please wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed. *-*\n");
counter++;
free(p);
}
void display(FILE *ptrFILE)
{
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
fseek(ptrFILE, 0L, SEEK_SET);
fflush(stdin);
printf("\n\nExpress name which you search: ");
gets(s->sName);
while (!feof(ptrFILE))
{
fscanf(ptrFILE, "\n%-33s%-33s%-38s\n", &s->name, &s->surname, &s->number);
if (strcmp(s->name, s->sName) == 0)
{
printf("*-* Person knowledge who is you search *-*\n");
Sleep(750);
printf("\n\nName: %s\nSurname: %s\nNumber: %s\n", s->name, s->surname, s->number);
}
}
free(s);
}
}
The MSVC documentation of fopen says about mode: "w" Opens an empty file for both reading and writing. If the file exists, its contents are destroyed.
Since the first file open in main is
if ((ptrFILE = fopen("Phone Book.txt", "w+")) == NULL)
you destroy anything you already have.
To read the content, use mode "r" to open the file, read the content, then close it.
To add new content, either re-open with mode "w" and write the whole content, or open in append mode "a" and just write the new records(s).
Or you can open in mode "r+" for reading and writing, but before writing you need to fseek the end of the file.
In int main() you opened file with "w+" mode so everything is discarded in file when it is called.
Also in function void display(FILE *ptrFILE) you have not closed the text file.And you have used feof() inside while loop which may create problem .
Please see following link why you should not use while(!feof())-Why is “while ( !feof (file) )” always wrong?
void display(FILE *ptrFILE)
{
fclose(ptrFILE);//!! flush out
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
char buff[128];//!!for fgets
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
//fseek(ptrFILE, 0L, SEEK_SET);//!!no need
fflush(stdin);
printf("\n\nExpress name which you search: ");
gets(s->sName);
while (fgets(buff, sizeof buff, ptrFILE))//!!
{
sscanf(buff, "%15s%15s%15s\n", s->name, s->surname, s->number);//!!
I'm trying to create phone book which has five function in c. I have formed just first function which takes and saves in file people's knowledge. However, I cannot succeed the second function which search just a person's (Not all people) knowledge from file.
To run this function (""display() function"") I want to a name from user to search and to display that name's knowledge on the screen. I wrote something but it didn't work. The problem is display() function. How can I read just one line and print it on the screen? Thanks in advance.
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function
#include <string.h> // "string" library contains of strcmp() function
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
};
void newRecord();
void display();
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
printf("\n\t\t *-* Phone Book Program *-*");
do
{
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord();
break;
}
case 2:
{
display();
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(0);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
}
}
} while (choice >=1 && choice <=6 );
return 0;
}
void newRecord()
{
system("cls"); // Screen is being cleaned
if ((ptrFILE = fopen("Phone Book.txt", "w")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n");
fprintf(ptrFILE, "\n%s%33s%38s\n", p->name, p->surname, p->number);
fclose(ptrFILE);
free(p);
printf("Please wait, information is saving to file..\n");
Sleep(1000);
printf("*-* Saving operation has been completed. *-*");
}
fclose(ptrFILE);
}
void display()
{
struct personKnowledge *s; // s means searching
char name[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
fseek(ptrFILE, 0L, SEEK_SET);
printf("Express name which you search: ");
gets(s->name);
while (!feof == NULL)
{
fscanf(ptrFILE,"%s", &name);
if (strcmp(s->name, name) == 0)
{
printf("qawsdsdf");
}
}
}
fclose(ptrFILE);
}
In answer to one of your questions, I recommend rewriting this loop in display()
while (!feof == NULL) // wrong way to use feof
{
fscanf(ptrFILE,"%s", &name); // might overflow the string space
if (s->name == name) // wrong way to compare strings
{
printf("qawsdsdf"); // missing newline?
}
}
with this
while (fgets(name, sizeof(name), ptrFILE) != NULL) // safer way to read to a small buffer
{
name [ strcspn(name, "\r\n") ] = 0; // remove trailing newline etc
if (strcmp(s->name, name) == 0) // compare the strings
{
printf("qawsdsdf\n"); // added newline
}
}
EDIT in any case your posted code does not even compile properly:
while (!feof == NULL)
is rubbish, it should have been
while (!feof(ptrFILE))
although as I said is not the way to use feof anyway. This would not have happened if you had compiler warnings enabled and dealt with them.
I think these minor changes will solve your problem
Allocate memory for storing personKnowledge s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
Make file pointer reach the starting location of data. A simple trick has been used to achieve this fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fscanf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n");
Make change in while loop.while (!feof(ptrFILE))
Scanning one row of data.fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number)
Make change in string comparison.if (strcmp(name,s->name) == 0)
The modified display function
void display(){
struct personKnowledge *s;
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated for s
fflush(stdin);
char name[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
fseek(ptrFILE, 0L, SEEK_SET);
printf("Express name which you search: ");
scanf("%s",name); //the name you want to retrieve
fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fscanf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n"); //when we read the file for first time we need to start from the first location of person data, this is a trick to make ptrFILE reach there
fflush(stdin);
while (!feof(ptrFILE))
{
fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number);//same format as fprintf used in newRecord
if (strcmp(name,s->name) == 0) //comparison
{
printf("qawsdsdf");
}
}}fclose(ptrFILE);}
My solution was to change how the file is formatted
fprintf(ptrFILE, "\n%s%33s%38s", p->name, p->surname, p->number);
Because if you're using a program to retrieve information, there's no need to fill it with a bunch of junk headers every time you write to it.
I then edited the display function to be able to retrieve said information.
void display()
{
struct personKnowledge s; // s means searching
char name[16];
char sname[16];
char number[16];
char surname[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
printf("Express name which you search: ");
scanf("%s", &sname);
do
{
fscanf(ptrFILE,"%s%33s%38s", &name, &surname, &number);
if (strcmp(sname, name) == 0)
{
printf("%s %s %s", name, surname, number);
}
}
while (strcmp(sname, name) != 0);
}
}
P.S. I'm still new to c myself and I don't think I could give you a good explanation as to why my code works and yours doesn't. But I can say that those headers you were writing to the file every time was a major part of the problem when I was troubleshooting your code.
#include <stdio.h>
#include <stdlib.h>
struct packets
{
int source, destination, type, port;
char data[50];
};
int addpacket(int *, struct packets *);
void listpackets(int , struct packets *);
void save(int, struct packets *);
int main()
{
struct packets *info;
char choice;
int records = 0;
info = malloc(sizeof(struct packets));
do
{
puts("\n1. Add Packets\n"); //Menu with list of options.
puts("\n2. List all saved packets\n");
puts("\n3. Save packets\n");
puts("\n4. Clear all packet information\n");
puts("\nx. Exit the programme\n");
printf("\nPlease select your option: \n");
scanf("%c", &choice); //Reading the menu option entered.
if(choice == '\n') //if the choice is the new line character read again.
scanf("%c", &choice);
switch (choice)
{
case '1': system("cls"); //Clears the screen
puts("\nYou have selected to Add packet information, follow on-screen instructions\n"); records = addpacket(&records, info); //calls function "addpacket" and sents a copy of records and pointer to struct info.
break;
case '2': system("cls"); //clears the screen
puts("\nAll packet information will now be displayed on the screen\n"); listpackets(records, info);
break;
case '3': system("cls"); //clears the screen
puts("\nAll packet information will now be saved\n"); save(records, info);
break;
case '4': system("cls"); //clears the screen
puts("\nAll packet information will now be deleted\n");
break;
case 'x': puts("\nThe proframme will now close, Goodbye!\n"); //closes the programme.
break;
default : puts("\nIncorrect option, please select from menu\n"); //used if none of the menu options have been selected.
break;
}
}while (choice != 'x'); //The programme will run until the "x" option is entered at the menu.
return 0;
}
int addpacket(int *recCount, struct packets *info)
{
int validation = 0;
int stringlength = 0;
int i = 0;
char datatest[50];
do{
printf("\nPlease enter the source address: \n");
if (scanf("%i", &info[*recCount].source) == 1)
{
validation = 1;
}
else{
validation = 0;
getchar();
puts("\nThis is not a valid source address!\n");
}
}while (validation != 1);
printf("\nPlease enter destination address: \n");
scanf("%i", &info[*recCount].destination); //pointer to the destination address.
printf("\nPlease enter type: \n");
scanf("%i", &info[*recCount].type); // pointer to the address of the type.
printf("\nPlease enter the port: \n");
scanf("%i", &info[*recCount].port); //pointer to the port address.
printf("\nPlease enter data: \n");
scanf("%s", info[*recCount].data); //pointer to the data address.
*recCount ++; //adding one to record count
return *recCount; // returning the record count which will the be copied into records in main.
}
void listpackets(int records, struct packets *info)
{
int i;
for (i=0; i<records; i++){
printf("\nSource address: %i\n", info[i].source); //Displays the source address.
printf("\nDestination address: %i\n", info[i].destination); //Displays the destination address.
printf("\nType: %i\n", info[i].type); //Displays the type.
printf("\nPort: %i\n", info[i].port); //displays the port.
printf("\nData: %s\n", info[i].data); //displays the data information.
}
}
void save(int records, struct packets *info)
{
FILE *savedfile;
char filename[30] = { '\0'}; //this is where the file name will be stored.
int i;
printf("\nPlease enter a filename: \n");
scanf("%s", filename);
if ((savedfile = fopen(filename, "w")) == NULL)
{
printf("\n%s could not be opened\n", filename);
exit(1);
}
else
{
for (i=0; i<records; i++)
fprintf(savedfile, "%i %i %i %i %s", info[i].source, info[i].destination, info[i].type, info[i].port, info[i].data);
}
fclose(savedfile);
}
My save and listpacket function crash when i call them. this was working earlier until i introduced malloc into my programme along side some basic input validation. i think this could be an issue with pointers. my programme compiles with no errors/warning so i am stuck with what the problem could be. feel free to try compiling to programme and see what i mean. any help would be greatly appreciated as i am struggling to fix this issue.
You're using malloc() to allocate space for a single struct packets. You later treat your info pointer as if it is an array of records such structures... you're going beyond the boundary of where you have allocated space.
Details on one potential way around (that will auto-grow your array):
// change the signature of addpacket():
int addpacket(int *, struct packets **);
...
// change how add packet gets called:
records = addpacket(&records, &info);
// change addpacket():
int addpacket(int *recCount, struct packets **callerinfo)
{
...
// grow the buffer by one record
*callerinfo = realloc(*callerinfo, (*recCount + 1) * sizeof (**callerinfo));
struct packets *info = *callerinfo; // to avoid changing other code
... no other changes, just the rest of your routine
}
That will come close, of not completely solve it.
The complete program, working for me:
#include <stdio.h>
#include <stdlib.h>
struct packets
{
int source, destination, type, port;
char data[50];
};
int addpacket(int *, struct packets **);
void listpackets(int , struct packets *);
void save(int, struct packets *);
int main()
{
struct packets *info;
char choice;
int records = 0;
info = malloc(sizeof(struct packets));
do
{
puts("\n1. Add Packets\n"); //Menu with list of options.
puts("\n2. List all saved packets\n");
puts("\n3. Save packets\n");
puts("\n4. Clear all packet information\n");
puts("\nx. Exit the programme\n");
printf("\nPlease select your option: \n");
scanf("%c", &choice); //Reading the menu option entered.
if(choice == '\n') //if the choice is the new line character read again.
scanf("%c", &choice);
switch (choice)
{
case '1': system("cls"); //Clears the screen
puts("\nYou have selected to Add packet information, follow on-screen instructions\n"); records = addpacket(&records, &info); //calls function "addpacket" and sents a copy of records and pointer to struct info.
break;
case '2': system("cls"); //clears the screen
puts("\nAll packet information will now be displayed on the screen\n"); listpackets(records, info);
break;
case '3': system("cls"); //clears the screen
puts("\nAll packet information will now be saved\n"); save(records, info);
break;
case '4': system("cls"); //clears the screen
puts("\nAll packet information will now be deleted\n");
break;
case 'x': puts("\nThe proframme will now close, Goodbye!\n"); //closes the programme.
break;
default : puts("\nIncorrect option, please select from menu\n"); //used if none of the menu options have been selected.
break;
}
}while (choice != 'x'); //The programme will run until the "x" option is entered at the menu.
return 0;
}
int addpacket(int *recCount, struct packets **callerinfo)
{
int validation = 0;
int stringlength = 0;
int i = 0;
char datatest[50];
*callerinfo = realloc(*callerinfo, (*recCount + 1) * sizeof (**callerinfo));
struct packets *info = *callerinfo; // to avoid changing other code
do{
printf("\nPlease enter the source address: \n");
if (scanf("%i", &info[*recCount].source) == 1)
{
validation = 1;
}
else{
validation = 0;
getchar();
puts("\nThis is not a valid source address!\n");
}
}while (validation != 1);
printf("\nPlease enter destination address: \n");
scanf("%i", &info[*recCount].destination); //pointer to the destination address.
printf("\nPlease enter type: \n");
scanf("%i", &info[*recCount].type); // pointer to the address of the type.
printf("\nPlease enter the port: \n");
scanf("%i", &info[*recCount].port); //pointer to the port address.
printf("\nPlease enter data: \n");
scanf("%s", info[*recCount].data); //pointer to the data address.
++(*recCount); //adding one to record count
return *recCount; // returning the record count which will the be copied into records in main.
}
void listpackets(int records, struct packets *info)
{
int i;
for (i=0; i<records; i++){
printf("\nSource address: %i\n", info[i].source); //Displays the source address.
printf("\nDestination address: %i\n", info[i].destination); //Displays the destination address.
printf("\nType: %i\n", info[i].type); //Displays the type.
printf("\nPort: %i\n", info[i].port); //displays the port.
printf("\nData: %s\n", info[i].data); //displays the data information.
}
}
void save(int records, struct packets *info)
{
FILE *savedfile;
char filename[30] = { '\0'}; //this is where the file name will be stored.
int i;
printf("\nPlease enter a filename: \n");
scanf("%s", filename);
if ((savedfile = fopen(filename, "w")) == NULL)
{
printf("\n%s could not be opened\n", filename);
exit(1);
}
else
{
for (i=0; i<records; i++)
fprintf(savedfile, "%i %i %i %i %s\n", info[i].source, info[i].destination, info[i].type, info[i].port, info[i].data);
}
fclose(savedfile);
}
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);
...