Bubble Sort in ANSI C - c

I have an assignment that needs the data sorted. Ive been trying to use the bubble sort method to sort the data however it does not seem to work. I have attached the assignment to allow you to understand what I am doing. I am not looking for the answer but for help. I am also wondering how the sales_id would incorporate into that since it is not an array and also needs to be sorted.
#include <stdio.h>
struct sales_commissions {
float commissions[3];
};
struct sales {
char sales_name[30];
int sales_id;
struct sales_commissions sc;
};
void comp_name(char company_name[15]);
int agent_number();
void agent_info(char[], int sales_agents, int sales_id, float[]);
void sorting(char[], int sales_agents, int sales_id, float[], char []);
main() {
/* --- Declaring Variables --- */
char company_name[15];
char c;
int i;
int sales_agents;
struct sales Sales;
comp_name(company_name);
sales_agents = agent_number();
agent_info(Sales.sales_name, sales_agents, Sales.sales_id, Sales.sc.commissions);
sorting(Sales.sales_name, sales_agents, Sales.sales_id, Sales.sc.commissions, company_name);
return 0;
}
void comp_name(char company_name[15]) {
printf("Welcome to the Sears Commission analysis\n");
printf("Enter the Company Name: ");
scanf("%[^\n]s", company_name);
return company_name;
}
int agent_number() {
char c;
int sales_agents = 0;
printf("Enter the number of sales agents (1 - 20): ");
scanf("%d", &sales_agents);
while ((c = getchar() != '\n') && c != EOF);
while (sales_agents < 1 || sales_agents > 20) {
while (sales_agents == 0) {
printf("*** No number of sales agents entered. Quitting program. ***\n");
return 0;
}
printf("*** Invalid number of sales agents. Please enter 1 - 20. ***\n");
printf("Enter the number of sales agents (1 - 20): ");
scanf("%d", sales_agents);
while ((c = getchar() != '\n') && c != EOF);
}
return sales_agents;
}
void agent_info(char sales_name[], int agent_number, int sales_id,
float commissions[])
{
char c;
int i;
for (i = 0; i < agent_number; i++) {
printf("Enter the name of sales agent #%d: ", i + 1);
scanf("[^\n]s", sales_name[i]);
while ((c = getchar() != '\n') && c != EOF);
printf("Enter ID number for sales agent #%d: ", i + 1);
scanf("%[^\n]s", sales_id);
while ( (c = getchar() != '\n') && c != EOF);
printf("Enter Commission 1 for sales agent #%d: ", i + 1);
scanf("%[^\n]s", &commissions[0]);
while ( (c = getchar() != '\n') && c != EOF);
printf("Enter Commission 2 for sales agent #%d: ", i + 1);
scanf("%[^\n]s", &commissions[1]);
while ( (c = getchar() != '\n') && c != EOF);
printf("Enter Commission 3 for sales agent #%d: ", i + 1);
scanf("%[^\n]s", &commissions[2]);
while ( (c = getchar() != '\n') && c != EOF);
}
return sales_name;
}
void sorting(char sales_name[], int agent_number, int sales_id,
float commissions[], char company_name[])
{
int i;
int u;
int temp;
char c;
char temp2;
char swapped = 'Y';
printf("Did we get to sorting?\n");
while (swapped == 'Y') {
swapped = 'N';
for (i = 0; i < agent_number - 1; i++) {
if (commissions[i] < commissions[i + 1]) {
temp = commissions[i];
commissions[i] = commissions[i + 1];
commissions[i + 1] = temp;
for (u = 0; u < 50; u++) {
temp2 = sales_name[i][u];
sales_name[i][u] = sales_name[i + 1][u];
sales_name[i + 1][u] = temp2;
}
swapped = 'Y';
}
}
}
printf("%s\n", swapped);
printf("\n\nCommission Report -- %s\n\n", c);
printf("Agent Name\n\n");
for (i = 0; i < agent_number; i++) {
printf("%-12s \n\n", sales_name[i]);
}
}
I was trying to first try and see if I could get a bubble sort running given what is an array. I have tried to see if it could pair the name to the commission.
P.S I am exhausted so I will be checking responses in the morning, pardon my delayed response.

