How to initialize a field in a struct from another struct? C - c

So im new to C programming and my assignment is to write a function(Max_way) that prints the driver who had the total of longest trips.
im using these 2 structs:
#define LEN 8
typedef struct
{
unsigned ID;
char name[LEN];
}Driver;
typedef struct
{
unsigned T_id;
char T_origin[LEN];
char T_dest[LEN];
unsigned T_way;
}Trip;
and a function to determine the total trips of a certain driver:
int Driver_way(Trip trips[], int size, unsigned id)
{
int km=0;
for (int i = 0; i < size; i++)
{
if (id == trips[i].T_id)
{
km = km + trips[i].T_way;
}
}
return km;
}
but when im trying to print the details of a specific driver from an array of drivers, i receive the correct ID, the correct distance of km, but the driver's name is not copied properly and i get garbage string containing 1 character instead of 8.
i've also tried strcpy(max_driver.name,driver[i].name) with same result.
void Max_way(Trip trips[], int size_of_trips, Driver drivers[], int size_of_drivers)
{
int *km;
int max = 0;
Driver max_driver;
km = (int*)malloc(sizeof(int) * (sizeof(drivers) / sizeof(Driver)));
for (int i = 0; i < size_of_drivers; i++)
{
km[i] = Driver_way(trips, sizeof(trips), drivers[i].ID);
for (int j = 1; j < size_of_drivers; j++)
{
if (km[j] > km[j - 1])
{
max = km[j];
max_driver.ID = drivers[i].ID;
max_driver.name = drivers[i].name;
}
}
}
printf("The driver who drove the most is:\n%d\n%s\n%d km\n", max_driver.ID, max_driver.name, max);
}
any idea why this is happening?

Note that one cannot copy a string using a simple assignment operator; you must use strcpy (or similar) as follows:
if (km[j] > km[j - 1]) {
max = km[j];
max_driver.ID = drivers[i].ID;
strcpy(max_driver.name,drivers[i].name);
}
Also note that since you were using ==, this was not even a simple assignment, put a comparison. Changing to == likely fixed a compile-time error, but it did NOT give you what you want.

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;
}

Segmentation Fault when returning integer

