Navigating 2D arrays by category? - c

Once again, I'd like to thank everyone for their prompt responses to my previous Gradebook question. I am now further along in the project, and have hit a (in my opinion) thornier problem.
The instructions call for me to create a function with this prototype:
int set_assignment_score(Gradebook *gb, char name[MAX_NAME_LEN], char a_name[], int score);
Once again, it will enter the Gradebook structure through the *gb pointer, but this time, it is meant to access the Scores array:
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS]
... and deposit the "score" integer inside a specific cell for further use. The two Char parameters are important, because later on I will need to retrieve each specific integer from the Scores array and match it up with its precise name and a_name in a print_gradebook function.
I would love to share what code I have so far, but the fact of the matter is that I barely know where to start. I think that the key, however, is knowing how to navigate an integer array using char name and char a_name in place of the usual [i] and [j].
Any suggestions, advice, mockery, or requests for clarification are welcome. Please.
Here is the Gradebook structure:
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignment_names[MAX_NUMBER_OF_ASSIGNMENTS][MAX_NAME_LEN + 1];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
EDIT: Thanks, everyone! Combining your advice, I came up with this:
int set_assignment_score(Gradebook *gb, const char name[MAX_NAME_LEN], const char a_name[], int score) {
int i, j;
for(i=0; i< MAX_NUMBER_OF_STUDENTS; i++) {
if(strcmp(gb->students[i].name, name) == 0) {
for(j=0; j< MAX_NUMBER_OF_ASSIGNMENTS; j++) {
if(strcmp(gb->assignment_names[j], a_name) == 0) {
gb->scores[i][j] = score;
}
}
}
}
printf("%d\n", gb->scores[i][j]);
return 1;
}
I suspect it's a lot clumsier than it needs to be, but it gets the job done. Funnily enough, the printf function I put in to test it doesn't provide the result I want (I guess I'm printing the address or something?), but the actual function does.

Yes, that's the general idea. The reason the printf doesn't work is because the loops continue running after you've found the matching student name and assignment name. So after the loops are done, you've lost the values of i and j. In fact, after the loops are done, i==MAX_NUMBER_OF_STUDENTS and j==MAX_NUMBER_OF_ASSIGNMENTS.
To keep the values of i and j, you should break from the loop when you find the matching name. (I also added some error checking to handle the case where one or both of the names aren't found.)
int set_assignment_score(Gradebook *gb, const char name[MAX_NAME_LEN], const char a_name[], int score)
{
int i, j;
for(i=0; i< MAX_NUMBER_OF_STUDENTS; i++)
if(strcmp(gb->students[i].name, name) == 0)
break;
for(j=0; j< MAX_NUMBER_OF_ASSIGNMENTS; j++)
if(strcmp(gb->assignment_names[j], a_name) == 0)
break;
if ( i == MAX_NUMBER_OF_STUDENTS || j == MAX_NUMBER_OF_ASSIGNMENTS )
{
printf( "unable to set score (i=%d, j=%d)\n", i, j );
return 0;
}
gb->scores[i][j] = score;
printf("%d\n", gb->scores[i][j]);
return 1;
}

Related

How can I arrange the structs in an array of structs in an ascending order?

I am sorry if this sounds confusing, I will try to be as clear as possible. I have an array of structs, where the array stores a struct that I have defined as a Business Card. However, before adding any new business cards into the array, I have to store the structs in ascending order based on the integer value of the Employee ID.
Here is the struct:
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
Hence, I tried to use relational operators to compare between the values of the ID and copy it in ascending order to another temporary array I named fakeHolder, before finally copying over to the actual array. However, I can't seem to understand why it is not in order after inputting my data as ID 9, 7, 5.
Here is my helper function:
int addNameCard(NameCard *nc, int *size){
int i = 0;
// Why is this a pointer?
NameCard fakeHolder[10];
char dummy[100];
char *p;
printf("addNameCard():\n");
if(*size == MAX){
printf("The name card holder is full");
// To quit the program
return 0;
}
// Keeps it to Fake Name Card Holder First
printf("Enter nameCardID:\n");
scanf("%d", &fakeHolder->nameCardID);
scanf("%c", &dummy);
printf("Enter personName:\n");
fgets(fakeHolder->personName, 20, stdin);
if(p = strchr(fakeHolder->personName, '\n')){
*p = '\0';
}
printf("Enter companyName:\n");
fgets(fakeHolder->companyName, 20, stdin);
if(p = strchr(fakeHolder->companyName, '\n')){
*p = '\0';
}
// Compare the ID value
for(int j = 0; j < *size; j += 1){
if(fakeHolder->nameCardID == (nc+j)->nameCardID){
printf("The nameCardID has already existed");
}
else if(fakeHolder->nameCardID < (nc+j)->nameCardID){
fakeHolder[(j+1)].nameCardID = (nc+j)->nameCardID;
strcpy(fakeHolder[(j+1)].personName,(nc+j)->personName);
strcpy(fakeHolder[(j+1)].companyName, (nc+j)->companyName);
}
}
*size += 1;
// Transfer to the Actual Name Card Holder
for(int k = 0; k < *size; k += 1){
(nc+k)->nameCardID = fakeHolder[k].nameCardID;
strcpy((nc+k)->personName, fakeHolder[k].personName);
strcpy((nc+k)->companyName, fakeHolder[k].companyName);
}
printf("The name card has been added successfully\n");
return 0;
}
Your current code has several problems, and you can rewrite it to be much more maintainable and easier to work with. For example,
i (in int i = 0;) is not being used
scanf("%c", &dummy); is there, I assume, to remove trailing \n - but a 100-char buffer for a single character to read is... surprising. See scanf() leaves the new line char in the buffer for lots of discussion on different approaches to "trailing stuff after integer".
splitting addNameCard into 2 functions, one to actually request a NameCard and another to insert it into the array, would divide up responsibilities better, and make your program easier to test. Avoid mixing input/output with program logic.
The question you ask can be solved via the standard library qsort function, as follows:
#include <stdlib.h>
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
void show(NameCard *nc, int n) {
for (int i=0; i<n; i++, nc++) {
printf("%d,%s,%s\n",
nc->nameCardID, nc->personName, nc->companyName);
}
}
// comparison functions to qsort must return int and receive 2 const void * pointers
// they must then return 0 for equal, or <0 / >0 for lower/greater
int compareCardsById(const void *a, const void *b) {
return ((NameCard *)a)->nameCardID - ((NameCard *)b)->nameCardID;
}
int main() {
NameCard nc[10];
nc[0] = (NameCard){1, "bill", "foo"};
nc[1] = (NameCard){3, "joe", "bar"};
nc[2] = (NameCard){2, "ben", "qux"};
show(nc, 3);
// calling the libraries' sort on the array; see "man qsort" for details
qsort(nc, 3, sizeof(NameCard), compareCardsById);
show(nc, 3);
return 0;
}

trouble passing strings from 2-D array which meet condition to main function from separate function

In this task, you are to get a list of the most critical reviewers. A
critical reviewer is defined as:
A reviewer who has the same amount of negative recommendations (‘n’)
as the reviewer with the most negative recommendations.
Using this definition of what a critical reviewer is, you are to look
through the list of reviewer’s recommendations and determine if they
are a critical reviewer or not.
** The function’s return value should be the number of critical reviewers. **
In addition, the list of critical reviewer’s names created by the
function must also be accessible outside of the function.
In this example, the highest number of ‘n’ recommendations for a
single reviewer is 2. Once you have determined the highest amount of
‘n’ recommendations, you can check to see which reviewers are
“critical reviewers”. In this example we can determine that reviewers
"Larry", "Judi", "Manisha", "Dora", and "Nick" are critical reviewers
as they are the reviewers represented by array indices 1, 3, 6, 8,
and 9 respectively. The number 5 would be returned by the function’s
return value as that is the count of critical reviewers found in the
list. This function has no print statements.
struggling to pass the names of only the critical reviewers to the array to be displayed in main.
//Function prototypes
void Recommendations(); //task 1
int criticalReviewers(); //task 2
//MAIN FUNCTION
int main(void) {
//Variables
char reviewerNames[NUMBER_REVIEWERS][30] = { "Ritu",
"Larry",
"Dan",
"Judi",
"Eric",
"Isabelle",
"Manisha",
"Terra",
"Dora",
"Nick" };
char movieNames[NUMBER_MOVIES][50] = { "Star Wars",
"Incredibles",
"Gone with the wind" };
char userReviews[NUMBER_REVIEWERS][NUMBER_MOVIES];
char reviewerAnswers[10][3];
char negativeReviewers[10][30];
//TASK TWO
printf("\n**********************************************\n");
printf("Task 2: Get names of critical reviewers\n\n");
//call to task 2 function
printf("Number of Critical Reviewers: %d\n", criticalReviewers(reviewerAnswers, reviewerNames, negativeReviewers));
printf("Critical Reviewers: ");
for (int k=0; k<criticalReviewers(reviewerAnswers, reviewerNames, negativeReviewers); k++) {
printf("%s, ", negativeReviewers + k);
}
printf("%s", negativeReviewers + criticalReviewers(reviewerAnswers, reviewerNames, negativeReviewers));
//CALL TO TASK 3 FUNCTION
mostRecommended(reviewerAnswers, movieNames);
WINPAUSE; // REMOVE BEFORE SUBMITTING
return 0;
}
//TASK ONE FUNCTION
//TASK 2 FUNCTION
int criticalReviewers(char userAnswers[10][3], char Reviewers[][30], char critReviewers[][30]) {
int i=0;
int j=0;
int numCriticalReviewers = 0;
int criticalScore = 0;
int criticalReviewers[10];
int timesSkipped=0;
//loop to determine number of critical REVIEWERS
for (i=0; i<10; i++) {
criticalReviewers[i] = 0;
for (j=0; j<3; j++) {
if (userAnswers[i][j] == 'n') {
criticalReviewers[i] = criticalReviewers[i] + 1;
}
if (criticalReviewers[i] > criticalScore) {
criticalScore = criticalReviewers[i];
}
}
}
for (i=0; i<10; i++) {
if (criticalReviewers[i] == criticalScore) {
numCriticalReviewers = numCriticalReviewers + 1;
for (int k=i; k<i+1; k++) {
critReviewers[k-timesSkipped][30] = Reviewers[k][30];
timesSkipped = 0;
}
}
else {
timesSkipped = timesSkipped + 1;
}
}
for (i=0; i<10; i++) {
if (criticalReviewers[i] == criticalScore) {
critReviewers = Reviewers + i;
}
}
return numCriticalReviewers;
}
I have properly printed in main the number of critical reviewers, but below it should print the names of critical reviewers which i can not figure out. everytime i try to pass the values it prints a random string of letters and symbols.
The issue is where you assign the reviewers to the critReviewers array in function criticalReviewers. Notice how you have the second index as 30. By doing this, you are assigning only the 30th index in the array (which is beyond the bounds of the array, indices 0-29, but that is a different issue).
What you should be doing is either looping through the string to copy each index one by one, or copying the string using a function like strcpy in the string.h library. Otherwise, everything looks like it works fine.
Solution 1:
for(i = 0; i < 30; i++) {
array1[someIndex][i] = array2[someIndex][i];
}
This will copy each entry in array2[someIndex] one by one.
Solution 2:
strcpy(array1[someIndex], array2[someIndex]);
This will copy the entire string in array2[someIndex] to array1[someIndex].
I would also take a while to read up on 2d arrays, if you're still confused after reading this. I always like geeksforgeeks.com for stuff like this: https://www.geeksforgeeks.org/multidimensional-arrays-c-cpp/

C: How to sort a Struct by one of its element? Can't use pointers

How do I sort struct like this one:
typedef struct
{
int weight;
int price;
Color color;
Equip equip;
}Cars;
by one of it's attributes like price, or weight? Automobil array is previously declared.
I can't use pointers, and any other built-in function.
Cars automobil[5];
Cars mobilOne={};
for(i=0; i<5; i++)
{
if((i+1)==5)
{
break;
}else
{
if (automobil[i].weight> automobil[i+1].weight)
{
mobilOne = automobil[i];
automobil[i] = automobil[i+1];
automobil[i+1] = mobilOne;
}
}
}
I tried to do this, this way, but it does not do anything...
Also if someone could tell me, how can I pass a struct like this one into a function I would be really thankful!
OK, well first what you are trying to do is not quite as bad as some people might tell you as for small N bubble sort is still pretty fast. The following will do you and of course you need a double loop:
int main() {
Cars automobil[NC];
// Initialiase automobil here
for (int i = 0; i < NC - 1; ++i) {
int am = i;
for (int j = i+1; j < NC; ++j) {
if ( automobil[am].weight > automobil[j].weight )
am = j;
}
if ( am != i) {
Cars tmp = automobil[am];
automobil[am] = automobil[i];
automobil[i] = tmp;
}
}
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
Notice that we can copy structs but even here we try to do it as little as possible.
However, it's very easy to say "I'll never have more than ten cars" and then find you are trying to sort several thousand so I would urge you to learn and understand qsort():
int carsSort(const void *a, const void *b) {
return ((Cars *) a)->weight - ((Cars *) b)->weight;
}
int main() {
Cars automobil[NC];
// Initialiase automobil here
qsort(automobil, NC, sizeof *automobil, carsSort);
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
John
PS: in reply to "how do I pass the array to a function?" remember one of the many wise sayings of K&R: "When an array name is passed to a function, what is passed is the location of the beginning of the array".
Hence:
int carsSort(const void *a, const void *b) {
return ((Cars *) a)->weight - ((Cars *) b)->weight;
}
void sortThem(Cars autom[]) {
qsort(autom, NC, sizeof *autom, carsSort);
}
int main() {
Cars automobil[NC];
// Initialiase automobil here
sortThem(automobil);
for (int i = 0; i < NC; ++i)
printf("%d\n", automobil[i].weight);
}
Inside sortThem() "autom" is a variable whose value is the address of automobil[0].
Without going into implementation details here is a procedural algorithm for a bubble sort (not in C): Bubble Sort Algorithm. Note, as mentioned in comments, this bubble sort implementation uses nested loops.
One other item to keep in mind: In order to switch two objects, a third temporary object of the same type needs to be used. For example:
int temp
int arr1[]={2,5,7,2,9,1,8,0,5,2,1};
int count = sizeof(arr1)/sizeof(arr1[0])
for(int i = 0; i < count-1; i++ )
{
if(arr1[i]>arr1[i+1])
{
temp = arr1[i];
arr1[i] = arr1[i+1];
arr[i+1] = temp;
}
}
Because you are sorting on a single member of a collection of members, the assignment swapping routine will need to swap every member each time the condition for a swap exists, i.e. although determining if the swap condition exists only considers one member, swapping will include all members: weight, price, Color and Equip. And, if Color and Equip are of struct type (your post does not specify), then each member of these objects belonging to array elements being compared, will also need to be swapped.
You should look forward to eventually using pointers as this will significantly reduce the number of assignment statements needed to complete this sort.

Assigning point to customer C programming

I would like to get assistance in my coding. I created a customer loyalty system using C (using file) and now I need to assign some called points to my customer, but what happenned is it will not assign any points to them.
{
for (int i = 0; i < (count / 3); i++)
{
fscanf(reward_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, &user[i].Points);
if (Point = user[i].Points)
{
strcpy(user[i].Points, Reward);
Point = Point + Reward;
printf("%d", Point);
system("pause");;
}
}
fclose(reward_file);
FILE *new_file = fopen("CustomerRegistration.txt", "w");
for (int i = 0; i < NumOfCust; i++)
{
fprintf(new_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, user[i].Points);
}
fclose(new_file);
printf("You Have Successfully Added Your Point!!!\n");
printf("You Will be Redirected Back to Customer Privilege Menu");
system("TIMEOUT \t 5");
}
I am using struct for my customer and here is the code
struct USER
{
char Username[255];
char Password[255];
int Points;
};
struct USER user[100];
Data is obtained from a function called "Login"
FILE *LOGINFILE = fopen("CustomerRegistration.txt", "r");
if (LOGINFILE)
{
system("cls");
printf("!!!Hello Customer!!!\n");
printf("Please type in your Username and Password\n");
printf("Username\t: ");
//while ((c = getchar()) !='\n');
gets(UN);
printf("Password\t: ");
gets(Pswd);
I also assigned global variable called "Point"
int Point = 0;
Your help will be highly appreciated.
From what I am understanding from your posted code you want to add a Reward to the Customer Points.
Firstly you just need to add to user.Points the Reward, using strcpy makes no sense because that function is used for copying strings.
that if( Point = user[i].Points ) also makes no sense firstly because C equality condition is represented by a double equal sign ( "==" ) and you don't need to make that check.
The .Points member is an int and Reward is also an int ,so you can do arithmethic operations and there is no need to use another Point auxiliar.
for (int i = 0; i < (count / 3); i++)
{
fscanf(reward_file, "%s\n%s\n%d\n", user[i].Username, user[i].Password, &user[i].Points);
user[i].Points += Reward;
printf("%d", user[i].Points);
system("pause");;
}
.....
the first loop:
for (int i = 0; i < (count / 3); i++)
the second loop
for (int i = 0; i < NumOfCust; i++)
if NumOfCust is greater than (count/3)) you'll get unitialized values on CustomerRegistration.txt. I can't see the values of those variables, but make sure it doesn't happen. The best would be to use the last value of i in the first loop to the stop condition for the second loop.

Please Help me with this ! [ Sorting Arrays]

Hello Everyone I created an address book by using arrays !... Here I got a problem with sorting arrays of type String .... When I want to Sort a contacts It will just Sort the first names Without moving Second name and phone numb..... etc .. I have no clear Idea about Moving whole line to sort in the address book ! ... I mean moving [first name, surname, phone number, Email] at the same time to the next line !... here is my Code!
void sortRecords() {
ofstream Cfile;
Cfile.open("addressbook.txt", ios::in);
string temp;
for (int i=0; i<line()-1; ++i)
{
for (int j=0; j<line()-1-i; j++)
{
while (first_name[j]>first_name[j+1])
{
temp= first_name[j+1];
first_name[j+1]=first_name[j];
first_name[j]=temp;
}
}
}
for (int p=0; p<line();p++)
{
Cfile<<first_name[p]<<setw(10)<<sur_name[p]<<setw(10)<<phone_number[p]<<setw(10)<<email[p]<<endl;
}
Cfile.close();
}
The efficient way to do this is with a second (numerical) array of "indirection pointers" - which say "the item originally at i is now at j". Then you only have to swap these indices around; but when you're done, you can generate the sorted array by running down this index array just once and making a copy of the elements. This is usually a good way to do it when you are sorting "bunches of stuff".
Alternatively, you just move all the items to their new location; you will want to write a "swap" function to keep your code legible...
It is usually a good idea, when you want to keep a bunch of related items together in an array, to declare a structure. In your case, this structure might look like this:
typedef struct {
char first_name[32];
char last_name[32];
char phone_number[16];
} entry;
Then you can declare your phone book as
entry phoneBook[100];
which would create enough space for 100 phonebook entries.
Finally, when you go through the list of entries, you might modify your bubble sort like this (assuming that n = number of entries):
for ( int i=0; i < n - 1; i++ )
{
for ( int j = i; j < n; j++ )
{
if (strcmpi(entries[j].first_name, entries[j+1].first_name) > 0)
{
swap(entries, j, j+1);
}
}
}
And finally you would have a swap function like this:
void swap(entry* e, int i, int j) {
// swap all elements of e[i] and e[j]
entry temp;
strcpy(temp.first_name, e[i].first_name);
strcpy(temp.last_name, e[i].last_name);
strcpy(temp.phone_number, e[i].phone_number;
strcpy(e[i].first_name, e[j].first_name);
strcpy(e[i].last_name, e[j].last_name);
strcpy(e[i].phone_number, e[j].phone_number;
strcpy(e[j].first_name, temp.first_name);
strcpy(e[j].last_name, temp.last_name);
strcpy(e[j].phone_number, temp.phone_number;
}

Resources