There are many problems in the code. You should enable more compiler warnings and fix the problems reported. Use gcc -Wall -Wextra -Werror or clang -Wall -Weverything -Werror.
The sort function prototype is incorrect: the argument Sales.sales_name is probably a 2D array char sales_name[20][50] and the sales_id is probably also an array, so the function prototype should be
void sorting(char sales_name[][50], int agent_number, int sales_id,
float commissions[], char company_name[]);
Furthermore, the swapping operation sales_name[i] = sales_name[i + 1][u]; should store to sales_name[i][u] instead and the temp variable must have the same type as the commissions element type: float.
Here is a modified version:
void sorting(char sales_name[][50], int agent_number, int sales_id[],
float commissions[], char company_name[]) {
char swapped = 'Y';
while (swapped == 'Y') {
swapped = 'N';
for (int i = 0; i < agent_number - 1; i++) {
if (commissions[i] < commissions[i + 1]) {
// swap the commission value?
float temp = commissions[i];
commissions[i] = commissions[i + 1];
commissions[i + 1] = temp;
// swap the agent ID?
int id = sales_id[i];
sales_id[i] = sales_id[i + 1];
sales_id[i + 1] = id;
// swap the agent name
for (int u = 0; u < 50; u++) {
char temp2 = sales_name[i][u];
sales_name[i][u] = sales_name[i + 1][u];
sales_name[i + 1][u] = temp2;
}
swapped = 'Y';
}
}
}
printf("\n\nCommission Report -- %s\n\n", company_name);
printf("Agent Name Commission\n\n");
for (int i = 0; i < agent_number; i++) {
printf("%-12s %.2f\n", sales_name[i], commissions[i]);
}
}
The while loop to read and discard the remainder of the input line is incorrect too: c must have type int to handle all possible byte values (all values of the type unsigned char) and the negative value EOF. You should encapsulate this inside a function:
// read and discard the remainder of the input line
// return the newline if found or EOF if none before the end of file
int flush_stdin(void) {
int c;
while ((c = getchar() != '\n') && c != EOF)
continue;
return c;
}
Most of the scanf conversions are incorrect:
scanf("[^\n]s", sales_name[i]) should be scanf("%49[^\n]", sales_name[i])
scanf("%[^\n]s", sales_id) should be scanf("%d", &sales_id[i])
scanf("%[^\n]s", &commissions[0]) should be scanf("%f", &commissions[0]) but it unclear what the commissions array represents: is the one per agent?
Instead of using a separate array for each sales agent data item, you should define a structure to describe each sales agent and use an array of such structures.

Related

Problem with counting elements in the list of names

