I have a C program that takes an array of strings, sorts using selection sort, and also searches a string in the sorted list. The selection sort doesn't work.
The code to display the string is OK. I also tried to verify if the smallest string is identified and yes it does. But it is not moved in its correct position as the selection sort should work. In the main function after displaying the unsorted strings, the program terminates. Where am I not doing the right thing?
Here is the code for the entire program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void doDisplay(char *council[15], int size) {
int i;
for (i = 0; i < 15; i++) {
//printf("\n%s", council[i]);
puts(council[i]);
}
}
void select(char *council[15], int size) {
int pass, i, smallest;
char temp[];
for (pass = 0; pass < size; pass++) {
smallest = pass;
for (i = pass + 1; i < size; i++) {
if (strcmp(council[i], council[i - 1]) < 0) {
smallest = i;
}
}
printf("Value of smallest is: %d\n", smallest);
if (smallest != pass) {
strcpy(temp, council[pass]);
strcpy(council[pass], council[smallest]);
strcpy(council[smallest], temp);
}
}
}
int BinSearch(char *council[15], char *name, int min, int max) {
int mid;
min = 0;
max = 15;
while (min < max) {
int mid = (min + max) / 2;
if (strcmp(council[mid], name) == 0) {
printf("%s", name);
return 1;
} else
if (strcmp(council[mid], name) > 1) {
max = mid - 1;
BinSearch(council, name, min, max);
} else {
min = mid + 1;
BinSearch(council, name, min, max);
}
}
}
int main() {
int result = 0;
char *key;
char *council[15] = {
"Bert", "Jeff", "Gary", "Neba", "Chang",
"Olga", "Nora", "Mary", "Vera", "Rani",
"Neil", "Jill", "Cain", "Lara", "Bart"
};
printf("Before Sorting\n");
doDisplay(council, 15);
select(council, 15);
printf("\nAfter Sorting");
doDisplay(council, 15);
printf("Enter search key: ");
gets(key);
scanf("%s", &key);
result = BinSearch(council, &key, 0, 15);
return 0;
}
There are multiple problems in your code:
the strings in the array are string literals, modifying them has undefined behavior. You should swap the pointers, not the string contents
char temp[]; is an invalid definition. Arrays must be defined with an fixed length either specified between the brackets or determined from the initializer at compile time.
the test strcmp(council[mid], name) > 1 is incorrect, you should compare to 0.
gets() is obsolete, do not use this function.
scanf("%s", &key); is invalid: key is an uninitialized pointer, passing its address is a type mismatch. You should pass an array of sufficient length.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void doDisplay(char *council[], int size) {
int i;
for (i = 0; i < size; i++) {
puts(council[i]);
}
}
void select(char *council[], int size) {
int pass;
for (pass = 0; pass < size; pass++) {
int smallest = pass;
int i;
for (i = pass + 1; i < size; i++) {
if (strcmp(council[i], council[smallest]) < 0) {
smallest = i;
}
}
if (smallest != pass) {
char *temp = council[pass];
council[pass] = council[smallest];
council[smallest] = temp;
}
}
}
int BinSearch(char *council[], const char *name, int size) {
int min = 0, max = size;
while (min < max) {
int mid = min + (max - min) / 2;
int cmp = strcmp(council[mid], name)
if (cmp == 0) {
return mid;
} else
if (cmp > 0) {
max = mid;
} else {
min = mid + 1;
}
}
return -1;
}
int main() {
char *council[15] = {
"Bert", "Jeff", "Gary", "Neba", "Chang",
"Olga", "Nora", "Mary", "Vera", "Rani",
"Neil", "Jill", "Cain", "Lara", "Bart"
};
int length = sizeof(council) / sizeof(council[0]);
char key[20];
int result;
printf("Before Sorting\n");
doDisplay(council, length);
select(council, length);
printf("After Sorting\n");
doDisplay(council, length);
printf("Enter search key: ");
scanf("%19s", key);
result = BinSearch(council, key, length);
if (result < 0) {
printf("%s not found\n", key);
} else {
printf("%s found at %d\n", key, res);
}
return 0;
}
Related
So ive genertaed a list of random numbers (of varying size) that need to be sorted using selection sort, i have the selection sort algoruthm but im not sure how to open my file, read it and then pass it through my algorithm.
In my selection sort i have an array of number for temporary ue but they need to be replaced with the numbers from the file.
This is my selection sort code im using...
int main() {
int arr[10]={6,12,0,18,11,99,55,45,34,2};
int n=10;
int i, j, pos, s;
for (i = 0; i < (n - 1); i = i + 1) {
pos = i;
for (j = i + 1; j < n; j = j + 1) {
if (arr[pos] > arr[j])
pos = j;
}
if (pos != i) {
s = arr[i];
arr[i] = arr[pos];
arr[pos] = s;
}
}
for (i = 0; i < n; i = i + 1)
printf("%d\n", arr[i]);
return 0;
}
Here is a solution which reads the numbers from standard input. The first number in the input is the number of integers to read.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NEW_ARRAY(pointer, length) \
{ \
(pointer) = malloc((size_t) (length) * sizeof (pointer)[0]); \
if ((pointer) == NULL) { \
fprintf(stderr, "Allocating memory failed: %s\n", strerror(errno)); \
exit(EXIT_FAILURE); \
} \
}
void Read(int **numbers, int *numbersLength)
{
int count, i;
count = scanf("%d", numbersLength);
if ((count == 1) && (*numbersLength > 0)) {
NEW_ARRAY(*numbers, *numbersLength);
i = -1;
do {
i++;
count = scanf("%d", &(*numbers)[i]);
} while ((count == 1) && (i < *numbersLength - 1));
if (count != 1) {
fprintf(stderr, "Expected %d numbers but got only %d\n", *numbersLength, i);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Number of integers should be a positive integer\n");
exit(EXIT_FAILURE);
}
}
void Sort(int numbers[], int numbersLength)
{
/*your sorting logic here*/
}
void Print(const int numbers[], int numbersLength)
{
int i;
for (i = 0; i < numbersLength; i++) {
printf(" %d", numbers[i]);
}
}
int main(void)
{
int numbersLength;
int *numbers;
Read(&numbers, &numbersLength);
Sort(numbers, numbersLength);
Print(numbers, numbersLength);
putchar('\n');
free(numbers);
return 0;
}
I think you'll want fgetc and fopen: https://man7.org/linux/man-pages/man3/fopen.3.html, https://man7.org/linux/man-pages/man3/fgetc.3.html. If they have varying lengths you will probably also be looping until you read EOF, the end of file character. Hope this helps and good luck!
I created a code with 4 functions:
Data_duplication that checks if the name is already exists.
Init that the function initializes through input from the user a set of names and a set of scores. Both arrays of the same size which called size. Whenever data is collected for arrays, they must be valid. If the user typed an invalid name, an error message should be printed and an alternate statistic requested. A valid score is complete between 0 and 100. A valid name meets the following conditions:
Begins with a large Latin letter.
All but the first characters are lowercase Latin characters.
Not already in the array. (The array must not contain the same name twice.)
Find function that gets as parameters, an array of names, an array of grades, and the size of these arrays. In addition, it receives as a student name parameter. The function finds the student's position in the array of names, and returns its grade. If the student does not appear in the set, 1- will be returned.
FreeAll that frees all the memory from the arrays.
PROBLEM:
When i enter for example that there are 3 students it is asking from me to write a fourth student and then it writes a grade that I don't know from where and gets out of the program.
Code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#define SIZE 20
int Data_duplication(char* temp, char** names, int line);
void Init(char*** names, int** grades, int* size);
int Find(char** names, int* grades, int size, char* name);
void FreeAll(char*** names, int** grades, int size);
int main()
{
char** Names = NULL;
int* Grades = NULL;
int size, grade;
char name[SIZE] = { 0 };
Init(&Names, &Grades, &size);
printf("Enter a student name\n");
scanf("%s", name);
grade = Find(Names, Grades, size, name);
printf("%d", grade);
FreeAll(&Names, &Grades, size);
return 0;
}
void Init(char*** names, int** grades, int* size)
{
int i, j, flag;
int strlengh;
char temp[SIZE] = { 0 };
printf("Enter number of students\n");
scanf("%d", size);
*names = (char**)malloc((*size) * sizeof(char*));
if (!(*names))
{
printf("Error");
return;
}
*grades = (int*)malloc((*size) * sizeof(int));
if (!*grades)
{
printf("Error");
return;
}
for (i = 0; i < *size; i++)
{
printf("Enter a name\n");
scanf("%s", temp);
strlengh = strlen(temp);
do
{
flag = 1;
if (strlen(temp) > 20)//if it longer then it should be
flag = 0;
if (temp[0] > 'Z' || temp[0] < 'A') //start with capital letter
flag = 0;
for (j = 1; temp[j] != '\0'; j++)//all the letter is a lower case letters except from the first
{
if (temp[j] > 'z' || temp[j] < 'a')
{
flag = 0;
break;
}
}
if (Data_duplication(temp, *names, i))//if its not a name that already entered
{
flag = 0;
}
if (flag)//if the name is ok
{
(*names)[i] = (char*)malloc((strlengh + 1) * sizeof(char));
if (!(*names)[i])
{
printf("Error");
return;
}
strcpy((*names)[i], temp);
}
else//if somthing wrong
{
printf("Bad name,try again.\n");
scanf("%s", temp);
}
} while (!flag);
printf("Enter grade\n");
scanf("%d", (*grades + i));
while (*(*grades + i) < 0 || *(*grades + i) > 100)//if the grade between 0 to 100
{
printf("Bad grade,try again.\n");
scanf("%d", (*grades + i));
}
}
}
int Data_duplication(char* temp, char** names, int line)//find if there is another name like this that already entered
{
for (int i = 0; i < line; i++)
{
if (!strcmp(temp, names[i]))
{
return 1;
}
}
return 0;
}
int Find(char** names, int* grades, int size, char* name)
{
int i;
for (i = 0; i < size; i++)
{
if (strcmp(name, names[i]) == 0);
{
return (*(grades + i));
}
}
return -1;
}
void FreeAll(char*** names, int** grades, int size)//free al the dynamic memo allocation
{
for (int i = 0; i < size; i++)
{
free(*(*names + i));
}
free(*names);
free(*grades);
}
arrays passed by reference so you don't need to pass pointer to array.
I made changes in your code.
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
#include<string.h>
#define SIZE 20
int Data_duplication(char* temp, char** names, int line);
void Init(char** names, int* grades, int size);
int Find(char** names, int* grades, int size, char* name);
void FreeAll(char** names, int* grades, int size);
int main()
{
int size, grade;
char name[SIZE];
printf("Enter number of students\n");
scanf("%d", &size);
char** Names=(char**)malloc((size) * sizeof(char*));
int* Grades= (int*)malloc((size) * sizeof(int));
Init(Names, Grades, size);
printf("--------------------------------------------------------------------\n");
printf("Enter a student name\n");
scanf("%s",name);
grade = Find(Names,Grades,size,name);
printf("%d", grade);
FreeAll(Names, Grades, size);
return 0;
}
void Init(char** names, int* grades, int size)
{
int i, j, flag;
int strlengh;
if (!(names))
{
printf("Error");
return;
}
for(i = 0; i < size ; i++){
names[i] = malloc(sizeof(char)*SIZE);
if(!names[i])
{
printf("Error");
return;
}
}
if (!grades)
{
printf("Error");
return;
}
for (i = 0; i < size; i++)
{
printf("Student i= %d\n",i);
do
{
char temp[SIZE]="";
printf("Enter a name\n");
scanf("%s", temp);
strlengh = strlen(temp);
flag = 1;
if (strlen(temp) > SIZE)//if it longer then it should be
flag = 0;
if (temp[0] > 'Z' || temp[0] < 'A') //start with capital letter
flag = 0;
for (j = 1; temp[j] != '\0'; j++)//all the letter is a lower case letters except from the first
{
if (temp[j] > 'z' || temp[j] < 'a')
{
flag = 0;
break;
}
}
if (Data_duplication(temp, names, i))//if its not a name that already entered
{
flag = 0;
}
if (flag)//if the name is ok
{
strcpy(names[i], temp);
printf("temp= %s\n", temp);
printf("names[i]= %s\n", names[i]);
}
else//if somthing wrong
{
printf("Bad name,try again.\n");
}
} while (!flag);
printf("Enter grade\n");
scanf("%d",&grades[i]);
while (grades[i] < 0 || grades[i] > 100)//if the grade between 0 to 100
{
printf("Bad grade,try again.\n");
scanf("%d",&grades[i]);
}
}
}
int Data_duplication(char* temp, char** names, int line)//find if there is another name like this that already entered
{
for (int i = 0; i < line; i++)
{
if (!strcmp(temp, names[i]))
{
return 1;
}
}
return 0;
}
int Find(char** names, int* grades, int size, char* name)
{
int i;
for (i = 0; i < size; i++)
{
printf("name= %s\n",name);
printf("names[i]= %s\n", names[i]);
if (strcmp(name, names[i]) == 0)
{
return (grades[i]);
}
}
return -1;
}
void FreeAll(char** names, int* grades, int size)//free al the dynamic memo allocation
{
for (int i = 0; i < size; i++)
{
free(names[i]);
}
free(names);
free(grades);
}
I am trying to return a char** from a function to main so I can do stuff with it, but when I print it out it gives me random characters. I'm at a loss.
main VV
// ./main < data/filelist.txt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hist.h"
int main(){
int count = 0;
int i;
char** files = read(&count);
displayList(files, count);
char** array = splitFiles(files, count);
printf("IN MAIN: array[0] - %s\n", array[0]);
Histogram* p;
printf("here\n");
int histArrayCount = calcHistogram(&array[0], &count, &p);
printf("here\n");
displayHistogram(p, histArrayCount);
printf("here\n");
}
hist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hist.h"
int calcHistogram (char** a, int* count, Histogram** q) {
int i, k;
int j = 0;
int histArrayCount = 0;
Histogram* p = (Histogram*)malloc((*count) * sizeof(Histogram));
for (k = 0; k < *count; k++) {
p[k].num = "1";
p[k].freq = 0;
}
for (i = 0; i <= *count; i++) {
while ((strcmp(p[j].num, "1") != 0) && (strcmp(p[j].num, a[i]) != 0)) {
j++;
}
if (strcmp(p[j].num, "1") == 0) {
p[j].num = a[i];
p[j].freq = 1;
histArrayCount++;
}
else if ((strcmp(p[j].num, a[i]) == 0)) {
p[j].freq += 1;
}
else {
printf("ERROR\n");
}
j = 0;
}
*q = p;
return histArrayCount;
}
void displayHistogram (Histogram* p, int histArrayCount) {
int i;
for (i = 0; i < histArrayCount - 1; i++) {
printf("value %s: freq %d\n", p[i].num, p[i].freq);
}
printf("\n");
}
char** splitFiles(char** files, int count) {
int i;
char** array = (char**)malloc((count)*sizeof(char*));
FILE* fp;
int c = 0;
for(i = 0; i < count; i++) {
char buff[255];
fp = fopen(files[i], "r");
array[i] = fgets(buff, 255, (FILE*)fp);
printf("%d : %s\n", i, buff);
}
printf("array[0] = %s\n", array[0]);
return array;
}
void displayList(char** a, int c) {
int i;
for (i = 0; i < c; i++) {
printf("File %d: %s\n", i, a[i]);
}
printf("\n");
}
char** read(int* c){
int count = 0;
int i;
char** a = (char**)malloc(100*sizeof(char*));
for (i = 0; i< 100; i++) {
a[count] = (char*)malloc(100*sizeof(char));
count++;
}
count = 0;
int endOfFile = scanf("%s", a[count]);
while (endOfFile != EOF) {
count++;
endOfFile = scanf("%s", a[count]);
}
*c = count;
return a;
}
When I print the array at index 0 in here it gives me what is actually there, but when I do the same thing in main it does not. It gives me three random characters.
hist.h
typedef struct Histogram {
char* num;
int freq;
} Histogram;
char** read(int* c);
void displayList(char** a, int c);
int calcHistogram (char** a, int* c, Histogram** p);
void displayHistogram (Histogram* a, int histArrayCount);
char** splitFiles (char** files, int count);
I am trying to implement recursive bubblesort for array of structures. But, it is giving wrong output when I sort the array by Employee name. I am not able to figure out what I am missing. Any help is appreciated.
#include<stdio.h>
#include<stdlib.h>
// GLOBAL VARIABLES
char *stringDataType = "string";
char *integerDataType = "integer";
// Employee structure
struct Employee
{
char *name;
int age;
};
// Method to swap two structures by reference.
void Swap(struct Employee *first, struct Employee *second)
{
struct Employee temp = *first;
*first = *second;
*second = temp;
}
// Method to check if the first string is greater than second string or not
// 1 if the first string is greater
// -1 if the seond string is greater
// 0 if both the strings are equal
int IsGreaterThan(char **first , char **second)
{
int index = 0;
while(*((*first)+index) == *((*second)+index))
{
index++;
}
if(*((*first)+index) > *((*second)+index))
{
return 1;
}
else if(*((*first)+index) < *((*second)+index))
{
return -1;
}
else
{
return 0;
}
}
// Method to check if the first structure is greater than second structure or not
// 1 if the first structure is greater
// -1 if the seond structure is greater
// 0 if both the structure are equal
int IsStructGreaterThan(struct Employee *first, struct Employee *second)
{
int index = 0;
return IsGreaterThan(&(*first).name, &(*second).name);
}
// Bubble Sort Method
void BubbleSort(struct Employee array[], int size, char *dataType, int swapped)
{
int i;
if(swapped == 0 || size == 0)
{
return;
}
for(i = 0; i < size - 1; i++)
{
swapped = 0;
if(dataType==stringDataType && (IsStructGreaterThan(&array[i], &array[i+1]) == 1) || dataType==integerDataType && array[i].age > array[i+1].age)
{
Swap(&array[i], &array[i + 1]);
swapped = 1;
}
}
BubbleSort(array, size-1, dataType, swapped);
}
// Entry point of the program
int main()
{
struct Employee array[] = {{"John", 45}, {"Mary", 23}, {"Celina", 79}, {"Mike", 41}};
int arraySize = 4;
int index;
printf("Before Sorting : \n");
for(index = 0; index < arraySize; index++)
{
printf("(%s, %d) ", array[index].name, array[index].age);
}
printf("\n");
int swapped = 1;
BubbleSort(array, arraySize, stringDataType, swapped);
printf("After Sorting by name : \n");
for(index = 0; index < arraySize; index++)
{
printf("(%s, %d) ", array[index].name, array[index].age);
}
printf("\n");
BubbleSort(array, arraySize, integerDataType, swapped);
printf("After Sorting by age : \n");
for(index = 0; index < arraySize; index++)
{
printf("(%s, %d) ", array[index].name, array[index].age);
}
printf("\n");
return 0;
}
OUTPUT
Before Sorting :
(John, 45) (Mary, 23) (Celina, 79) (Mike, 41)
After Sorting by name :
(John, 45) (Celina, 79) (Mary, 23) (Mike, 41)
After Sorting by age :
(Mary, 23) (Mike, 41) (John, 45) (Celina, 79)
Strings should be compared by strcmp() instead of comparison operators.
You could change IsStructGreaterThan() into
int IsStructGreaterThan(struct Employee *first, struct Employee *second)
{
return strcmp(first->name, second->name);
}
put swapped = 0 before the for-loop, not inside it, and fix the string comparison as per other answers.
I'm trying write a program that takes a list of names, sorts those names, and allows the user to search for a name from that list. The program compiles, but once the user has entered "y" to search for a name and has entered the name he wishes to search for, the program just freezes.
I appreciate any help!
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#define NUM_OF_NAMES 8
#define NAME_SIZE 5
void printNames(char names[][NAME_SIZE], int size);
void bubbleSortNames(char names[][NAME_SIZE], int last);
bool binarySearchNames(char list[][NAME_SIZE], int end, char target[], int *location);
int main()
{
char nameList[NUM_OF_NAMES][NAME_SIZE] = {"Bob", "Sue", "Jake","Rod", "Jon", "Ash", "Deb", "Kay"};
char searchText[NAME_SIZE];
char userChoice;
int searchLocation;
printf("\n\n\nLIST BEFORE SORTING\n");
printNames(nameList, NUM_OF_NAMES);
bubbleSortNames(nameList, NUM_OF_NAMES);
printf("\n\n\nLIST AFTER SORTING\n");
printNames(nameList, NUM_OF_NAMES);
printf("\n\n\nWould you like to search for a name? (y/n) ");
scanf(" %s", &userChoice);
while(userChoice == 'y')
{
printf("\n\n\nPlease try to search for a name: ");
scanf("%s", searchText);
if(!(binarySearchNames(nameList, NUM_OF_NAMES, searchText, &searchLocation)))
printf("\n\n\nThe name %s was not found.\n", searchText);
else
printf("\n\n\nThe name %s was found at location %d!", searchText, searchLocation);
}
printf("\n\n\nThank you for using this program.\n\n\n");
return 0;
}
/********************************
Prints the names from the array.
********************************/
void printNames(char names[][NAME_SIZE], int size)
{
int index;
for(index = 0; index < size; index++)
puts(names[index]);
return;
}
/*******************************
Sorts the names from the array.
*******************************/
void bubbleSortNames(char names[][NAME_SIZE], int last)
{
char temp[NAME_SIZE];
int current;
int walker;
for(current = 0; current < last; current++)
{
for(walker = last; walker > current; walker--)
{
if(strcmp(names[walker], names[walker - 1]) < 0)
{
strncpy(temp, names[walker - 1], sizeof(temp) - 1);
strncpy(names[walker - 1], names[walker], sizeof(names[walker - 1]) - 1);
strncpy(names[walker], temp, sizeof(names[walker]) - 1);
}
}
}
return;
}
/*********************************
Searches for names to be printed.
*********************************/
bool binarySearchNames(char list[][NAME_SIZE], int end, char target[], int* location)
{
int first = 0,
last,
mid;
last = end;
while(first <= last);
{
mid = (first + last) / 2;
if(strcmp(target, list[mid]) > 0)
first = mid + 1;
else if(strcmp(target, list[mid]) < 0)
last = mid - 1;
else
first = last + 1;
}
*location = mid + 1;
return (strcmp(target, list[mid]) == 0);
}
In function binarySearchNames:
while(first <= last) you put a ;
This results in an endless loop.
Try using a debugger when encountering such problems.
scanf(" %s", &userChoice);
Have you tried removing the space before the %s and replacing the %s with a %c? Both could cause issues.