Sort struct array in lexicographical order - arrays

I need to sort students according to their surname or if their surname is the same according to their name in lexicographical order.
#include <stdio.h>
struct Student {
char name[20], surname[20];
};
void sort(struct Student students[], int n) {
int i, j, temp;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
if (students[j].surname > students[i].surname ||
students[j].name > students[i].name) {
temp = i;
students[i] = students[j];
students[j] = students[temp];
}
}
void main() {
struct Student students[6] = {
{"Mujo", "Mujic"},
{"Meho", "Mujic"},
{"Pero", "Peric"},
{"Beba", "Bebic"},
{"Mujo", "Mujic"},
{"Fata", "Fatic"},
};
sort(students, 6);
int i;
for (i = 0; i < 6; i++)
printf("%s %s\n", students[i].surname, students[i].name);
}
This prints only one student six times. Could you help me to fix this?
Note: using auxiliary arrays is not allowed

Your swap code is dubious — broken, I believe. A big warning bell is the type of temp — it needs to be a struct Student.
You have:
temp = i;
students[i] = students[j];
students[j] = students[temp];
You need:
struct Student temp = students[i];
students[i] = students[j];
students[j] = temp;
Obviously, remove the definition int temp; as well.
However, there are other problems too (as ever). You can't usefully compare strings using relational operators — use strcmp(). And your ordering test is wrong too, even when revised to use strcmp().
This code does the job, sorting names in descending order:
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
char surname[20];
};
static void sort(struct Student students[], int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
int rc = strcmp(students[j].surname, students[i].surname);
if (rc > 0 ||
(rc == 0 && strcmp(students[j].name, students[i].name) > 0))
{
struct Student temp = students[i];
students[i] = students[j];
students[j] = temp;
}
}
}
}
static void dump_array(const char *tag, size_t size, const struct Student *students)
{
printf("%s (%zu):\n", tag, size);
for (size_t i = 0; i < size; i++)
printf("%s %s\n", students[i].surname, students[i].name);
}
int main(void)
{
struct Student students[] =
{
{"Mujo", "Mujic"},
{"Meho", "Mujic"},
{"Pero", "Peric"},
{"Zebra", "Elephant"},
{"Beba", "Bebic"},
{"Mujo", "Mujic"},
{"Abelone", "Shells"},
{"Fata", "Fatic"},
};
enum { NUM_STUDENTS = sizeof(students) / sizeof(students[0]) };
dump_array("Before", NUM_STUDENTS, students);
sort(students, NUM_STUDENTS);
dump_array("After", NUM_STUDENTS, students);
return 0;
}
Output:
Before (8):
Mujic Mujo
Mujic Meho
Peric Pero
Elephant Zebra
Bebic Beba
Mujic Mujo
Shells Abelone
Fatic Fata
After (8):
Shells Abelone
Peric Pero
Mujic Mujo
Mujic Mujo
Mujic Meho
Fatic Fata
Elephant Zebra
Bebic Beba

Related

I have read data from txt file and stored in a struct array , and want to sort the data by name field