I have made one program, where you enter a few characters (10 max). It makes you a list, count average length of surnames, tell about how much different names. But the problem is, when I enter the last number (10) - it sorts me it incorrectly (like 1, 10, 2, 3, 4, 5, 6, 7, 8, 9). Beneath I will present my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people {
char num[2];
char surname[20];
char name[10];
} peoples[10], c;
int main()
{
int i, j, k = 0, l = 0, m = 0, n = 0;
float s = 0;
char str[100];
system("chcp 1251 > nul");
for (i = 0, j = 0; i < 10; i++, j++)
{
printf("Enter number, surname, name %d of your human: ", i + 1);
gets(str);
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].num[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].surname[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != '\0')
{
peoples[j].name[k] = str[n];
}
else
break;
n++;
k++;
}
n = 0;
k = 0;
}
for (i = 0; i < 10; i++)
{
for (j = i + 1; j < 10; j++)
{
if (!strcmp(peoples[i].name, peoples[j].name))
m = 1;
}
if (m == 0)
l++;
m = 0;
s = s + strlen(peoples[i].surname);
}
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
if (strcmp(peoples[j].num, peoples[j+1].num) > 0)
{
c = peoples[j+1];
peoples[j+1] = peoples[j];
peoples[j] = c;
}
for (i = 0; i < 10; i++)
{
printf("%s ", peoples[i].num);
printf("%s ", peoples[i].name);
printf("%s ", peoples[i].surname);
printf("\n");
}
printf("\nYou have %d different names\n", l);
printf("Avarege lenght of surname is = %f\n", s / 10);
}
If you want to give numeric input, then use actual numeric data.
Change the num field to become an int instead of a single-character string:
struct people {
int num;
char surname[20];
char name[10];
};
Use fgets to read the line:
fgets(str, sizeof str, stdin);
[Error checking left as exercise for reader]
Then use e.g. sscanf for parse your string:
sscanf(str, "%d %s %s", &peoples[j].num, &peoples[j].name, &peoples[j].name);
[Error checking left as exercise for reader]
And finally, instead of doing your own sorting use the standard qsort function:
qsort(peoples, 10, sizeof(struct people), &compare_people_num);
With the comparison function being something like this:
int compare_people_num(const void *a, const void *b)
{
const struct people *p1 = a;
const struct people *p2 = b:
return p1->num - p2->num; // Change order to reverse sort
}
Using sscanf and qsort will make your code much simpler and easier to understand.

why can't my program recognize similar words in a string?

