Seg Fault in my - c

I have an issue with my code here when I try to add a record to the database. Everytime I enter anything more than a few characters in for the first name prompt, the program will seg fault, even after moving elements from the old record. I understand that seg faults are due to trying to access memory that we don't have access too, but for the life of me I can't figure out what's causing it. The point of this code is to create a structure of type credit card which is defined in the header file which has a hardcoded set of 4 records, and be able to print the current database, add a record, delete a record, and other choices from the menu. Right now I am focusing on adding and deleting a record, as they are the most difficult part of this program. Why do I keep getting seg fault errors when trying to add a record?
The header file:
#ifndef myStruct
#define myStruct
struct creditCard
{
char firstName[100];
char lastName[100];
char cardNumber[17]; //TA advised to use string since 16 digits will overflow in plain integer
char expMonth[10];
};
//function headers below
int printCreditCard(struct creditCard *);
int sizeOfDb(struct creditCard *);
int countRecords(struct creditCard *);
int deleteRecord(struct creditCard *);
int addRecord(struct creditCard *);
#endif
Here is the actual program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "myStruct.h"
int accesses = 0; //number of times database was manipulated
int count = 0; //used to count how many records there are; we always start at 4
//int size = 0; //used to tell us how big the database is
struct creditCard *ptr; //chunk of memory for each record/structure
struct creditCard *headPtr; //chunk of memory for the first records/structure
int main(void)
{
ptr = (struct creditCard *) malloc(4 * sizeof(struct creditCard));
headPtr = ptr;
memcpy(ptr->firstName,"Bob",100);
memcpy(ptr->lastName,"Marley",100);
memcpy(ptr->cardNumber,"0000000000000000",17);
memcpy(ptr->expMonth,"September", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "John", 100);
memcpy(ptr->lastName, "Adams", 100);
memcpy(ptr->cardNumber,"1111111111111111",17);
memcpy(ptr->expMonth, "October", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "Bill", 100);
memcpy(ptr->lastName, "Gates", 100);
memcpy(ptr->cardNumber,"2222222222222222",17);
memcpy(ptr->expMonth, "January", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "Steve", 100);
memcpy(ptr->lastName, "Jobs", 100);
memcpy(ptr->cardNumber,"3333333333333333",17);
memcpy(ptr->expMonth, "May", 10);
count = count++;
while (1)
{
//headPtr = ptr; //put the newest database into headPtr so it points to the first record in that database
//ptr = headPtr; //start the database back at the first record
//countRecords(ptr); //update the count of the current database
int sel;
printf("MAIN MENU\n");
printf("=====\n");
printf("1. Select 1 to print all records.\n");
printf("2. Select 2 to print number of records .\n");
printf("3. Select 3 to print size of database.\n");
printf("4. Select 4 to add record.\n");
printf("5. Select 5 to delete record.\n");
printf("6. Select 6 to print number of accesses to database.\n");
printf("7. Select 7 to Exit.\n");
printf("Enter Your Selection: \n");
scanf("%d", &sel); //get user input;
if (sel == 1)
{
printCreditCard(ptr);
accesses++;
}
else if (sel == 2)
{
fprintf(stderr,"Number of records in the database is %d records\n", count); //pulls value of count from global updated variable
accesses++;
}
else if (sel == 3)
{
sizeOfDb(ptr);
accesses++;
}
else if (sel == 4)
{
ptr = headPtr;
addRecord(ptr);
accesses++;
}
else if (sel == 5)
{
deleteRecord(ptr);
accesses++;
}
else if (sel == 6)
{
fprintf(stderr,"Number of accesses to the database is %d\n", accesses);
accesses++;
}
else if (sel == 7)
{
printf("Now Exiting.\n");
return 0;
}
else
{
printf("Invalid input, please select a valid option.\n");
break; //go back to the main menu
}
}
}
//functions defined below
int sizeOfDb(struct creditCard *card2)
{
int size = 0;
int j;
for (j = 1; j <= count; j++)
{
size += sizeof(card2->firstName); //get the size of each element
size += sizeof(card2->lastName);
size += sizeof(card2->cardNumber);
size += sizeof(card2->expMonth);
card2++;
}
//loop through each record and get sizeof() of each record
fprintf(stderr, "Total Size of the Database is %d bytes.\n", size);
return size;
}
int addRecord(struct creditCard *card3)
{
count = count++;
fprintf(stderr, "count is %d \n", count);
int p;
struct creditCard *tempStruct;
//struct creditCard *dummy;
char fName, lName, month, number;
//tempStruct = (struct creditCard *) malloc (count * sizeof(struct creditCard)); //allocate memory to a dummy record
tempStruct = (struct creditCard *) malloc ((count+1) * sizeof(struct creditCard)); //allocate memory to a dummy record
//dummy = (struct creditCard *) malloc (sizeof(struct creditCard));
//dummy = (struct creditCard *) malloc (2 * sizeof(struct creditCard));
card3 = headPtr; //start at the beginning of the old database
for (p = 1; p < count; p++) //copies the old database in the new database up to the record before the newly allocated record
{
memcpy(tempStruct->firstName, card3->firstName, 100);
memcpy(tempStruct->lastName, card3->lastName, 100);
memcpy(tempStruct->cardNumber, card3->cardNumber, 17);
memcpy(tempStruct->expMonth, card3->expMonth, 10);
fprintf(stderr, "first name is %s\n", tempStruct->firstName);
if (p == count-1)
{
tempStruct++;
}
else
{
tempStruct++;
card3++;
}
}
printf("Please enter your first name.\n");
scanf("%s", &fName);
fprintf(stderr, "fname is %s\n", &fName);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->firstName, &fName,100);//put first name in struct
fprintf(stderr, "struct name is %s\n", tempStruct->firstName);
//fprintf(stderr, "dummy name is %s\n", dummy->firstName);
printf("Please enter your last name.\n");
scanf("%s", &lName);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->lastName,&lName,100);//put last name in struct
printf("Please enter your 16 digit credit card number with no spaces.\n");
scanf("%s", &number);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->cardNumber,&number,17);//put creditcard number in struct
printf("Please enter the month in which your credit card expires.\n");
scanf("%s", &month);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->expMonth,&month, 10); //put month of expiration in struct
//code below copies stuff from the dummy record to the new database called tempStruct
//memcpy(tempStruct->firstName, dummy->firstName, 100);
//memcpy(tempStruct->lastName, dummy->lastName, 100);
//memcpy(tempStruct->cardNumber, dummy->cardNumber, 17);
//memcpy(tempStruct->expMonth, dummy->expMonth, 10);
card3 = tempStruct; //put the new database in place of the old database
//free(dummy); //clear memory for the dummy record because we don't need it anymore
return 0;
}
int deleteRecord(struct creditCard *card4) //goes to the last record in the database and clears the memory for it, essentially deleting it
{
count = count--;
int l;
struct creditCard *newDb; //will hold the new database with one less record at the end
newDb = (struct creditCard *) malloc(count * sizeof(struct creditCard));
for (l = 0; l < 4; l++)
{
memcpy(newDb->firstName,card4->firstName,100);
memcpy(newDb->lastName,card4->lastName,100);
memcpy(newDb->cardNumber,card4->cardNumber,17);
memcpy(newDb->expMonth,card4->expMonth,10);
card4++;
}
//now we need to put the data into the new record
card4 = newDb; //put the new database into ptr to hold as the new database
return 0;
}
int printCreditCard(struct creditCard *card)
{
card = headPtr; //start at the beginning of the database
int i;
if (count == 0)
{
printf("The database is empty\n");
return 0;
}
else
{
for (i = 1; i <= count; i++)
{
printf("Credit Card Record %d\n", i);
fprintf(stderr, "First Name = \%s\n", card-> firstName);
fprintf(stderr, "Last Name = \%s\n", card-> lastName);
fprintf(stderr, "Card Number = \%s\n", card-> cardNumber);
fprintf(stderr, "Expiration Date = \%s\n\n", card-> expMonth);
card++; //go to the next record to print
}
}
return 1; //we have now printed all records, go to main menu.
}