I recently joined Stackoverflow community because I had to ask this question. I've been searching for possible explanations and solutions on the website but so far nothing enlightened me as I wanted. My error is probably caused by a very specific line of code. I'm trying to create a function that reads an array of struct votes, (struct contains integer member number, char *category, char *nominee) and copies all the votes that contain the same number and category to another array of struct. Basically to show all the repeated votes.
typedef struct
{
int member;
char *categ;
char *nom;
}Vote
Vote vote(int member, char *categ, char *nom)
{
Vote result;
result.member = member;
result.categ = categ;
result.nom = nom;
return result;
}
int votes_count(Vote *v, int n, Vote *v1)
{
int result = 0;
int *index = malloc(sizeof(int) * 1000);
int a = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (a == 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0)
{
v1[result++] = vote(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
for (int b = 0; b < a; ++b)
{
if( a > 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0 && j != index[b])
{
v1[result++] = voto(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
}
}
}
return result;
}
Afterwads, it returns the number of elements of new array that contains all repetitions. I want to use an array of ints to save all line indexes so that the function doesn't read and copy the lines it already accounted.
Sorry if the code is hard to understand, if needed I can edit to be more understandable. Thanks for any answears.
P.S: I'm portuguese, sorry in advance for grammar mistakes
if your only intention is to harvest the duplicates, you only need to compare to the elements that came before an element
you don't need the index[] array
For simplicity, I used two integer arrays, you should change them to your struct arrays, also change the compare function.
unsigned fetchdups(int orig[], int dups[], unsigned count)
{
unsigned this, that, ndup=0;
for (this=1; this<count; this++){
for (that=0; that<this; that++){
/* change this to your compare() */
if(orig[that] == orig[this]) break;
}
if (this == that) continue; /* no duplicate */
dups[ndup++] = this;
}
return ndup;
}

Having trouble making memset function?

void memSet(char destination[], char valueMemSet, int numOfValue)
{
char temp;
int j=1;
for (int i = 0; i <= numOfValue; i++)
{
temp = destination[i];
destination[i] = valueMemSet;
destination[j] = temp;
j++;
}
}
The array is originally "this is the source Concatenate means to link."
This is what I am trying to get "------this is the source Concatenate means to link."
This is What I am currently getting "-------Tthe source Concatenate means to link."
When I ran the debugger it saves the first letter of the array but every single one after gets replaced.
How can I solve this issue?
memset() is a function, which sets a particular value in a given memory, like you want to initialize total array's elements to some particular value(for eg - zero). So it will set the same in that array.
what you need here is strcat() function.
Is that what you need?
void memSet(char destination[], char valueMemSet, int numOfValue, int len)
{
int j=len-numOfValue;
for (int i = len-1;i>=numOfValue;i--) {
destinstion[i] = destination[j--];
}
for (int i = 0; i < numOfValue; i++)
{
destination[i] = valueMemSet;
}
}

Trouble accessing value in array of structs

I am having trouble with this code. In particular I can't seem to figure out why it is that the voteFractions() function doesn't work for me. It gets called appropriately, and all the correct parameters seem to reach the function, but I cannot get anything from "candidates[i].votes_fraction = candidates[i].votes/total;". All I ever get for candidates[i].votes_fraction is 0.00.
I tried running the program with NUMBER_OF_CANDIDATES = 1, and everything runs OK when that is the case, so I feel like I may be doing something silly, but I just can't seem to see it...
#define NUMBER_OF_CANDIDATES 10
typedef struct candidate{
char name[20];
int votes;
float votes_fraction;
} candidate;
int totalVotes(candidate *candidates)
{
int total = 0;
for (int i = 0; i<NUMBER_OF_CANDIDATES; i++)
total += candidates[i].votes;
return total;
}
void voteFractions(candidate *candidates, int total, char *winner)
{
float most_votes = 0, test;
for (int i = 0; i<NUMBER_OF_CANDIDATES; i++)
{
candidates[i].votes_fraction = candidates[i].votes/total;
if (candidates[i].votes_fraction > most_votes)
{
most_votes = candidates[i].votes_fraction;
strcpy(winner, candidates[i].name);
}
}
}
int main()
{
candidate candidates[NUMBER_OF_CANDIDATES];
int total;
char winner[20];
for (int i = 0; i<NUMBER_OF_CANDIDATES; i++)
{
printf("Enter candidate's name and the number of votes received: ");
scanf("%s %d", candidates[i].name, &candidates[i].votes);
}
total = totalVotes(candidates);
voteFractions(candidates, total, winner);
return 0;
}
The problem is that in this statement
candidates[i].votes_fraction = candidates[i].votes/total;
expression
candidates[i].votes/total
uses integer arithmetic because the both operands have type int. As total is always greater than or equal to candidates[i].votes then the result of the division is equal to 0. You have to write
( float )candidates[i].votes/total
Take into account that variable test is declared but not used in function voteFractions. You may remove it.
void voteFractions(candidate *candidates, int total, char *winner)
{
float most_votes = 0, test;
//...

Seg fault on malloc

I am reading integers from a file, and when I try to grow my array, I am getting a segmentation fault on the second call to growMyArray(struct myArray), specifically at int *grownArray = malloc(arrayToGrow.maxCount * sizeof(int));:
struct myArray growMyArray(struct myArray arrayToGrow) {
arrayToGrow.maxCount *= 2;
int *grownArray = malloc(arrayToGrow.maxCount * sizeof(int));
int i;
for (i = 0; i < arrayToGrow.count; i++)
grownArray[i] = arrayToGrow.numbers[i];
free(arrayToGrow.numbers);
arrayToGrow.numbers = grownArray;
return arrayToGrow;
}
My structure:
typedef struct myArray {
int count;
int maxCount;
int *numbers;
} myArray;
Reading from input redirection:
struct myArray getRandomNumbers() {
struct myArray randomNumbers;
randomNumbers.count = 0;
randomNumbers.maxCount = DEFAULT_SIZE;
randomNumbers.numbers = malloc(randomNumbers.maxCount * sizeof(int));
while (scanf("%d", &randomNumbers.numbers[randomNumbers.count]) == 1) {
randomNumbers.count++;
if (randomNumbers.count > randomNumbers.maxCount)
randomNumbers = growMyArray(randomNumbers);
}
return randomNumbers;
}
I find this particularly odd because growing the array always works the first time but never works the second time. I have used multiple values for DEFAULT_SIZE, ranging from 2 to 20000 on a set of test data of size 200000.
Is there an apparent reason why I am getting a segmentation fault on the second call to growMyArray, specifically at int *grownArray = malloc(arrayToGrow.maxCount * sizeof(int));?
You wrote past the end of the array.
while (scanf("%d", &randomNumbers.numbers[randomNumbers.count]) == 1) {
randomNumbers.count++;
if (randomNumbers.count > randomNumbers.maxCount)
randomNumbers = growMyArray(randomNumbers);
}
Because you use > in the test, the if only fires once randomNumbers.count = randomNumbers.maxCount + 1, i.e. the scanf writes to randomNumbers.numbers[randomNumbers.maxCount] which is past the end of the array.
Therefore, change > to >= in the if statement there.
take care of youre data type
typedef struct myArray {
int count;
int maxCount;
int *numbers;
} myArray;
this means that count and maxcount are signed integers and they can reach negative values which is not correct for count and can lead also to some memory corruption.

Resources