This code does not give any errors but displays the array with old
values without sorting by name field, it works up to reading the txt file storing data in a struct array student an instance of struct person, then when used the code to sort it and print the results of sorted array . but it does not work
#include < stdio.h >
#include < string.h >
int main() {
// read data from txt file and stores
// in a struct array
storeInarraySort();
}
int storeInarraySort() {
// struct person with 4 fields
struct person {
char name[100];
char address[100];
char IDnumber[20];
int age;
};
FILE * file = fopen("personout.txt", "r");
// declares an struct array to store data
struct person student[10];
int k = 0;
if (file != NULL)
{
char line[128]; /* or other suitable maximum line size */
/* read a line */
while (fgets(line, sizeof line, file) != NULL)
{
// stores values in struct array
sscanf(line, " %99[^,], %99[^,], %19[^,], %d", student[k].name,
student[k].address, student[k].IDnumber, & student[k].age);
k++;
}
printf("%d\n", k); // no of records in array
fclose(file);
// number of records k r=k first for loop
// inner for loop s=r+1
//char temp;
//struct person temp;
for (int r = 0; r < k - 1; r++) {
for (int s = r + 1; r < k; r++) {
if (strcmp(student[r].name, student[s].name) > 0) {
struct person temp = student[r];
//strcpy(temp,student[r]);
student[r] = student[s];
//strcpy(student[r],student[s]);
student[s] = temp;
//strcpy(student[s],temp);
}
}
}
// prints struct array to check
for (int t = 0; t < k; t++) {
printf("%s\n %s\n %s\n %d\n ", student[t].name,
student[t].address, student[t].IDnumber, student[t].age);
}
}
}
Use selection sort for sorting.
void swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
void selectionSort(int arr[], int n)
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n-1; i++)
{
// Find the minimum element in unsorted array
min_idx = i;
for (j = i+1; j < n; j++)
if (strcmp(arr[j].name , arr[min_idx].name) < 0)
min_idx = j;
// Swap the found minimum element with the first element
swap(&arr[min_idx], &arr[i]);
}
}

Insertion code using file stream