I want to write a program that will take an input T. In the next T lines, each line will take a string as an input. The output would be how many ways the string can be reordered.
#include <stdio.h>
#include <stdlib.h>
int main() {
int T, i, l, count = 1, test = 0, word = 0, ans;
char line[200];
scanf("%d", &T);
for (i = 0; i < T; i++) {
scanf(" %[^\n]", line);
l = strlen(line);
for (int q = 0; q < l; q++) {
if (line[q] == ' ') {
word++;
}
}
ans = fact(word + 1);
word = 0;
for (int j = 0; j < l; j++) {
for (int k = j + 1; k < l; k++) {
if (line[k] == ' ' && line[k + 1] == line[j]) {
int m = j;
int n = k + 1;
for (;;) {
if (line[m] != line[n]) {
break;
} else
if (line[m] == ' ' && line[n] == ' ') {
test = 1;
break;
} else {
m++;
n++;
}
}
if (test == 1) {
count++;
ans = ans / fact(count);
count = 0;
test = 0;
}
}
}
}
printf("%d\n", ans);
}
}
int fact(int n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
Now, in my program,
my output is like this:
2
no way no good
12
yes no yes yes no
120
if T = 2 and the 1st string is no way no good, it gives the right output that is 12 (4!/2!). That means, it has identified that there are two similar words.
But in the 2nd input, the string is yes no yes yes no. that means 3 yes and 2 nos. So the and should be 5!/(3!2!) = 10. But why is the answer 120? and why can't it recognize the similar words?
The main problem in your duplicate detector is you test the end of word with if (line[m] == ' ' && line[n] == ' ') but this test fails to identify a duplicate that occurs with the last word because line[n] is '\0', not ' '.
Note these further problems:
you do not handle words that occur more than twice correctly: you should perform ans = ans / fact(count); only after the outer loop finishes. For example, if a word is present 3 times, it will be detected as 3 pairs of duplicates, effectively causing ans to be divided by 23 = 8, instead of 3! = 6.
you should protect against buffer overflow and detect invalid input with:
if (scanf(" %199[^\n]", line) != 1)
break;
the range of type int for ans is too small for a moderately large number of words: 13! is 6227020800, larger than INT_MAX on most systems.
The code is difficult to follow. You should consider parsing the line into an array of words and using a more conventional way of counting duplicates.
Here is a modified version using this approach:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int cmpstr(const void *p1, const void *p2) {
char * const *pp1 = p1;
char * const *pp2 = p2;
return strcmp(*pp1, *pp2);
}
unsigned long long factorial(int n) {
unsigned long long res = 1;
while (n > 1)
res *= n--;
return res;
}
int main() {
int T, i, n, begin, count;
unsigned long long ans;
char line[200];
char *words[100];
if (!fgets(line, sizeof line, stdin) || sscanf(line, "%d", &T) != 1)
return 1;
while (T --> 0) {
if (!fgets(line, sizeof line, stdin))
break;
n = 0;
begin = 1;
for (char *p = line; *p; p++) {
if (isspace((unsigned char)*p)) {
*p = '\0';
begin = 1;
} else {
if (begin) {
words[n++] = p;
begin = 0;
}
}
}
qsort(words, n, sizeof(*words), cmpstr);
ans = factorial(n);
for (i = 0; i < n; i += count) {
for (count = 1; i + count < n && !strcmp(words[i], words[i + count]); count++)
continue;
ans /= factorial(count);
}
printf("%llu\n", ans);
}
return 0;
}

Why is my "c" variable growing exponentially when it reaches the 3rd cycle in the for loop?

I am having a problem, here with a program that is meant to be a data entry routine, the problem in question, is the variable c that goes to the capac function to ask the user for the maximum capacity of the string, when it reaches the 3rd cycle of the for it starts to grow god knows how, making my for, something unusable.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
int func_carac(int *car) //function that catches characters introduced by the user
{
int caracter;
printf("\nType the character you want: \n");
caracter = getche();
*car = caracter;
return *car;
}
//________________________________________________________\\
int func_capac(int *cap) //function to ask the user for the amount of characters
{
int quant;
printf("\nDetermine the maximum character capacity you want to write: ");
scanf("%d",&quant);
*cap = quant;
return *cap;
}
int main()
{
int car, pos, c, total;
char vetor[] = {'\0'};
func_capac(&c);
total = c + 1;
vetor[total];
vetor[total] = '\0';
printf("%i", c);
for(pos = 0; pos < c; pos++)
{
func_carac(&car);
if((car >= 97) && (car <= 122) || (car == 32))
{
printf("\n%c - Tabela ASCII, %d \n",car ,car);
printf("%i", c);
vetor[pos] = (char) car;
}
else if(car == 8)
{
printf("Successfully removed the previous character.");
pos = pos-2;
}
else
{
pos--;
}
}
printf("Frase: %s\n",vetor);
}
If someone could help me, I would be grateful
#Someprogrammerdude nailed it. vector[] = { '\0' } means that vector is an array of length 1. As you write to vector after position 0 you end up with undefined behavior (i.e. overwriting c somehow). Here is the minimal fix:
int main()
{
int car, pos, c, total;
func_capac(&c);
total = c + 1;
char vetor[total];
for(int i = 0; i < total; i++) vetor[i] = 0; // or memset(vector, 0, total);
...

Nested Loops C programming - I need to scan input to find sets of letters

I am trying to write a function to scan in a string and find sets of the capital letter 'O'. Say my string is yyyOOOyyyOOyyyOyyy, it should print:
a group of 3 capital letter O's have been found together.
a group of 2 capital letter O's have been found together.
a group of 1 capital letter O's have been found together.
I cannot find a good way to do this. I'm trying to use nested loops, but I just don't have enough experience with it yet. Here is what I have come up with so far (I know it is completely non-functional). My code is also not allowing a user input using scanf (I have to use scanf for the assignment) Any help in correcting my loops and getting scanf to work would be great! Thanks!
void problem_03_function(){
char double_o_string[30];
scanf("%s", &double_o_string);
int count_double_o = 0;
char capital_letter_O = 'O';
int num_in_str = 0;
for(num_in_str; num_in_str < strlen(double_o_string); num_in_str++){
if(double_o_string[num_in_str] == capital_letter_O){
count_double_o++;
}
printf("a group of %d capital letter O's have been found togeth$
}
}
In order to avoid having two places to print the message, one for Os in the middle of the string and an extra check for Os at the end, I'd suggest a solution like the following, where an inner loop consumes a sequences of characters until the a non-O or the EOF is consumed, and the outer loop prints a message if the leading sequence of Os was non-empty:
#include <stdio.h>
int main() {
int c, count;
do {
for (count=0; (c = getchar()) == 'O'; count++) {}
if (count)
printf("a group of %d O's found.\n", count);
} while (c != EOF);
return 0;
}
Here is the same with a string pointer instead of getchar():
void test(char *p) {
int c, count;
do {
for (count=0; (c = *(p++)) == 'O'; count++) {}
if (count)
printf("a group of %d O's found.\n", count);
} while (c != 0);
}
You might need to do something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* findSet(char *p) {
char cTS = 'o';
int i = 0;
int lastFound = 0;
int *array = malloc(sizeof(int) * 10); /* You can do better by allocating
dynamically because this will limit you to 10 sets only. */
int count = 0;
int lastPos = 0;
int strle = strlen(p);
for(; i < strle; i++) {
if(p[i] == cTS) {
count++;
lastFound = 1;
if(i == strle - 1) {
if(lastPos >= 10) return array;
array[lastPos++] = count;
break;
}
}
else {
if(lastFound) {
if(lastPos >= 10) return array;
array[lastPos++] = count;
}
count = 0;
lastFound = 0;
}
}
for(; 10 - lastPos;) {
array [lastPos++] = 0;
}
return array;
}
int main() {
int *x = findSet("ohoHeloooloo");
int i = 0;
for(; i < 10; i++) {
printf("%d", x[i]);
}
return 0;
}
Notice that you can change what you want to search for by changing cTS variable.
void show_fn(){
char double_o_string[30];
scanf("%s", double_o_string);
int count_double_o = 0;
int flag=0;
char capital_letter_O = 'O';
int num_in_str = 0;
for(num_in_str; num_in_str < strlen(double_o_string); num_in_str++){
if(double_o_string[num_in_str] == capital_letter_O){
flag=1;
count_double_o++;
if(num_in_str+1==strlen(double_o_string)){printf("a group of %d capital letter O's have been found together\n",count_double_o);}
}else{
if(flag==1){
printf("a group of %d capital letter O's have been found together\n",count_double_o);
count_double_o=0;flag = 0;
}
}
}
}
Try this:
void problem_03_function(){ // homework? ;)
char double_o_string[30];
scanf("%s", double_o_string); // Without & as double_o_string is already a pointer. See http://stackoverflow.com/questions/5406935/
int count_double_o = 0;
char capital_letter_O = 'O';
int num_in_str = 0;
int notice_not_printed = 0; // EDIT: simplified version of #kkaushi's answer
for( ; num_in_str < strlen(double_o_string); num_in_str++){ // You don't really need the first statement of for statement here
if(double_o_string[num_in_str] == capital_letter_O){
count_double_o++;
notice_not_printed = 1;
} else if (count_double_o) { // to prevent printing "a group of 0 capital..."
printf("a group of %d capital letter O's have been found together\n", count_double_o);
count_double_o = 0; // you need to reset the capital O count
notice_not_printed = 0;
}
}
// Used if the string ends with 'O'. See #kkaushi's answer
if (notice_not_printed)
printf("a group of %d capital letter O's have been found together\n", count_double_o);
}
void problem_03_function(){
const char capital_letter_O = 'O';
char double_o_string[30];
scanf("%s", &double_o_string);
int i = 0, o_gp= 0, o_gp_flag[3] = {0};
int len = strlen(double_o_string);
while(i < len){
o_gp = 0;
while(double_o_string[i++] == capital_letter_O){
if(++o_gp == 3 || i == len)break;
}//when o_gp > 3 , skip ?
if(o_gp)
o_gp_flag[o_gp-1] = 1;
}
for(i=0;i<3;++i)
if(o_gp_flag[i])
printf("a group of %d capital letter O's have been found togeth\n", i+1);
}
I think if you put this in your loop, it will work.
if(double_o_string[num_in_str] == capital_letter_O){
count_double_o++;
}
else if(count_double_o != 0) {
printf("a group of %d capital letter O's have been found togeth", count_double_o)
count_double_o = 0;
}

Can't get user input using getchar() and pointer notation in C

I'm changing a program from normal array notation to pure pointer notation and I can't receive user input using getchar() in a while loop. I printed out was the program was receiving and it output upside down question marks. I wasn't sure why this was happening because I never changed the variable type. The problem is in the second function to receive user input. Thank you for the help.
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes */
void fillS1(char * x);
void fillS2(char * x, char * y, char z);
void strFilter(char * a, char * b, char c);
int main(int argc, const char * argv[])
{
char s1[42];
char s2[22];
char x = 0;
fillS2(s2, s1, x);
return 0;
}
/* Function to generate a random string of 40 uppercase letters */
void fillS1(char randomlyGeneratedString[])
{
char * pointerToRandom = randomlyGeneratedString;
int i;
for (i = 0; i < 40; i++) {
*(pointerToRandom + i) = 'A' + rand() % 26;
}
pointerToRandom[40] = (char)0;
//printf("This is the generated string %s\n", pointerToRandom);
}
/* Function to get user input of characters */
void fillS2(char userString[], char randomString[], char replacementCharacter)
{
char * pointerToUserString = userString;
char * pointerToRandom = randomString;
int i = 0;
int n = 0;
int capitalLetterCheck = 0;
char loopContinue = 0;
char copyString[42];
char * pointerToCopyString = copyString;
fillS1(pointerToRandom);
do {
/* For loop to copy the first randomly generated string */
for(i = 0; i < 42; i++)
*(pointerToCopyString + i) = *(pointerToRandom + i);
i = 0;
capitalLetterCheck = 0;
/* While loop to to get user input */
printf("Please enter at least 2 capital letters and a maximum of 20.\n");
while (((*(pointerToUserString + i)) = getchar() != '\n')) {
/* Counter to determine how many characters were entered */
i++;
}
i++;
*(pointerToUserString + i) = '\0';
//printf("This is the value if i %i", i);
//printf("This is the user's string %s", pointerToUserString);
/* Capital letter check */
for (n = 0; n < 20; n++) {
if (((*(pointerToUserString + i)) >= 'A') && (*(pointerToUserString + i) <= 'Z'))
{
capitalLetterCheck++;
}
}
if (i < 3) {
printf("You need at least two letters\n");
}
else if (i > 21){
printf("You cannot have more than twenty letters\n");
}
else if (capitalLetterCheck >= 2) {
puts(pointerToUserString);
printf("Enter a character to replace occuring letters.\n");
scanf("%c", &replacementCharacter);
getchar();
strFilter(pointerToCopyString, pointerToUserString, replacementCharacter);
}
else
printf("You must have 2 capital letters.\n");
printf("Would you like to enter another string (y/n)?\n");
loopContinue = getchar();
getchar();
} while (loopContinue != 'n' && loopContinue != 'N');
}
/* Function to replace letters with the character chosen by the user */
void strFilter(char a[], char b[], char c)
{
char * pointerToA = a;
char * pointerToB = b;
int i = 0;
int n = 0;
while (n < 20) {
for (i = 0; i < 40; i++) {
if ((*(pointerToA + i)) == *(pointerToB + n)){
*(pointerToA + i) = c;
}
}
i = 0;
n++;
}
puts(a);
}
The problem is this in the if statement:
(*(pointerToUserString + i)) = getchar() != '\n'
Assignment is an expression, with lower precedence than comparison. This means the above is the same as:
(*(pointerToUserString + i)) = (getchar() != '\n')
So (*(pointerToUserString + i)) gets assigned the value of the expression getchar() != '\n' which is not what you want.

Resources