I am making a sorting program for a final assignment. It takes the account number, last name, and balance of the account and sorts it in ascending order based on the account number. The issue I am having with my program is that once it gets to the for loop to output the information, it completely skips it. I believe it might have to do with my bubble sort function, but I am not sure how to fix it. We haven't been taught quick sort, so I am not using it. I am receiving an error: incompatible type for argument 1 of `sort', but I cannot change the array to type struct without it causing more issues. Here is my code:
#include <stdio.h>
/* Define structure */
struct account
{
int number;
char full_name[30];
float balance;
};
/* Function prototype */
void sort (int[], int);
/* Begin main function */
int main()
{
/* Declare variables */
struct account person[5];
int x=0, i=0, count=0;
printf("Enter account number, last name, and balance.\n");
printf("Enter -999 to end input:\n\n");
/* Create loop for user information */
while(1)
{
scanf("%i", &person[x].number);
if(person[x].number == -999) /*Break when -999 is input */
{
count = x;
break;
}
if(person[x].number < 1 || person[x].number >1000)
{
printf("***Invalid account number. Please enter 1 - 1000 or -999 to exit***\n");
x--;
continue;
}
scanf("%s", person[x].full_name);
scanf("%f", &person[x].balance);
if(person[x].balance < 0)
{
printf("*** Invalid balance amount. Please enter a positive value. ***\n");
x--;
continue;
}
}/* End of while loop */
/* Call to sort function to sort information */
sort(person[x].number, count);
/* Display the information in ascending order */
printf("ACCOUNT\tLAST NAME\tBALANCE\n");
/* Create for loop to output the sorted information */
for(x=0; x < count; x++)
{
printf("%d\t%s\t%f\n",person[x].number,person[x].full_name,person[x].balance);
} /* End of for loop */
}/* End of main */
/* Start sort function */
void sort(int p[], int count)
{
/* Declare variables.*/
char changed = 'T'; /* a "flag" to indicate if a swap was made.*/
int x, temp;
while (changed == 'T')
{
changed = 'F';
/* Create for loop for swaping information */
for (x = 0; x < count-1; x++)
{
if ( p[x] > p[x + 1])
{
/* Swap needs to be made.*/
temp = p[x];
p[x] = p[x+1];
p[x+1] = temp;
/* Set flag indicating that a swap was made. This ensures that */
/* processing will continue, until nothing needs to be swapped. */
changed = 'T';
}
} /* end for loop */
} /* end while loop*/
} /* end function sort */
Here is my output:
Enter account number, last name, and balance.
Enter -999 to end input:
10 Happy 55.00
15 Day 60.00
35 Man 75.00
-999
ACCOUNT LAST NAME BALANCE
Press any key to continue . . .
I appreciate your assistance and the time you are taking to help!
first as mentioned in comments add x++ at the end of your while-loop to scan data.
also you should know that by sending one member of struct (number) to your sort function , and sorting it , other members won't be sorted (only another number will be replaced with theirs).
also note here sort(person[x].number, count); you are sending one element of member number from struct to function . while in declaration of function ,you said you will send an array of integer to it.
this should be sort(person, count); and in function deceleration you should
use sort(struct account p[],int count); also you have to change function by using p[x].number.
also note that to add x++ at the end of your while-loop , you have to remove those continue , otherwise when you do x-- you won't reach x++.
I wrote another sort function which I think is more logical.
struct account
{
int number;
char full_name[30];
float balance;
};
void sort(struct account p[], int count);
int main()
{
struct account person[5];
int x = 0, i = 0, count = 0;
printf("Enter account number, last name, and balance.\n");
printf("Enter -999 to end input:\n\n");
while (1)
{
scanf("%i", &person[x].number);
if (person[x].number == -999)
{
count = x;
break;
}
if (person[x].number < 1 || person[x].number >1000)
{
printf("***Invalid account number. Please enter 1 - 1000 or -999 to exit***\n");
x--;
//remove continue
}
scanf("%s", person[x].full_name);
scanf("%f", &person[x].balance);
if (person[x].balance < 0)
{
printf("*** Invalid balance amount. Please enter a positive value. ***\n");
x--;
//remove continue
}
x++;//add x++
}
sort(person, count);//new function sort
printf("ACCOUNT\tLAST NAME\tBALANCE\n");
for (x = 0; x < count; x++)
{
printf("%d\t%s\t%f\n", person[x].number, person[x].full_name, person[x].balance);
}
}
void sort(struct account p[], int count)
{
char changed = 'T';
int x, temp;
float btemp;
char ntemp[30];// btemp for balance and ntemp for full_name
while (changed == 'T')
{
changed = 'F';
for (x = 0; x < count - 1; x++)
{
if (p[x].number > p[x + 1].number)
{
temp = p[x].number;
p[x].number = p[x + 1].number;
p[x + 1].number = temp;
btemp = p[x].balance;
p[x].balance = p[x + 1].balance;
p[x + 1].balance = btemp;
strcpy(ntemp , p[x].full_name);
strcpy(p[x].full_name , p[x + 1].full_name);
strcpy(p[x + 1].full_name , ntemp);
changed = 'T';
}
}
}
}
Related
I am new to programming so this is difficult for me. I need the program to end if the user's first input is -999, if not then they go on to input the account_num, last_name, and balance. But if the user enters -999 after the first input then it ends their input and displays the results. I cannot figure out how to get this whole -999 part to work while making my client[x].account_num be sorted in ascending order.. My code is below.
#include <stdio.h>
void bubble_sort(int[], int);
struct information
{
int account_num;
char last_name[30];
float balance;
};
int main()
{
/* declare variables */
struct information client[5];
int i, x, temp;
char c;
/* Prompt user */
printf ("Enter account number, last name, and balance.\n");
printf ("Enter -999 to end input:\n\n");
/* prompt user to enter number of people */
x = 0;
while (client[x].account_num != -999)
{
int tmp;
scanf ("%i", &tmp);
/* if types -999 as their first input program ends */
if (tmp == -999)
{
break;
}
else if (tmp < 1 || tmp > 1000)
{
printf ("*** Invalid account number. Please enter 1 - 1000 or -999 to exit ***\n");
}
else
{
client[x].account_num = tmp;
x ++;
}
bubble_sort(client[x].account_num, i);
scanf("%s", client[x].last_name);
while ( (c = getchar() != '\n') && c != EOF); /* clear input buffer. */
scanf("%.2f", &client[x].balance);
}
for (x = 0; x < 5; x++)
printf("%i\n", &client[x].account_num);
return 0;
}
void bubble_sort(int list[], int i)
{
int e, d, t;
for (e = 0; e < (i - 1); e++)
{
for (d = 0; d < i - e - 1; d++)
{
if (list[d] > list[d + 1])
{
/* swapping */
t = list[d];
list[d] = list[d + 1];
list[d + 1] = t;
}/* end for*/
}/*end for*/
}/* end for */
}/* end function */
There are several issues here. First, you don't want to index account_num and balance in the struct, unless you want to have several account numbers and balances per account holder. I also suggest replacing the for with a while loop so you don't have to fiddle with the loop counter x in case the user enters an invalid account number. Finally, for the sake of clarity I introduced a temporary variable tmpfor input and performed all tests on it, assigning the content to the account structure only if all validity tests were passed. tmpis only needed inside the whileloop which is why I declared it there, instead of making it part of the declarations in main().
#include <stdio.h>
#define MAX_CLIENTS 5
#define MAX_ACCOUNTS 1000
struct information
{
int account_num;
char last_name[30];
float balance;
};
int main()
{
/* declare variables */
struct information client[MAX_CLIENTS];
int i, x, people;
char c;
/* Prompt user */
printf ("Enter account number, last name, and balance.\n");
printf ("Enter -999 to end input:\n\n");
/* prompt user to enter number of people */
x = 0;
while (x < MAX_CLIENTS)
{
int tmp;
scanf ("%i", &tmp);
/* if types -999 as their first input program ends */
if (tmp == -999)
{
break;
}
else if (tmp < 1 || tmp > MAX_ACCOUNTS)
{
printf ("*** Invalid account number. Please enter 1 - %d or -999 to exit ***\n", MAX_ACCOUNTS);
}
else
{
client[x].account_num = tmp;
x ++;
}
}
return 0;
}
The code is from Absolute beginner's guide to C, and I get this error ./BlackJack.c<41> : warning C4047: '==' : 'int' differes in levels of indirection from 'char [2]' when I try to compile it in Visual Studio. This is the main function of a Blackjack game.
Line <41> is if (ans == "H") {
main()
{
int numCards; /* Equals 52 at the beginneing */
int cards[52], playerPoints[2], dealerPoints[2], total[2];
/* For user Hit/Stand or Yes/No response */
do { initCardsScreen(cards, playerPoints, dealerPoints, total, &numCards);
dealerGetsCard(&numCards, cards, dealerPoints);
printf("\n");
playerGetsCard(&numCards, cards, playerPoints);
playerGetsCard(&numCards, cards, playerPoints);
do {
ans = getAns("Hit or stand (H/S)? ");
if (ans == "H") {
platerGetsCard(&numCards, cards, playerPoints);
}
}
while ( ans != 'S');
totalIt(playerPoints, total, PLAYER);
/* Player's total */
do {
dealerGetsCard(&numCards, cards, dealerPoints);
} while (dealerPoints[ACEHIGH] < 17);
/* 17: Dealer stop */
totalIt(dealerPoints, total, DEALER);
/* Dealer's total */
findWinner(total);
ans = getAns("\nPlay again (Y/N)? ");
} while (ans == 'Y');
return;
}
(Update): Here is the entire code.
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#define BELL '\a'
#define DEALER 0
#define PLAYER 1
#define ACELOW 0
#define ACEHIGH 1
int askedForName = 0;
/****************************
This program specific prototype
****************************/
void dispTitle(void);
void initCardsScreen(int cards[52], int playerPoints[2], int dealerPoints[2], int total[2], int * numCards);
int dealCard(int * numCards, int cards[52]);
void dispCard(int cardDrawn, int points[2]);
void totalIt(int points[2], int total[2], int who);
void dealerGetsCard(int *numCards, int cards[52], int dealerPoints[2]);
void playerGetsCard(int *numCards, int cards[52], int playerPoints[2]);
char getAns(char mesg[]);
char ans;
void findWinner(int total[2]);
main()
{
int numCards; /* Equals 52 at the beginneing */
int cards[52], playerPoints[2], dealerPoints[2], total[2]; /* For user Hit/Stand or Yes/No response */
do { initCardsScreen(cards, playerPoints, dealerPoints, total, &numCards);
dealerGetsCard(&numCards, cards, dealerPoints);
printf("\n");
playerGetsCard(&numCards, cards, playerPoints);
playerGetsCard(&numCards, cards, playerPoints);
do {
char ans = getAns("Hit or stand (H/S)? ");
if (ans == "H") {
playerGetsCard(&numCards, cards, playerPoints);
}
}
while ( ans != 'S');
totalIt(playerPoints, total, PLAYER);
/* Player's total */
do {
dealerGetsCard(&numCards, cards, dealerPoints);
} while (dealerPoints[ACEHIGH] < 17);
/* 17: Dealer stop */
totalIt(dealerPoints, total, DEALER);
/* Dealer's total */
findWinner(total);
ans = getAns("\nPlay again (Y/N)? ");
} while (ans == 'Y');
return;
}
void initCardsScreen(int cards[52], int playerPoints[2], int dealerPoints[2], int total[2], int *numCards)
{
int sub, val=1; /* This function's Work variables */
char firstName[15]; /* Holds user's first name */
*numCards = 52; /* Holds running total of number of cards */
for (sub = 0; sub <= 51; sub++) { /* Counts from 0 to 51 */
val = (val == 14) ? 1 : val; /* If val is 14 reset to 1 */
cards[sub] = val;
val++; }
for (sub = 0; sub <= 1; sub++) { /* Counts from 0 to 1 */
playerPoints[sub] = dealerPoints[sub] = total[sub]=0; }
dispTitle();
if (askedForName ==0) { /* Name asked for nly once */
printf("\nWhat is your first name? ");
scanf_s(" %s", firstName);
askedForName = 1; /* Don't ask prompt again */
printf("Ok, %s, get ready for casino action!\n\n", firstName);
getchar(); /* Discards newline. You can safely */
} /* ignore compiler warning here. */
return;
}
/*** This function gets a card for the player and updates the player's points. ***/
void playerGetsCard(int *numCards, int cards[52], int playerPoints[2])
{
int newCard;
newCard = dealCard(numCards, cards);
printf("You draw: ");
dispCard(newCard, playerPoints);
}
/*** This function gets a card for the dealer and updates the dealer's poimts. ***/
void dealerGetsCard(int *numCards, int cards[52], int dealerPoints[2])
{
int newCard;
newCard = dealCard(numCards, cards);
printf("The dealer draws: ");
dispCard(newCard, dealerPoints);
}
/*** This function gets a card from the deck and stores it in either the dealer's or the player's hold of cards ***/
int dealCard(int * numCards, int cards[52])
{
int cardDrawn, subDraw;
time_t t; /* Gets time for a random value */
srand((unsigned int)(time(&t))); /* Seeds random-number generator */
subDraw = (rand() % (*numCards)); /* From 0 to numcards */
cardDrawn = cards[subDraw];
cards[subDraw] = cards[*numCards -1]; /* Puts top card */
(*numCards); /* in place of drawn one */
return cardDrawn;
}
/*** Displays the last drawn card and updates points with it. ***/
void dispCard(int cardDrawn, int points[2])
{
switch (cardDrawn) {
case(11) : printf("%s\n", "Jack");
points[ACELOW] += 10;
points[ACEHIGH] += 10;
break;
case(12) : printf("%s\n", "Queen");
points[ACELOW] += 10;
points[ACEHIGH] += 10;
break;
case(13) : printf("%s\n", "King");
points[ACELOW] += 10;
points[ACEHIGH] += 10;
break;
default : points[ACELOW] += cardDrawn;
if (cardDrawn == 1)
{
printf("%s\n", "Ace");
points[ACEHIGH] += 11;
}
else
{
points[ACEHIGH] += cardDrawn;
printf("%d\n", cardDrawn);
}
} return;
}
/*** Figure the total for player or dealer to see who won. This function takes into account the fact that Ace is either 1 or 11. ***/
void totalIt(int points[2], int total[2], int who)
{
/* The following routine first looks to see if the total points counting Aces as 1 is equal to the total points couning Aces as 11. If so,
or if the total points counting Aces as 11 is more than 21, the program uses the total with Aces as 1 only */
if ((points[ACELOW] == points[ACEHIGH]) || (points[ACEHIGH] > 21)) {
total[who] = points[ACELOW]; /* Keeps all Aces as 1 */
}
else {
total[who] = points[ACEHIGH]; /* Keeps all Aces as 11 */
}
if (who == PLAYER) /* Determines the message printed */ {
printf("You have a total of %d\n\n", total[PLAYER]);
}
else {
printf("The house stands with a total of %d\n\n", total[DEALER]);
}
return;
}
/*** Prints the winning player. ***/
void findWinner(int total[2])
{
if (total[DEALER] == 21) {
printf("The house wins.\n");
return;
}
if ((total[DEALER] > 21) && (total[PLAYER] > 21)) {
printf("%s", "Nobody wins.\n");
return;
}
if ((total[DEALER] >= total[PLAYER]) && (total[DEALER] < 21)) {
printf("The house wins.\n");
return;
}
if ((total[PLAYER] > 21) && (total[DEALER] < 21)) {
printf("The house wins.\n");
return;
}
printf("%s%c", "You win!\n", BELL);
return;
}
/*** Gets the user's uppercase, single-character response. ***/
char getAns(char mesg[])
{
char ans;
printf("%s", mesg); /* Prints the prompt message passed */
ans = getchar();
getchar(); /* Discards newline. You can safely ignore compiler warning here. */
return toupper(ans);
}
/*** Clears everything off the screen. ***/
void dispTitle(void)
{
int i=0;
while (i < 25) { /* Clears screen by printing 25 blank lines to 'push off' stuff that
might be left over on the screen before this program */
printf("\n");
i++;
}
printf("\n\n*Step right up to the Blackjack tables*\n\n");
return;
}
Notice how all of your other comparisons have single quotes?
while (ans == 'Y')
There, you're comparing a single character (which is a number, and thus comparable to another number).
In the code that's failing, on the other hand, you're using double quotes.
ans == "H"
So you're comparing to a string, which is an array of chars. The array is two characters long to accommodate the null terminator.
"H" (in double quotes) is a string, not a character. To get a character constant containing the letter H, you need 'H' (in single quotes.) So, your line should read if( ans == 'H' ).
What will also work is if( ans == "H"[0] ). This will compare ans against the first (zero-th) character of the string "H".
I agree that this is an insanely cryptic message for a simple type mismatch error. Blame it on C and C compilers. (May I suggest that you use some more modern language like C# or Java?)
The compiler reports your ans as an int while you may have declared it as a char. (I do not know how you have declared it, because you seem to have omitted its declaration from the source code that you posted.) If that is happening, it is because the compiler implicitly converts the char to int while trying to compare it with something else.
The compiler also reports your "H" as a char[2], and it might not be immediately obvious why: C uses null-terminated strings, so the literal "H" is represented as a 2-character array, where the first character is 'H' and the second character is the null character. ('\0').
And then the compiler mumbles something about different levels of indirection instead of telling you that the types you are trying to compare are incompatible. That's because in trying to perform the comparison the compiler considers "H" not as an array of characters, but as a pointer to the first character of the array, but that still does not help, because what it ends up with is a pointer to a character, (one level of indirection,) while it needs a character. (Zero levels of indirection.)
The question is that show the digits which were repeated in C.
So I wrote this:
#include<stdio.h>
#include<stdbool.h>
int main(void){
bool number[10] = { false };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] == true)
{
printf("%d ", digit);
}
number[digit] = true;
n /= 10;
}
return 0;
}
But it will show the repeated digits again and again
(ex. input: 55544 output: 455)
I revised it:
#include<stdio.h>
int main(void){
int number[10] = { 0 };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] == 1)
{
printf("%d ", digit);
number[digit] = 2;
}
else if (number[digit] == 2)
break;
else number[digit] = 1;
n /= 10;
}
return 0;
}
It works!
However, I want to know how to do if I need to use boolean (true false), or some more efficient way?
To make your first version work, you'll need to keep track of two things:
Have you already seen this digit? (To detect duplicates)
Have you already printed it out? (To only output duplicates once)
So something like:
bool seen[10] = { false };
bool output[10] = { false };
// [...]
digit = ...;
if (seen[digit]) {
if (output[digit])) {
// duplicate, but we already printed it
} else {
// need to print it and set output to true
}
} else {
// set seen to true
}
(Once you've got that working, you can simplify the ifs. Only one is needed if you combine the two tests.)
Your second version is nearly there, but too complex. All you need to do is:
Add one to the counter for that digit every time you see it
Print the number only if the counter is exactly two.
digit = ...;
counter[digit]++;
if (counter[digit] == 2) {
// this is the second time we see this digit
// so print it out
}
n = ...;
Side benefit is that you get the count for each digit at the end.
Your second version code is not correct. You should yourself figured it out where are you wrong. You can try the below code to print the repeated elements.
#include<stdio.h>
int main(void){
int number[10] = { 0 };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] > 0)
{
number[digit]++;;
}
else if (number[digit] ==0 )
number[digit] = 1;
n /= 10;
}
int i=0;
for(;i<10; i++){
if(number[i]>0)
printf("%d ", i);
}
return 0;
}
In case you want to print the repeated element using bool array (first version) then it will print the elements number of times elements occur-1 times and in reverse order because you are detaching the digits from the end of number , as you are seeing in your first version code output. In case you want to print only once then you have to use int array as in above code.
It is probably much easier to handle all the input as strings:
#include <stdio.h>
#include <string.h>
int main (void) {
char str[256] = { 0 }; /* string to read */
char rep[256] = { 0 }; /* string to hold repeated digits */
int ri = 0; /* repeated digit index */
char *p = str; /* pointer to use with str */
printf ("\nEnter a number: ");
scanf ("%[^\n]s", str);
while (*p) /* for every character in string */
{
if (*(p + 1) && strchr (p + 1, *p)) /* test if remaining chars match */
if (!strchr(rep, *p)) /* test if already marked as dup */
rep[ri++] = *p; /* if not add it to string */
p++; /* increment pointer to next char */
}
printf ("\n Repeated digit(s): %s\n\n", rep);
return 0;
}
Note: you can also add a further test to limit to digits only with if (*p >= '0' && *p <= '9')
output:
$./bin/dupdigits
Enter a number: 1112223334566
Repeated digit(s): 1236
Error is here
if (number[digit] == true)
should be
if (number[digit] == false)
Eclipse + CDT plugin + stepping debug - help you next time
As everyone has given the solution: You can achieve this using the counting sort see here. Time complexity of solution will be O(n) and space complexity will be O(n+k) where k is the range in number.
However you can achieve the same by taking the XOR operation of each element with other and in case you got a XOR b as zero then its means the repeated number. But, the time complexity will be: O(n^2).
#include <stdio.h>
#define SIZE 10
main()
{
int num[SIZE] = {2,1,5,4,7,1,4,2,8,0};
int i=0, j=0;
for (i=0; i< SIZE; i++ ){
for (j=i+1; j< SIZE; j++){
if((num[i]^num[j]) == 0){
printf("Repeated element: %d\n", num[i]);
break;
}
}
}
}
This has stumped me for a few days now. I have tried searching but have turned up mostly just definitions for struct...
In an if loop I set 2 struct variables, but neither of them come out correct. guests[x].plusone is stuck at 0 and guests[x].plusonefood is simply empty. If I set them (with the same line) outside of the loop, however, there are no issues. My compiler shows no warnings or errors. What am I missing?
This is my first project with C, so please point out anything else you notice, too.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct guestinfo
{
char name[50];
short int plusone;
char food[50];
char plusonefood[50];
};
char temp[5];
char setfood (int f)
{
char foodtemp[f];
int x;
for (x=0; x < f; x++)
{
printf("Food option %d:\n", (x+1));
fgets(&foodtemp[x],100,stdin);
}
return *foodtemp;
}
int main ()
{
int number_of_rsvp=0;
int number_of_food=0;
printf("Number of food choices:\n");
fgets(temp,5,stdin);
number_of_food = atoi (temp);
while (number_of_food <= 0)
{
printf("Please enter a number greater than 0\n");
fgets(temp,5,stdin);
number_of_food = atoi (temp);
}
char food [50] [number_of_food];
**food = setfood(number_of_food);
printf("Number of RSVPs:\n");
fgets(temp,5,stdin);
number_of_rsvp = atoi (temp);
while (number_of_rsvp <= 0)
{
printf("\nPlease enter a number greater than 0\n");
fgets(temp,5,stdin);
number_of_rsvp = atoi (temp);
};
struct guestinfo guests[number_of_rsvp];
int x;
int f;
for (x=0; x < number_of_rsvp; x++)
{
// add input validation to this section
printf("Guest Number %d:\n\nGuest Name:\n", (x+1));
fgets(guests[x].name,50,stdin);
printf("Food Choice #:\n");
fgets(temp,3,stdin);
f = atoi(temp);
f--;
*guests[x].food = food [50] [f];
printf("Plus One? Y/N\n");
fgets(temp,3,stdin);
}
if (strchr (temp,'Y') != NULL || strchr (temp,'y') != NULL) //This loop
{
guests[x].plusone = 1;
printf("Plus one food choice #:\n");
fgets(temp,3,stdin);
f = atoi(temp);
f--;
*guests[x].plusonefood = food [50] [f];
}
else if (strchr (temp,'N') != NULL || strchr (temp,'n') != NULL)
{
guests[x].plusone = 0;
};
FILE *guestlist = fopen ("guestlist.txt","w");
// debugging
printf("%d\n",guests[0].plusone);
printf("%s\n",guests[0].plusonefood);
for (x=0; x < number_of_rsvp; x++)
{
fprintf(guestlist,"Guest Number %d:\n\nName: %s\nFood Choice: %s\n",(x+1),guests[x].name,guests[x].food);
switch (guests[x].plusone)
{
case 1:
{
fprintf(guestlist,"Plus One: Yes\n\tPlus One Food: %s\n\n",guests[x].plusonefood);
break;
}
case 0:
{
fprintf(guestlist,"Plus One: No\n\n");
break;
}
default:
{
break;
}
}
}
fclose (guestlist);
printf("Printing Guest List...\n");
return 0;
}
The problem is that you are accessing an invalid memory place.
The array has number_of_rsvp elements.
Your for() loop interates over the variable x up to the value number_of_rsvp and exits.
After that, the value of x is equal to number_of_rsvp.
Since the index of the array only can go from 0 to number_of_rsvp - 1, the element guests[x], which is guests[number_of_rsvp], is out-of-bound.
Problem: Trying to sort an array coming from a typedef struct I created (phonebook).
Goal: Trying to build a phonebook that allows users to add, delete, sort, and print the phonebook.
Where I'm at: I've got everything working except the sort. I've cobbled together a sort function from reading various web forums/examples, but can't get it to work.
Issue I'm having: After adding entries (which works fine), if you try to sort entries, the function zeroes out values of those entries and when you print the phonebook, it shows all entries as blank. It should sort them alphabetically by last name.
Here's the sort algorithm I have in place:
void Sort (phone phonebook[])
{
phone temp;
int i; int j;
for (i=0; i<19; i++)
{
for (j=i+1; j<19; j++)
{
if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0)
{
temp=phonebook[i];
phonebook[i]=phonebook[j];
phonebook[j]=temp;
}
}
}
}
Any ideas?
Full code here:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//typedef struct to define what's in the phonebook
typedef struct PhoneBookContacts
{
char Name[20];
char Surname[20];
char PhoneNumber[20];
} phone;
//Function prototypes
void AddEntry (phone[]);
void DeleteEntry (phone[]);
void PrintEntry (phone[]);
void Sort (phone[]);
int counter = 0; //Global counter variable used to keep track of number of contacts
//Begin main function
int main (void)
{
phone phonebook[20]; //Phonebook instance
char userChoice; //Variable to use to select menu choice
while (userChoice != 'Q') {
printf ("***************\n");
printf ("Please enter a command:\n");
printf("'A': Add an entry\n");
printf("'D': Delete an entry\n");
printf("'S': Sort entries\n");
printf("'P': Print the phonebook\n");
printf("'Q': Quit\n");
printf ("***************\n");
scanf("%s", &userChoice); //Stores menu choice into variable userChoice
// Add Contact
if (userChoice == 'A')
AddEntry(phonebook);
//Remove Contact
if (userChoice == 'D')
DeleteEntry (phonebook);
//Print Contacts
if (userChoice == 'P')
PrintEntry(phonebook);
//Sort Contacts
if (userChoice == 'S')
Sort(phonebook);
//Quit
if (userChoice == 'Q') {
printf("Phonebook will now quit.");
return 0;
}
}
}
//Function Definition to Add Contacts to the Phonebook
void AddEntry (phone phonebook[]) {
counter++; //global counter increase
printf("\nFirst Name: ");
scanf("%s", phonebook[counter-1].Name); //counter-1 b/c arrays start at 0
printf("Last Name: ");
scanf("%s", phonebook[counter-1].Surname);
printf("Phone Number (XXX-XXX-XXXX): ");
scanf("%s", phonebook[counter-1].PhoneNumber);
printf("\n%s added to phonebook\n", phonebook[counter-1].Name); //tell user friend added
}
void DeleteEntry (phone phonebook[])
{
int x = 0;
char deleteName[20]; // Temp string to compare to existing phonebook
char deleteSurname[20]; //temp string
char nullStr[20] = {"\0"}; // empty string to remove phonenumber
printf("\nEnter name: ");
scanf("%s", deleteName); //place into temp string
printf("Enter Surname: ");
scanf("%s", deleteSurname); //place into temp string
for (x = 0; x < counter; x++)
{
if (strcmp(deleteName, phonebook[x].Name) == 0) //compare deleteName to phonebook.Name
{
for (x = 0; x < counter; x++)
{
if (strcmp(deleteSurname, phonebook[x].Surname) == 0) //If deleteSurname matches phonebook.Surname
{
strcpy(phonebook[x].Name, nullStr); //Put null into Name
strcpy(phonebook[x].Surname, nullStr); //Null into Surname
strcpy(phonebook[x].PhoneNumber, nullStr); //Null into PhoneNumber
printf("Contact removed from phonebook.\n");
counter--;
break;
}
}
}
else printf("Invalid entry--try again.\n");
}
}
// Function def to print contacts
void PrintEntry (phone phonebook[]) {
int x = 0;
printf("\nPhonebook entries:\n");
for ( x = 0; x < counter; x++) {
printf("\n(%d)\n", x+1); //Show contact number
printf("Name: %s %s\n", phonebook[x].Name, phonebook[x].Surname); //Name
printf("Number: %s\n", phonebook[x].PhoneNumber); //Number
}
}
void Sort (phone phonebook[]) {
phone temp;
int i; int j;
for (i=0; i<19; i++) {
for (j=i+1; j<19; j++) {
if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0) {
temp=phonebook[i];
phonebook[i]=phonebook[j];
phonebook[j]=temp;
}
}
}
}
You can use the already implemented sorting function qsort function available at stdlib.h:
int SortFunc(void* a, void* b) {
phone *p1 = (phone*)a;
phone *p2 = (phone*)b;
return strcmp(p1->Surname, p2->Surname);
}
void Sort (phone phonebook[]) {
qsort(phonebook, counter, sizeof(phone), &SortFunc);
}
The function is usually Quicksort, but that's up to the C library implementation to decide.
Update:
The blank listing is because the sorting is reversed and always sorting all the 19 items of the phonebook, comparing the empty ones against the real ones. If you have less than 19 entries on the phonebook, the actual data is going to be present at the end of the phonebook array.
Your original Sort function was always working almost OK. Just change the end condition on the two for.
void Sort (phone phonebook[]) {
phone temp;
int i; int j;
for (i=0; i<counter; i++) {
for (j=i+1; j<counter; j++) {
if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0) {
temp=phonebook[i];
phonebook[i]=phonebook[j];
phonebook[j]=temp;
}
}
}
}
I've also updated my Sort above.
First things first, you have a buffer overflow issue here:
char userChoice;
:
scanf("%s", &userChoice);
That scanf will write two bytes when you enter one character (the character plus a null terminator). This corrupted the first name of the first phonebook entry in my environment but, since it's undefined behaviour, it could do anything!
You can get around this by using:
char userChoice[] = "something that's not Q";
:
scanf("%s", userChoice);
:
if (*userChoice == 'A') // for all of these.
That won't stop a buffer overflow if you enter enough text but it will if you limit yourself to single character commands. If you want a truly robust user input function, see here.
Now to your specific problem. It looks like you have a bit of a bubble sort going on there, but your logic is slightly off. Assuming you don't want to use qsort (which would be the better way for real code), you just need to fix up a couple of things.
Your outer loop is okay, as is your inner loop, but the inner loop body should be comparing elements j and j+1, not j and i. That's because it works by swapping adjacent elements if they're out of order.
In addition, a forward focused bubble sort will place the highest element at the end of the list on the first pass, so you can't start j at i+1 on the second pass, simply because the first element may not be correct yet.
The following psuedo-code is your classic bubble sort:
didSwap = true
while didSwap:
didSwap = false
for i = 0 to lastidx - 1:
if array[i] > array[i+1]:
temp = array[i]
array[i] = array[i+1]
array[i+1] = temp
didSwap = true
Read that, understand how it works, then implement it on your own. If you have trouble with that, I've included a working version below:
void Sort (phone phonebook[]) {
phone temp;
int i; int didSwap;
didSwap = 1;
while (didSwap) {
didSwap = 0;
for (i = 0; i < counter - 1; i++) {
if (strcmp(phonebook[i].Surname, phonebook[i+1].Surname) > 0) {
temp=phonebook[i];
phonebook[i]=phonebook[i+1];
phonebook[i+1]=temp;
didSwap = 1;
}
}
}
}
for (i=0; i<19; i++)
{
for (j=i+1; j<19; j++)
{
if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0)
{
temp=phonebook[i];
phonebook[i]=phonebook[j];
phonebook[j]=temp;
}
}
}
Three problems with your code. First is the logic of your algorithm. Bubble sort works by fixing the order of two adjacent element. In your code, after the first iteration of your inner for loop, it's not going to compare two adjacent elements.
The second problem, again in sorting algorithm, your counters i and j are both going to 19, even when there is less entries than that. This might mess up the sorting as they will be reading invalid(uninitialized) entry. you should check the upper bound for the counter.
The next one is in the deletion
if (strcmp(deleteName, phonebook[x].Name) == 0) //compare deleteName to phonebook.Name
{
for (x = 0; x < counter; x++)
{
if (strcmp(deleteSurname, phonebook[x].Surname) == 0) //If deleteSurname matches phonebook.Surname
{
strcpy(phonebook[x].Name, nullStr); //Put null into Name
strcpy(phonebook[x].Surname, nullStr); //Null into Surname
strcpy(phonebook[x].PhoneNumber, nullStr); //Null into PhoneNumber
printf("Contact removed from phonebook.\n");
counter--;
break;
}
}
}
The code above will not check properly whether the first and last name since you're checking them separately. You only need one for loop with if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 )