There is really a lot wrong here-- you should try using lint or another static analysis tool to help you find errors.
One particular problem -- when you input fname, you are passing scanf a pointer to a single character-- you really want to pass it a pointer to an array of characters (actually, you don't want to use scanf at all, but I won't get into that). Scanf is merrily copying the input characters into the memory positions after that single char, which of course will cause a segfault at some point.
You'll also need to learn to use some sort of debugger (gdb?) which will help you look at the core dump when you get a segfault so you can find where things went wrong.

Related

Modifying data in a Linked List in C?

When I modify the linked list (based on the ID), it modifies the node successfully but deletes the rest of the list. The whole list stays only if I modify the most recent node that I've added to the list.
I know that the problem is at the end where it says:
phead=i;
return phead;
But I don't know how to fix it as I haven't found anything to help me, even though I'm sure it is simple to know why it is wrong.
struct ItemNode *modify1Item(struct ItemNode *phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i=phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i= i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
}
else{
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
When I return it, i say head=modify1Item(phead);
I tested your code everything worked as expected. Without seeing your code, I can't comment much. But I think, for your code, the only time everything would get delete is if you assign the return value incorrectly. So this below is probably something close to your code. For the test code below, unless you modify it, the IDs are 0, 1, and 2. Oh and the reason why I commented only work for 0 to 9 is because I don't want to make up the entire char string so I used i ^ 48. Of which, 0 - 9 ^ 48 would turn into the correspondent ASCII code of 0 - 9. If you go beyond that, you may get weird result for that two string that all.
I just noticed that you use NULL in your search. Thus, I updated the code so the "next" of last index will be NULL otherwise if your code found nothing, it will run forever.
#include <stdio.h>
#include <string.h>
typedef struct ItemNode {
int ID;
int uPrice;
int onHand;
char name[30];
char desc[30];
struct ItemNode * next;
} ItemNode ;
struct ItemNode * modify1Item(struct ItemNode * phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i = phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i = i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
} else {
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
int main(){
// only work for 0 - 9.
int index = 3;
ItemNode iArr[index];
for ( int i = 0; i < index; i++ ){
iArr[i].ID = i;
iArr[i].uPrice = i + i;
iArr[i].onHand = i * i;
iArr[i].name[0] = i ^ 48;
iArr[i].desc[0] = i ^ 48;
// If last index link back to first index.
// Updated: but for you usage case
// because of your search function
// last index should be NULL otherwise your
// search will run forever
if ( i < index - 1 ) iArr[i].next = &iArr[i + 1];
else iArr[i].next = NULL; // if change search method with unique ID then you can use -> &iArr[0];
}
// Mod 0
ItemNode * test = modify1Item(iArr);
printf("0 name: %s\n\n",iArr[0].name );
// Mod 1
ItemNode * test1 = modify1Item(iArr);
printf("1 name: %s\n\n",iArr[1].name );
// Mod 2
ItemNode * test2 = modify1Item(iArr);
printf("2 name: %s\n\n",iArr[2].name );
// Check if 0 is still there.
printf("0 name: %s\n\n",iArr[0].name );
return 0;
}

Error when adding another record to dynamic memory database

My task is to initialize a struct in a header with some data. Then using pointers, add/remove data by malloc-ing bigger/smaller chunks and copying the data over.
Currently, my addRecord function doesn't work as it always seems to add the same crap (Part of record number 1):
Name =
Fire Number = attan (Seems to be part of Manhattan)
Street = ork (Seems to be part of New York)
City = cret (Seems to be part of Secret)
State = tan (Seems to be part of Manhattan)
What am I doing wrong?
My header:
#include <stdio.h>
#include <stdlib.h>
struct structPointer{
char name[51];
char fireNumber[11];
char street[26];
char city[26];
char state[26];
};
My c file:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "myData.h"
struct structInit *sP;
struct structInit *sSP;
int recordNumber = 0;
int numberOfAccesses = 0;
int main(void) {
sP = (struct structInit *) malloc(5 * sizeof(struct structInit));
sSP = sP;
memcpy(sP->name,"Adam Baum",51);
memcpy(sP->fireNumber,"N1234",11);
memcpy(sP->street,"Top Secret",26);
memcpy(sP->city,"Manhattan",26);
memcpy(sP->state,"New York",26);
sP++;
recordNumber++;
memcpy(sP->name,"Adam Zapel",51);
memcpy(sP->fireNumber,"S4321",11);
memcpy(sP->street,"Throat",26);
memcpy(sP->city,"Manhattan",26);
memcpy(sP->state,"New York",26);
sP++;
recordNumber++;
memcpy(sP->name,"Al Bino",51);
memcpy(sP->fireNumber,"W1234",11);
memcpy(sP->street,"White",26);
memcpy(sP->city,"Anchorage",26);
memcpy(sP->state,"Alaska",26);
sP++;
recordNumber++;
memcpy(sP->name,"Anne Teak",51);
memcpy(sP->fireNumber,"E4321",11);
memcpy(sP->street,"Oak",26);
memcpy(sP->city,"Woodville",26);
memcpy(sP->state,"Wisconsin",26);
sP++;
recordNumber++;
memcpy(sP->name,"Barb Dwyer",51);
memcpy(sP->fireNumber,"N1234",11);
memcpy(sP->street,"Keepout",26);
memcpy(sP->city,"Kilgore",26);
memcpy(sP->state,"Texas",26);
recordNumber++;
sP = sSP;
int sel;
while (1){
printf("MENU\n");
printf("=====\n");
printf("1. Print All Records\n");
printf("2. Print Number of Records\n");
printf("3. Print Size of Database\n");
printf("4. Add Record\n");
printf("5. Delete Record\n");
printf("6. Print Number of Accesses to Database\n");
printf("7. Exit\n");
printf("=====\n");
printf("Enter selection: ");
scanf("%d", &sel);
printf("\n");
switch(sel){
case 1:
numberOfAccesses++;
printAllRecords(sP);
break;
case 2:
numberOfAccesses++;
fprintf(stderr,"There are a Total of %d records.\n\n", recordNumber);
break;
case 3:
numberOfAccesses++;
printSizeOfDatabase(sP);
break;
case 4:
numberOfAccesses++;
sP = sSP;
addRecord(sP);
break;
case 5:
numberOfAccesses++;
deleteRecord(sP);
break;
case 6:
numberOfAccesses++;
fprintf(stderr,"The total number of Accesses is %d\n\n", numberOfAccesses);
break;
case 7:
exit(0);
default:
printf("Error: Input was not a valid selection.\n\n");
break;
}
}
return 0;
}
int printAllRecords(struct structInit *structPointer){
int i;
structPointer = sSP;
printf("All Records: \n");
for(i=1;i<=recordNumber;i++){
printf("Record Number: %d\n", i);
fprintf(stderr, "Name = \%s\n", structPointer-> name);
fprintf(stderr, "Fire Number = \%s\n", structPointer-> fireNumber);
fprintf(stderr, "Street = \%s\n", structPointer-> street);
fprintf(stderr, "City = \%s\n", structPointer-> city);
fprintf(stderr, "State = \%s\n\n", structPointer-> state);
structPointer++;
}
return 1;
}
int printSizeOfDatabase(struct structInit *structPointer) {
int size = 0;
int i;
for (i=1;i<=recordNumber;i++) {
size += sizeof(structPointer->name);
size += sizeof(structPointer->fireNumber);
size += sizeof(structPointer->street);
size += sizeof(structPointer->city);
size += sizeof(structPointer->state);
structPointer++;
}
fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
return size;
}
int addRecord(struct structInit *structPointer){
char entryName;
char entryFireNumber;
char entryStreet;
char entryCity;
char entryState;
recordNumber++;
struct structInit *theStruct;
theStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
int i;
for (i=1;i<recordNumber;i++){
memcpy(theStruct->name,structPointer->name,51);
memcpy(theStruct->fireNumber,structPointer->fireNumber,11);
memcpy(theStruct->street,structPointer->street,26);
memcpy(theStruct->city,structPointer->city,26);
memcpy(theStruct->state,structPointer->state,26);
/*if(i==recordNumber){
theStruct++;}
else{
theStruct++;
structPointer++;}*/
theStruct++;
structPointer++;
}
theStruct++;
printf("Enter the Name of the New Record: \n");
scanf("%s",&entryName);
memcpy(theStruct->name,&entryName,51);
printf("Enter the Fire Number of the New Record: \n");
scanf("%s",&entryFireNumber);
memcpy(theStruct->fireNumber,&entryFireNumber,11);
printf("Enter the Street of the New Record: \n");
scanf("%s",&entryStreet);
memcpy(theStruct->street,&entryStreet,26);
printf("Enter the City of the New Record: \n");
scanf("%s",&entryCity);
memcpy(theStruct->city,&entryCity,26);
printf("Enter the State of the New Record: \n");
scanf("%s",&entryState);
memcpy(theStruct->state,&entryState,26);
structPointer=theStruct;
printf("Record has been added.\n\n");
return 0;
}
int deleteRecord(struct structInit *structPointer){
struct structInit *anotherStruct;
anotherStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
int i;
for(i=0;i<5;i++){
memcpy(anotherStruct->name,structPointer->name,51);
memcpy(anotherStruct->fireNumber,structPointer->fireNumber,11);
memcpy(anotherStruct->street,structPointer->street,26);
memcpy(anotherStruct->city,structPointer->city,26);
memcpy(anotherStruct->state,structPointer->state,26);
structPointer++;
}
structPointer=anotherStruct;
recordNumber--;
printf("Record has been deleted.\n\n");
return 0;
}
At a glance:
The %s format specifier for scanf specifies a pointer to the first element of an array of char.
You're passing a pointer to one char.
It's just bad luck that the program doesn't crash completely.
You want
char entryName[51];
/* ... */
printf("Enter the Name of the New Record: \n");
scanf("%s", entryName);
and similar for the rest of the inputs.
Replace memcpy with strncpy - you shouldn't copy anything from outside the source object.
If you use realloc you can get rid of the entire copying loop when you expand your table.
Assigning to a parameter doesn't modify the value of the variable whose value you passed in.
This is as true for pointers as it is for everything else.
If you want to modify a variable, pass a pointer to it:
int addRecord(struct structInit **structPointer)
{
/* ... */
*structPointer = theStruct;
/* ... */
}
You don't need to do a memberwise memcpy between structs - in fact you don't need memcpy at all, since assignment works:
struct structInit a = /* ... */;
struct structInit b = /* ... */;
a = b; /* OK */
You need to make up your mind about whether to use global variables or parameters.
In particular, printAllRecords disregards the value of its parameter completely.
deleteRecord assumes that there are five records in your table.
You can also replace printSizeOfDatabase with this:
int printSizeOfDatabase() {
int size = recordNumber * sizeof(struct structInit);
fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
return size;
}
You could use realloc in the add function.
A typedef would make the program a lot easier to read.
Please add this line to the end of mydata.h
typedef struct structPointer structInit;
Then before main() it becomes
structInit *sP;
structInit *sSP;
Then printAllRecords become :
int printAllRecords(structInit *structPointer)
Then turn ON your debugger and READ the messages.

allocating in heap memory array of pointers to struct

I'm trying to make simple data base by using structure like
struct Employee{
char* name;
int ID;
int GPA;
int salary;
};
i know how i can allocate one pointer of the struct type in heap by using that
struct Employee* emp=malloc(sizeof(Employee));
my problem now that i'm not very good in allocating processes and i want
to allocate N number of pointer of the struct in the heap and i can't use arrays because the size will not be knows until running time
any suggestions ?
Yes, you need to allocate the memory dynamically, i.e. allocate a new heap block for every new struct Employee.
You can do this for example using realloc when the size changes:
yourArrayPtr=realloc(yourArrayPtr,newsize * sizeof(struct Employee));
The realloc function basically assigns a new amount of memory for the data pointed by its return value. It is a convenient way of expanding, or shrinking a dynamically allocated array. newsize here is the new number of elements of your array, and it is multiplied by the size of one Employee structure, rendering the total amount of space needed for your new array. The return value of realloc is assigned to your array pointer, so that it points specifically to this newly allocated space. In this case it could be used like this:
struct Employee* emp= NULL;
And then when you need it:
int n = 8;
emp = realloc (emp, n * sizeof(struct Employee));
Keep in mind, that you still have to free this memory.
You can now initialize and access this data:
emp[3] = {value1, value2, value3, ...};
As far as structures go, you could also think of another data structure - a linked list, where every structure contains a pointer to its successor. You can read about it here: http://www.cprogramming.com/tutorial/c/lesson15.html
In your case, it would be sth like:
struct Employee{
char* data;
struct Employee* next;
};
As others mentioned, you can use malloc to create as many entries of employee details in heap and store them in a dynamic list(linked list). i have given an example code, you can start from here and extend it, if you want to save the employee details before exiting, you can write it to a binary file and read it back when you run the program again(based on your needs), since once you program exits all the data will be lost.
#include <stdio.h>
#include <stdlib.h>
// Max length for employee name
const unsigned int MAX_NAME_LEN = 100;
typedef struct Employee{
char* name;
unsigned int ID;
int GPA;
float salary;
} EMPLOYEE ;
typedef struct emp_database_entry {
EMPLOYEE data;
struct emp_database_entry *next;
} EMPLOYEE_ENTRY;
typedef EMPLOYEE_ENTRY* EMPLOYEE_DATABASE;
// to create a new employee
EMPLOYEE_ENTRY* createEmployee() {
EMPLOYEE_ENTRY *newEmp = (EMPLOYEE_ENTRY*)malloc(sizeof(EMPLOYEE_ENTRY));
printf("Enter Employee Name:");
newEmp->data.name = (char*)malloc( MAX_NAME_LEN * sizeof(char) );
scanf("%s",newEmp->data.name);
printf("Enter employee ID:");
scanf("%u",&newEmp->data.ID);
printf("Enter employee GPA:");
scanf("%u",&newEmp->data.GPA);
printf("Enter employee salary:");
scanf("%f",&newEmp->data.salary);
newEmp->next = 0;
return (newEmp);
}
// add a new employee to database
EMPLOYEE_DATABASE addEmployee(EMPLOYEE_DATABASE db) {
EMPLOYEE_ENTRY *newEmp = createEmployee();
if(db == NULL) {
// add the first entry
db = newEmp;
} else {
// add it to the top
newEmp->next = db;
db = newEmp;
}
return (db);
}
// Search for Employee using ID
EMPLOYEE_ENTRY* searchEmployee(EMPLOYEE_DATABASE db, unsigned int ID) {
EMPLOYEE_ENTRY *employee = db;
if(employee == NULL) {
printf("There are no Employees in the database\n");
return (NULL);
}
// Search till the end, if a match is found return the
// pointer to employee
while( employee != NULL ) {
if( employee->data.ID == ID )
return (employee);
else
employee = employee->next;
}
return (NULL);
}
void printOneEmployee( EMPLOYEE_ENTRY *employee ) {
printf("Employee Details\n");
printf("Name : %s\n",employee->data.name);
printf("ID : %u\n",employee->data.ID);
printf("GPA : %d\n",employee->data.GPA);
printf("Salary: %f\n\n",employee->data.salary);
}
// Print all employee details
void printAllEmployee( EMPLOYEE_DATABASE db ) {
EMPLOYEE_ENTRY *employee = db;
// traverse till the end and print one by one
while( employee != NULL ) {
printOneEmployee(employee);
employee = employee->next;
}
}
// freeing allocated memory
void freeDatabase(EMPLOYEE_DATABASE db) {
EMPLOYEE_DATABASE employee = 0;
while( db != NULL ) {
employee = db;
db = employee->next;
free(employee->data.name);
free(employee);
}
}
void displayOption( EMPLOYEE_DATABASE db ) {
int option = -1;
while( option != 5 ) {
printf("\nEmployee DataBase\n");
printf("1: Add a Employee\n");
printf("2: Search Employee\n");
printf("3: Print All Employee\n");
printf("4: Exit\n");
printf("Enter a number for the choice: ");
scanf("%d",&option);
if( option > 4 || option < 0 ) {
option = -1;
}
switch( option ) {
case 1:
db = addEmployee(db);
break;
case 2:
int ID;
if(db != NULL){
printf("Enter the Employee ID: ");
scanf("%d",&ID);
printf("Search Result1: ");
printOneEmployee(searchEmployee(db, ID));
}
else
printf("No Employees in the database\n");
break;
case 3:
printAllEmployee(db);
break;
case 4:
freeDatabase(db);
printf("DataBase Deleted\nExiting..");
exit(0);
default:
printf("Invalid Option!. Try Again!.\n");
}
}
}
int main() {
EMPLOYEE_DATABASE db = 0;
displayOption(db);
return (0);
}
Of course you can use arrays if you use C99. In C99 you can do things like:
scanf("%d", &N);
struct Employee emp[N];
emp[0].ID = 123;
if you are using gcc (or MinGW), just be sure to compile with -std=c99
On the other hand, if you just want to create an array on the heap, you can do something like:
scanf("%d", &N);
struct Employee* emp=malloc(N*sizeof(Employee));
emp[0].ID =123;
...
// do not forget to deallocate emp
free(emp);

Adding records with pointers to arrays

I have to create a program which adds records to a simple phone book. The code is below, but it doesn't work - function ends and then it stucks on declaring struct record x and doesn't want to display my added record - the program breaks down. When I put this part of code on the end of the function (but instead of "struct record x = array[0];" I put "struct record x = (*array)[0]") it works - record is printed. So I guess the problem is something about pointers, but I'm struggling and I really couldn't find out what's wrong. I remember that few weeks ago I created a program which was very similar but it was adding a new record to an array of integers, with fixed values and it was working well, so maybe there's something with structures that I don't know about. Thanks for any help!
I know the program isn't done yet and I know that I didn't make any action for temp_array == NULL, it'll be done after I found out what's going on.
struct record {
char f_name[SIZE];
char name[SIZE];
long int phone;
};
int add_record(struct record** array, int n)
{
struct record* temp_array = malloc((n+1) * sizeof(struct record));
if (temp_array == NULL)
{
free(temp_array);
return -1;
}
int i;
for (i=0; i < n; i++)
{
temp_array[i] = (*array)[i];
}
struct record new_record;
printf("\nAplly data.");
printf("\nFirst name: "); /*fgets(new_record.f_name, SIZE, stdin);*/ scanf("%s", &new_record.f_name);
printf("Surname: "); /*fgets(new_record.name, SIZE, stdin);*/ scanf("%s", &new_record.name);
printf("Phone number: "); scanf("%d", &new_record.phone);
temp_array[n] = new_record;
free (*array);
*array = temp_array;
//struct record x = (*array)[0];
//puts(x.f_name); puts(x.name); printf("%d", x.phone);
return 0;
}
main()
{
struct record* array; int n = 0;
int choice;
printf("\n1. Add record\n2. Delete record\n3. Find record\n0. Exit\n\nChoose action: ");
scanf("%d", &choice);
switch(choice) {
case 0: printf("\nKsiazka zostala zamknieta.\n"); return;
case 1: add_record(&array, n); n++; break;
case 2: return;
case 3: return;
default: printf("Wrong choice.\n\n"); return;
}
struct record x = array[0];
puts(x.f_name); puts(x.name); printf("%d", x.phone);
}
struct record* array=NULL;, and use %ld for long int – BLUEPIXY

Invalid pointer in C

I apologize in advance, but this is kind of a long one.
In my program, I read in the student's information, but when I go to output it, it comes out scrambled, and then gets a pointer error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student{
char *firstName;
char *lastName;
char id[10];
char gender;
int age;
double gpa;
};
void main()
{
int n;
struct student *classroom;
printf("How many students?");
scanf("%d",&n);
classroom = (struct student*) malloc(n*sizeof(struct student));
if (classroom == NULL)
exit(1);
readStudentsInformation(classroom,n);
outputStudents(classroom,n);
printf("The average age is %.2f.\n",averageAge(classroom,n));
printf("The average GPA is %.2f.\n",averageGpa(classroom,n));
sortByLastName(classroom,n);
outputStudents(classroom,n);
sortByID(classroom,n);
outputStudents(classroom,n);
sortByAge(classroom,n);
}
void outputStudents(struct student classroom[], int size)
{
int i;
for (i = 0; i < size; i++)
{
printf("%15s",classroom[i].firstName);
printf("%15s:",classroom[i].lastName);
printf("%14s,",classroom[i].id);
printf("%3c",classroom[i].gender);
printf("%5d",classroom[i].age);
printf("%5.2f",classroom[i].gpa);
}
}
Input:
How many students?2
First Name?Thom
Last Name?Arron
ID?2
Gender?M
Age?26
GPA?3.9
First Name?Frank
Last Name?Roberts
ID?1
Gender?F
Age?24
GPA?3.4'
Output:
Roberts Roberts: 2, M 26 3.90 : 1, F 24 3.40The average age is 25.00.
The average GPA is 3.65.
* glibc detected * ./lab12: munmap_chunk(): invalid pointer: 0x00007fff30319a90 *
: 2, M 26 3.90Aborted (core dumped)
The full code is here, but I didn't want to copy 200 lines to stack overflow: http://codepad.org/LYpS6t5z
Any idea what would cause this?
This is one conceptual error, you have it in a couple of places
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
classroom[i].firstName = temp;
What you want here instead is
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
strcpy(classroom[i].firstName, temp); // note this
Or, cleaned up a bit:
classroom[i].firstName = malloc(1+strlen(temp)); // note clean up here
if (classroom[i].firstName == NULL)
exit(1);
strcpy(classroom[i].firstName, temp);
Or even just
classroom[i].firstName = strdup(temp); // this takes place of all the lines above
These errors explain why your free's are failing.
Nothing else jumps out at me.
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
classroom[i].firstName = temp;
Your second assignment here overwrites the address, leaking the mallocd memory and making the pointer invalid as soon as that for iteration finishes. The same buffer is reused (with the same error) for lastName, which is why you see Roberts Roberts instead of the actual first and last name. When you go to free them, they are (1) invalid and (2) not made by malloc, so you get the crash you see.
Just like other arrays, you can't copy them by assignment, you have to copy byte-by-byte:
size_t len = strlen(temp);
classroom[i].firstName = malloc(1+len);
if (classroom[i].firstName == NULL)
exit(1);
strncpy(classroom[i].firstname, temp, len);
classroom[i].firstname[len] = '\0';
And don't cast the result of malloc.
Weirdness happening in readStudentsInformation, in particular lines like
classroom[i].lastName = temp;
are causing issues later on when you try to free this memory with
free(classroom[i].firstName);
Appropriate memory handling below:
void readStudentsInformation(struct student classroom[], int size)
{
int i;
char temp[50];
for (i = 0; i < size; i++)
{
printf("First Name?");
scanf("%s",temp);
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
/* after mallocing good memory can write in the data.. */
strcpy(classroom[i].firstName, temp);
/* classroom[i].firstName = temp; */
printf("Last Name?");
scanf("%s",temp);
classroom[i].lastName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].lastName == NULL)
exit(1);
/* classroom[i].lastName = temp; */
strcpy(classroom[i].lastName, temp);
printf("ID?");
scanf("%s",classroom[i].id);
fflush(stdin);
__fpurge(stdin);
printf("Gender?");
scanf("%c",&classroom[i].gender);
printf("Age?");
scanf("%d",&classroom[i].age);
printf("GPA?");
scanf("%lf",&classroom[i].gpa);
}
}

Resources