Here is the task i'm working on:
I am given a txt file containing the list of student names, id numbers, schools, majors, and test scores.
Read this contents and copy to the structure in C.
Sort this list using insertion sort.
Print sorted list on the screen.
I checked my coding by muting some parts, there is an error with my insertion sorting function.
I have no idea which part is incorrect. It all makes sense to me. I need help :( here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000
#define BUF_SIZE 80
typedef struct {
char name[20];
char studentID[10];
char department[20];
char major[20];
int mid;
int final;
} student;
FILE *fp;
void operation(student t, student list[], int j);
void insertion_sort(student list[], int n);
void printing(student list[], int n);
int main(int argc, char *argv[])
{
char filename[20] = "studentlist.txt";
int n = 1; /* (number of students) + 1 */
student list[MAX];
char buffer[BUF_SIZE];
int i;
fp = fopen(filename, "r");
while (1) {
if (fgets(buffer, BUF_SIZE, fp) == NULL)
break;
strncpy(list[n].name, buffer, strlen(buffer) - 1);
fgets(buffer, BUF_SIZE, fp);
strncpy(list[n].studentID, buffer, strlen(buffer) - 1);
fgets(buffer, BUF_SIZE, fp);
strncpy(list[n].department, buffer, strlen(buffer) - 1);
fgets(buffer, BUF_SIZE, fp);
strncpy(list[n].major, buffer, strlen(buffer) - 1);
fgets(buffer, BUF_SIZE, fp);
list[n].mid = atoi(buffer);
fgets(buffer, BUF_SIZE, fp);
list[n].final = atoi(buffer);
n++;
}
fclose(fp);
insertion_sort(list, n);
printing(list, n);
return 0;
}
void insertion_sort(student list[], int n)
{
int i;
student temp;
for (i = 2; i < n; i++) {
temp = list[i];
operation(temp, list, i - 1);
}
}
void operation(student t, student list[], int j)
{
list[0] = t;
while (t.studentID < list[j].studentID) {
list[j + 1] = list[j];
j--;
}
list[j + 1] = t;
}
void printing(student list[], int n)
{
int i;
for (i = 1; i < n; i++) {
printf(" %s ", list[i].name);
printf(" %s ", list[i].studentID);
printf(" %s ", list[i].department);
printf(" %s ", list[i].major);
printf(" %6d ", list[i].mid);
printf(" %6d ", list[i].final);
putchar('\n');
}
}
Continuing from the comments and the first answer, you are making tracking index error between the split insertion_sort and operation functions. There is no need for two functions when one will work (and arguably be smaller). There is little benefit to be obtained from the split (except for increased confusion).
Putting a simple insertion sort together in one function that will fit your needs (and using pointers to sort as opposed to repeatedly using the function copy-constructor to accomplish the swaps), you could do something similar to the following:
typedef struct {
int id, g;
} student;
void insertion_sort (student **list, int nmemb)
{
for (int i = 0; i < nmemb; i++)
for (int j = i; j > 0 && list[j]->id < list[j-1]->id; j--)
{
student *tmp = list[j];
list[j] = list[j-1];
list[j-1] = tmp;
}
}
Putting together a short (and limited struct member example), you can do something like the following to sort the student data by ID (or id below)
#include <stdio.h>
typedef struct {
int id, g;
} student;
void insertion_sort (student **list, int nmemb)
{
for (int i = 0; i < nmemb; i++)
for (int j = i; j > 0 && list[j]->id < list[j-1]->id; j--)
{
student *tmp = list[j];
list[j] = list[j-1];
list[j-1] = tmp;
}
}
void printing(student *list[], int n)
{
int i;
for (i = 0; i < n; i++) {
printf(" %d ", list[i]->id);
printf(" %d \n", list[i]->g);
}
}
int main (void) {
student s[] = { {.id = 5, .g = 72}, /* minimal student test data */
{.id = 2, .g = 91},
{.id = 4, .g = 77},
{.id = 1, .g = 96},
{.id = 3, .g = 85}};
int n = sizeof s / sizeof *s;
student *l[n];
for (int i = 0; i < n; i++) /* initialize pointers in l */
l[i] = &s[i];
insertion_sort (l, n); /* sort pointers in l */
printing (l, n); /* output sorted pointers */
return 0;
}
Example Use/Output
Sorted by student.id
$ ./bin/inssort_so
1 96
2 91
3 85
4 77
5 72
If you did want to avoid using the additional level of indirection involved in passing an array of pointers (actually a pointer-to-pointer-to-type), you can make your original approach work as follows:
void insertion_sort (student *list, int nmemb)
{
for (int i = 0; i < nmemb; i++)
for (int j = i; j > 0 && list[j].id < list[j-1].id; j--)
{
student tmp = list[j];
list[j] = list[j-1];
list[j-1] = tmp;
}
}
void printing (student *list, int n)
{
for (int i = 0; i < n; i++)
printf (" %d %d \n", list[i].id, list[i].g);
}
int main (void) {
student s[] = { {.id = 5, .g = 72},
{.id = 2, .g = 91},
{.id = 4, .g = 77},
{.id = 1, .g = 96},
{.id = 3, .g = 85}};
int n = sizeof s / sizeof *s;
insertion_sort (s, n);
printing (s, n);
return 0;
}
As you go forward, also consider passing a compare callback function to your sort routines. That allows you to sort many different types of data using your same sort routine -- just by changing the compare function (as is done for the C-library qsort routine.

Reading of a char contained in a struct results in access violation exception

i am trying to implement a linked-list in C with the aim to do a BFS on it.
The input for the list should look like this:
a-bc
b-a
c-a
which represents a list looking like this:
a
/ \
b c
now, my problem is that I cannot read the variable name defined in my Vertex struct. My program segfaults with Access Reading Violation. While printf("%s", s) takes a char *, casting the name to a char* doesn't help. The error takes place before the char is even accessed?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Vertex Vertex;
typedef struct Vertex
{
char name;
int visited;
int distance;
Vertex* next;
} Vertex;
struct Vertex* AddVertex(Vertex* head, char newVertexName)
{
Vertex* newHead = malloc(sizeof(Vertex));
newHead->name = newVertexName;
printf("added vertex named: %s", newHead->name); // causing the error
newHead->next = head;
newHead->visited = 0;
newHead->distance = 0;
return newHead;
}
int main()
{
// BFS
char s[100];
int l = 0;
const int nNrOfVerts = 27;
Vertex* adjList[28];
// initialise array of pointers
for(int i = 0; i <= nNrOfVerts; ++i)
{
adjList[i] = NULL;
}
// fill vertices with user data
for(int i = 1; i <= nNrOfVerts; ++i)
{
printf("enter %d vert: ", i);
if(scanf("%s", &s) != 1)
{
break;
}
l = strlen(s);
if(l > 2)
{
for(int k = 0; k < l; ++k)
{
// increment to accustom for the - seperator
if(1 == k)
{
k = 2;
}
adjList[i] = AddVertex(adjList[i], s[k]);
}
}
for(int k = 0; k < 100; ++k)
{
s[k] = NULL;
}
}
bfs(adjList);
// printing the list
for(int i = 1; i <= l; ++i)
{
for(int j = 0; j <= nNrOfVerts; ++j)
{
if(adjList[j]->distance == i)
{
printf("Level: %d is: %s", i, adjList[j]->name);
}
printf("No node for dist: %d", i);
}
}
return 0;
}
How can I access the value of newHead->name or adjList[i]->name for that matter? The interesting thing is, if I try to access adjList[i]->distance the correct integer is returned...
You declared name as a char but then you try to print it as a character :
printf("added vertex named: %s", newHead->name);
Change the %s to %c :
printf("added vertex named: %c", newHead->name);
or change your name to a char *.

How do I print the contents of a struct in C?

Resolved the issues on my own, using different methods than those suggested below! :)
Thanks for viewing my question! :)
I've been learning about structs and working on a practice lab in C, and my code does not seem to be compiling correctly with any change I make to it. Currently I am not receiving any output and the program crashes. I'm still very confused on how to correctly utilize the '*' and '&' symbols when passing them into functions as well. My goals for this practice are to:
print the contents of the array in the same format as the data file
print the full name of the student with the best GPA
calculate and print the average GPA
print the names of all students with GPAs above the average
print the name of the youngest student who has a GPA below average
sort the structures in the array into order from lowest to highest
GPA
print the array again (will now be in a different order from last
time)
How do I properly call to and print these items from the student struct? And how would I access the gpa values to pass into a function that would calculate the average?
#include <stdio.h>
#include <stdlib.h>
// define constants
#define ARR 100
#define FIRST 7
#define MIDINIT 1
#define LAST 9
#define STREET 16
#define CITY 11
#define STATE 2
#define ZIP 5
#define AGE 3
#define GPA 4
#define START 0
#define FIRSTID 8
#define INITID 10
#define STREETID 20
#define CITYID 37
#define STATEID 49
#define ZIPID 52
#define AGEID 57
#define GPAID 64
// defined structs
typedef struct {
char street[STREET + 1];
char city[CITY + 1];
char state[STATE + 1];
char zip[ZIP + 1];
} Address;
typedef struct {
char firstname[FIRST + 1];
char initial[MIDINIT + 1];
char lastname[LAST + 1];
Address ofstudent;
int age;
double gpa;
} Student;
// function prototype
void strsub(char buf[], char s[], int start, int size);
void processStudent(int *id, Student students[]);
void sortStudentGpa(Student *students, int id);
void maxGpa(Student *students, int id);
/* lab6student.c: creates an array of student structures and outputs reports */
int main(void)
{
Student students[ARR]; // creates an array of student structures
int id = 0; // counter for student
processStudent(&id, students);
maxGpa(students, id);
}
void strsub(char buf[], char s[], int start, int size) {
int i;
for (i = 0; i < size && buf[start + i] != '\0'; i++) {
// loops as long as iterator is less than size
// and while string has not run out of characters
s[i] = buf[i + start];
}
s[i] = '\0';
}
/* void sort(Student *students, int id) {
int j, i;
for(i = 1; i < n; i++) {
for(j = 0; j < id - i; j++) {
if(students[j].gpa > students[j + 1].gpa) {
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
} */
void processStudent(int *id, Student students[]) {
FILE *data;
char line[ARR];
*id = 0; // counter for student
data = fopen("Students.dat", "r");
if (data == NULL) {
printf("Students.dat file not found!\n");
exit(1);
}
// process file
while (!feof(data)) {
// organize student info into separate arrays
fgets(line, ARR, data);
strsub(line, students[*id].firstname, START, FIRST);
strsub(line, students[*id].initial, FIRSTID, MIDINIT);
strsub(line, students[*id].lastname, INITID, LAST);
strsub(line, students[*id].ofstudent.street, STREETID, STREET);
strsub(line, students[*id].ofstudent.city, CITYID, CITY);
strsub(line, students[*id].ofstudent.state, STATEID, STATE);
strsub(line, students[*id].ofstudent.zip, ZIPID, ZIP);
students[*id].age = atoi(&line[AGEID]);
students[*id].gpa = atoi(&line[GPAID]);
(*id)++;
}
fclose(data);
}
//sorts struct student array containing num (gpa) elements into
//ascending order
void sortStudentGpa(Student *students, int id) {
int i, j; // indexes into unsorted and sorted partitions
Student temp; // temporarily holds an element from the array
for (i = 1; i < id; ++i) {
temp = students[i];
j = i - 1;
while (j >= 0 && temp.gpa < students[j].gpa) {
students[j + 1] = students[j];
j = j - 1;
}
students[j + 1] = temp;
}
}
void maxGpa(Student *students, int id) {
int iwithmax, i;
float max = 0;
for ( i = 0 ; i < id ; i++) {
if (students -> gpa > max) {
max = students -> gpa;
iwithmax = i;
}
}
printf("\n\nHighest GPA is done by Student %d with GPA = %f", iwithmax, max);
}
In the maxGpa function just change the definition as
void maxGpa(Student *students, int id);
then in the maxGpa function do the following changes
void maxGpa(Student *students, int id) {
int iwithmax, i;
float max = 0;
for ( i = 0 ; i < id ; i++) {
if (students -> gpa > max) {
max = students -> gpa;
iwithmax = i;
}
}
Try this.....

passing structures to functions

How do you pass structures to a function? is it the same way as with variables (i.e. &var1 to pass it, and *ptr_to_var from function).
Suppose in the following code I wanted to send agencies[i].emps[j].SB and agencies[i].emps[j].ANC to a function which does some calculations on them and then returns a value and store it in agencies[i].emps[j].SNET
how do I go about that?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char mat[20];
double SB;
int ANC;
double RCNSS;
double SNET;
} employee;
typedef struct {
char name[20];
employee* emps;
int emps_count;
} agency;
int main(void)
{
int num_ag, num_emps, i, j;
printf("enter number of agencies\n");
scanf("%d", &num_ag);
agency* agencies = malloc(sizeof(agency) * num_ag);
for (i = 0; i < num_ag; i++) {
sprintf(agencies[i].name, "agency %d", i+1);
printf("enter num of employees for agency %d\n", i+1);
scanf("%d", &num_emps);
agencies[i].emps = malloc(sizeof(employee) * num_emps);
agencies[i].emps_count = num_emps;
for (j = 0; j < num_emps; ++j) {
scanf("%s", &agencies[i].emps[j].mat);
}
}
for (i = 0; i < num_ag; i++) {
printf("agency name: %s\n", agencies[i].name);
printf("num of employees: %d\n", agencies[i].emps_count);
}
for (i = 0; i < num_ag; ++i) {
free(agencies[i].emps);
}
free(agencies);
return 0;
}
You can simple pass a structure pointer to your function:
// Void of a type void function, which saves result of the calculation
void modify_employee(employee * emp) {
emp->SNET = emp->SB * emp->ANC;
}
// Example of type double function, which returns result
// of of the calculation (withuot saving it)
double modify_employee2(employee * emp) {
return emp->SB * emp->ANC;
}
Use it like this:
employee* emp = malloc(sizeof(employee));
emp->SB = 20.5;
emp->ANC = 15;
printf("SNET: %f\n", emp->SNET);
modify_employee(emp);
printf("SNET: %f\n", emp->SNET);

Resources