C - Passing structures through function arguments - c

I am asked to write a function that takes two values from the structure type and compare them. If they are equal, it wants me to add two other values from those structures and send this to another structure. It is also supposed to return a 1 or 0 through the functions name, so I defined the function as an int.
I have attempted to write a program that takes an employee's social security number and their wage, and then another employee's ssn and wage. If the socials are the same, it will combine the two wages and send them to another structure which contains that employees total wages.
I am getting errors every time I mention the function compare. This appears to be due to the arguments of the function. How can this be done properly?
#include <stdio.h>
#include <stdlib.h>
#define EMPLOYEE_COUNT 4
struct ewage
{
int ssn;
int wage;
}
struct record
{
int totalwage;
}
int compare(struct ewage s1, struct ewage s2, struct record *r);
int main (void)
{
struct ewage e[EMPLOYEE_COUNT];
struct record r[EMPLOYEE_COUNT];
int i, j;
for (i = 0; i < EMPLOYEE_COUNT; i ++)
{
for (j = i + 1; j < EMPLOYEE_COUNT; j ++)
{
int success = compare(e[i], e[j], &record[i]);
if (success == 1)
printf ("%d / %d | Record: %d \n", i, j, record[i]);
else
printf ("%d / %d | DOES NOT MATCH \n", i, j);
}
}
system ("PAUSE");
return 0;
}
int compare(struct ewage s1, struct ewage s2, struct record *r)
{
if (s1.ssn == s2.ssn)
{
r->totalwage = s1.wage + s2.wage;
return 1;
}
return 0;
}

You need semicolons after your struct defintion
struct ewage
{
int ssn;
int wage;
}; // here
struct record
{
int totalwage;
}; // here
record is not defined, I assume it's real name is r
int success = compare(e[i], e[j], &r[i]); // here
if (success == 1)
printf ("%d / %d | Record: %d \n", i, j, &r[i]); // here
Finally, you need something to print with the final %d, I assume total wage here:
printf ("%d / %d | Record: %d \n", i, j, r[i].totalwage); // here
Now you can start to debug it ...

there are a few mistakes:
1.there should be a ';' after the definition of a struct
2.you shouldn't pass a type 'record' to your function compare,instead you should pass &r[i]

Related

Printing out values in an array not working as expected

I was tasked with inputting student information based on a given struct, where each field of information is to be typed in one line, separated by a space, then the student id is sorted incrementally, and then print out the information, each student on a new line. The problem is while I thought my code was good, the print part keeps giving fractured results and overall just not printing out the correct values. Where should I fix this?
Here's my code:
#include <stdio.h>
typedef struct
{
char id[8];
int year;
}student;
int main() {
student std[100];
int i, j, num, tmp;
printf("So sinh vien:\n");
scanf("%d", &num);
printf("Nhap thong tin sinh vien:\n");
for(i=0; i <= num; i++)
{
scanf("%c %d\n", &std[i].id, &std[i].year);
}
for(i=0; i < num; i++)
{
for (j=1; j< num; j++)
{
if (std[i].id > std[j].id)
{
tmp = *std[i].id
*std[i].id = *std[j].id;
*std[j].id = tmp;
}
}
}
for(i=0; i < num; i++)
{
printf("%c ", std[i].id);
printf("%d\n", std[i].year);
}
return 0;
}
My output is
So sinh vien:
3
Nhap thong tin sinh vien:
12324521 2003
12341552 2002
12357263 2001
Σ 12324521
≡ 3
ⁿ 2341552
Check the return value of scanf() otherwise you may be operating on uninitialized variables.
Check that num less than the 100 records you allocated for student, or even better use a vla along with a check to avoid large input from smashing the stack.
You input num then read num+1 records but later you only print num records.
As you read a character with "%c" the first input with be the \n from the previous scanf().
The struct contains a char id[8] but you only read a single character into it. Read a string instead.
In sort you use > to compare the first letter of id. You probably want to use strcmp() to compare strings.
In sort section you use a int tmp for storing a character of id (which is ok) but then you write an int which is no good.
In sort you only swap the ids. You probably want to swap the entire record not just the ids.
It seems to be an exchange sort. Use a function, and also at least for me the algorithm didn't work as the inner loop variable should start at j=i+1 not 1.
In your print char id[8] as a single char instead of string.
Moved print functionality to a function. This allows you, for instance, to print the students before and after the sort() during debugging.
Minimizing scope of variables (i and j are now loop local, tmp is only used in the swap() function). This makes code easier to reason about.
#include <stdio.h>
#include <string.h>
#define ID_LEN 7
#define str(s) str2(s)
#define str2(s) #s
typedef struct {
char id[ID_LEN+1];
int year;
} student;
void swap(student *a, student *b) {
student tmp = *a;
*a = *b;
*b = tmp;
}
void print(size_t num, student std[num]) {
for(size_t i=0; i < num; i++)
printf("%s %d\n", std[i].id, std[i].year);
}
// exchange sort
void sort(size_t num, student std[num]) {
for(size_t i=0; i < num - 1; i++)
for (size_t j=i+1; j < num ; j++)
if(strcmp(std[i].id, std[j].id) > 0)
swap(&std[i], &std[j]);
}
int main() {
printf("So sinh vien:\n");
size_t num;
if(scanf("%zu", &num) != 1) {
printf("scanf() failed\n)");
return 1;
}
if(num > NUM_MAX) {
printf("Too many students\n");
return 1;
}
student std[num];
printf("Nhap thong tin sinh vien:\n");
for(size_t i=0; i < num; i++)
if(scanf("%" str(ID_LEN) "s %d", std[i].id, &std[i].year) != 2) {
printf("scanf() failed\n");
return 1;
}
sort(num, std);
print(num, std);
}
and here is an example run:
So sinh vien:
3
Nhap thong tin sinh vien:
aaa 1
zzz 2
bbb 3
aaa 1
bbb 3
zzz 2
printf("%c ", std[i].id);
should be
printf("%s ", std[i].id);
%c means a single char.

Building a struct with a function

Hello i'm trying to build a function to search a car for a client by client demand.
The structure contains: model,year,price.
the client is asked to enter his demands and then the code calls a function that check if there is a car in the structure that is suitable for him.
I get error for "access violation reading error"
thanks!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define SIZE 10
typedef struct
{
char model[10];
float price;
int year;
}car;
void findCar(car *arr[], int minYear, float maxPrice, char modelWanted, int carAmount);
int main()
{
int carAmount;
car* arr;
puts("How many cars?");
scanf("%d", &carAmount);
arr = (car*)malloc(carAmount * sizeof(car));
if (arr == NULL)
return -1;
for (int i = 0; i < carAmount; i++)
{
puts("Enter car details, Model, Price,Year");
scanf("%s%f%d",arr[i].model,&arr[i].price,&arr[i].year);
}
char modelWanted[SIZE];
float maxPrice;
int minYear;
puts("Enter wanted model,maximum price and minimum year!");
scanf("%s%f%d", modelWanted, &maxPrice, &minYear);
for (int i = 0; i < carAmount; i++)
printf("Model is: %s, Price is: %.2f, Year is: %d\n", arr[i].model, arr[i].price, arr[i].year);
findCar(&arr, minYear, maxPrice, modelWanted, carAmount);
free(arr);
return 1;
}
void findCar(car *arr[], int minYear, float maxPrice, char modelWanted,int carAmount)
{
int i, counter = 0;
for (i = 0; i < carAmount; i++)
if (((strcmp(arr[i]->model, modelWanted)) == 0) && (arr[i]->year >= minYear) && (arr[i]->price <= maxPrice))
{
printf("Model is: %s, Price is: %.2f, Year is: %d\n", arr[i]->model, arr[i]->price, arr[i]->year);
++counter;
}
printf("We found %d cars for you!", counter);
}
You are passing pointer to array of struct
car *arr[]
so instead of accessing elements by arr[i]->model like you do, you should access them using (*arr)[i].model. The method you uses is for accessing the array of pointers to struct element, but you have pointer to array of struct.
Of course already commented char instead of char* will also cause run time error, but you should have received compiler warning for this.

How to search for multiple registers in a struct?

I have choice 2 that I need to fix. For example, if I have a name Marcus and user types in 'arc' should show all the names that contain 'arc' not just Marcus. My code works if I only type the whole name and only shows one line(register) anyways.
And then I have choice 3 lagersaldo ( stands for quantity ). If user registered 3 things for example with quantity.. 20, when search all the items with quantity 20 should show up. The code only shows one of them. Anyone can help solve this?
struct varor{
int varunummer;
char namn[WORDLENGTH];
int lagersaldo;
};
if(choice=='2'){
int i, namn;
printf("Ange namn: ");
scanf("%d", &namn);
i = ifNamnExists(namn, reg, nrOfGoods);
if(i>0){
printf("\nVarunummer \t Namn \t\t\t Lagersaldo\n");
printf(" %d \t\t %s \t\t\t %d\n",reg[i].varunummer,reg[i].namn,reg[i].lagersaldo);
}else printf("\nNamn finns inte!\n");
}
if(choice=='3'){
int i, lagersaldo;
printf("Ange lagersaldo: ");
scanf("%d", &lagersaldo);
i = ifLagersaldoExist(lagersaldo, reg, nrOfGoods);
if(i>0){
printf("\nVarunummer \t Namn \t\t\t Lagersaldo\n");
printf(" %d \t\t %s \t\t\t %d\n",reg[i].varunummer,reg[i].namn,reg[i].lagersaldo);
}else printf("\nLagersaldo för det nr. finns inte!\n");
}
if(choice=='4') run=0;
}
int ifNamnExists(char namn, const struct varor reg[], int nrOfGoods){
int i;
for(i=0; i < nrOfGoods; i++){
if(strcmp(&namn, reg[i].namn)==0){
return i;
}
}
return -1;
}
int ifVarunummerExist(int varunummer, const struct varor reg[], int nrOfGoods){
int i;
for(i=0; i<nrOfGoods; i++)
if(reg[i].varunummer == varunummer)
return i;
return -1;
}
As #BLUEPIXY has pointed out in short, your code needs a few modifications.
You are treating a substring as an integer rather than a string.
You are using strcmp() to check if a string has a substring while strcmp() does not work like that, it checks for the equality of two strings and returns a 0 value so, check out this function strstr().
You are returning the value in your for loop inside ifNamnExists(). A return statement returns the control back to the place where it was called. So, as soon as your code finds something, it returns back without iterating any further, same goes with the other function ifVarunummerExist().

Printing the data in multiple structs

I'm working with four differest structs, two of which are quite large. I have a function to write each value of each struct to a .txt file, but the code is very long and robust. I'm looking for a way of printing out each value without having to hard code each in, but everything I've found so far in my research indicates that hardcoding is the only way, but I figured I'd check on here before I give up completely. As it stands right now, my code looks like this:
char text[416];
snprintf(text, 416,
"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
epsy.VBUS_voltage_mV,
epsy.temp_internal_degC,
epsy.status,
batty.Z_pos_Camera_Temperature,
batty.Z_neg_Camera_Temperature,
batty.Y_pos_Camera_Temperature,
batty.Y_neg_Camera_Temperature,
batty.X_pos_Camera_Temperature,
batty.FPGA_Temp_1,
batty.FPGA_Temp_2,
batty.Rx_Hinge_Temperature,
batty.Bat_1_Vbat,
batty.Bat_1_Ichg,
batty.Bat_1_Idch,
batty.Bat_1_MCU_Temp,
batty.Bat_1_Temp_Therm,
batty.Bat_1_Status,
batty.Bat_2_Vbat,
batty.Bat_2_Ichg,
batty.Bat_2_Idch,
batty.Bat_2_MCU_Temp,
... and it goes on for a while. (80 values)
Is there a simpler way of doing this? If so, how do I do it?
The following solution defines a union that combines the actual struct with it's integral members with an array of integral values in order to "view" the struct members as array elements accessible through subscription.
To make this save, we need to control the alignment, since the compiler might add padding between the data members. This would then let the "array-view" point to invalid memory and introduce undefined behaviour.
I suggest to use #pragma pack(n) to control the alignment. Note that the code may also work without this alignment thing, yet it might get a problem if data members of other type are introduced before or after the "integral block" (This would also require to offset the "array-view", but that's not shown here).
The surrounding union is required to guarantee that the array and the struct are actually aligned correctly; otherwise, a cast from a struct to an array might introduce undefined behaviour.
I'm aware that #pragma pack is not portable and that it affects the memory layout and probably speed. Yet it is supposed to work on most compilers, and I think it is needed for controlling alignment in order to avoid UB:
#pragma pack(4) /* set alignment to 4 byte boundary */
#define nrOfMyPackedDataElements 3
union MyPackedData {
struct {
int32_t firstInt;
int32_t secondInt;
int32_t thirdInt;
} data;
int32_t array[nrOfMyPackedDataElements];
};
#pragma pack() /* reset alignment to compiler default */
int main() {
union MyPackedData data;
data.data.firstInt = 10;
data.data.secondInt = 20;
data.data.thirdInt = 30;
for (int i=0; i < nrOfMyPackedDataElements; i++) {
printf("%d ",data.array[i]);
}
return 0;
}
In C11 you could rewrite your structs using unnamed structures and union fields.
Something like this:
#include <stdio.h>
struct dir_t
{
int pos;
int neg;
};
struct cam_temp_t
{
dir_t x;
dir_t y;
dir_t z;
};
// it seems that you have only ints in your structure...
#define TOTAL_N_INTS 8
struct batty_t
{
union
{
int data_[TOTAL_N_INTS];
struct
{
struct cam_temp_t camera_temperature;
int fpga; // you get it...
int bat;
}
};
};
int main(void)
{
struct batty_t example = {
.camera_temperature = {
.x = {3, 4},
.y = {5, 6},
.z = {7, 8}
},
.fpga = 1,
.bat = 2
};
for (int i = 0; i < TOTAL_N_INTS; ++i )
{
printf("%4d", example.data_[i]);
}
return 0;
}
Of course if you have different types, you should use different arrays.
Accessing an int array via a struct and visa-versa like this answer might be valid, might not. Yet I am now not so confident for its use with general types. Leaving this as wiki for anyone to add/amend/delete.
OP later commented that the struct members are not all int. Oh well.
If all members are and forever will be int ...
Access each member, one at a time by int offset.
Some untested code to illustrate the idea:
int print_int_struct(char *dest, size_t d_size, const void *st, size_t s_size) {
if (s_size % sizeof(int) != 0) {
return -1; // bad struct size
}
size_t n = s_size / sizeof(int);
const char *delimiter = "";
for (size_t i = 0; i < n; i++) {
int d;
memcpy(&d, st, sizeof d);
st = (char*) st + sizeof(int);
int len = snprintf(dest, d_size, "%s%d", delimiter, d);
if (len < 0 || (size_t) len >= d_size) {
return -1; // out of room
}
dest += len;
d_size -= len;
delimiter = " ";
}
return 0;
}
struct s1 {
int VBUS_voltage_mV;
int temp_internal_degC;
int status;
...
};
struct s1 st = ...;
char buf[1024];
print_int_struct(buf, sizeof buf, &st, sizeof st);
puts(buf);

Quick sort function works only if last value is the largest

I'm trying to practice using Quick Sort in C. My program is a simple array of structs that takes in command line args (name1 age 1 name2 age2...etc) and outputs said ages in descending order.
It works correctly ONLY if the last age inputted is the largest. Other than that I either get no output or Seg Fault 11. Does anyone have any ideas?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NameLen 80
void print_struct();
struct people
{
char name [NameLen + 1];
int age;
}; //defining a structure//
typedef struct people PERSON;
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
int i,j;
j = 0;
int l = ((argc/2)-1);
struct people list[l]; //maximum size of array of structs
if (argc %2 == 0) //if the number of arguments is an even number
{
printf("Invalid Arguments!\n");
printf("Usage : ./hw5 name1 age1 name2 age2 ... "); //print error message and correct program usage
exit(0);
}
printf("You have entered %d persons(s) into the program \n",(argc/2));
for (i=1; i < argc; i+=2)
{
strcpy(list[j].name, argv[i]);
list[j].age = atoi(argv[i+1]);
if(list[j].age == 0)
{
printf("...Invalid age <=0. Try again.\n");
exit(0);
}
j++;
}
printf("Unsorted Names: \n");
print_struct(&list,argc);
printf ("Sorted by Age: \n");
quicksort(list,0 ,j);
for(i=0;i<j;i++){
printf("Name : %s| Age : %d\n", list[i].name, list[i].age);}//possible error here?
//Quicksort Function
Perhaps the problem is the value of j. Is j the length of list? Or the length of list - 1?
It seems like this would be what you would want:
j = length of list
printf ("Sorted by Age: \n");
quicksort(list,0 ,j-1);
for(i=0;i<j;i++){
printf("Name : %s| Age : %d\n", list[i].name, list[i].age);}
The quicksort function is fine. The issue is that you're calling it wrong:
quicksort(list,0 ,j);
The values you're passing in for first and last represent the index of the first and last elements. As evident from how you use j to loop through the elements, j is the number of elements. That means that the last element has index j-1.
So you're passing a value for last that is one element past the end of the array. When you then try to read/write this bogus element, you invoke undefined behavior which in your case (fortunately) leads to a segfault.
Pass in the actual index of the last element (i.e. one less than the size) and it runs successfully.
quicksort(list,0 ,j - 1);
Your loops are incorrect:
while(list[i].age<=list[pivot].age&&i<last)
i++;
It is possible for this loop to end with i == last, which is bad because you attempt to swap the value, which would be out of scope of the array.
while(list[j].age>list[pivot].age)
j--;
Here, since j starts as last, you start right off with reading outside of the array.
One possible remedy is to move j backwards first, then test (do-while style). Then, increment i, testing against the decremented j.
do --j; while(list[j].age>list[pivot].age);
do ++i; while(list[i].age<=list[pivot].age&&i<j);
I made the code a little bit simple (changed the array of chars to just a char to make it more simple as possible).
My thoughts are that when you call:
quicksort(list,0 ,j);
What you should call is:
quicksort(list,0 ,j-1);
Because the last parameter must be the array lenght minus 1, the last position.
I got no seg fault, when running your code, or the one I modified, if it is possible, double check the strings you are using as input.
Here is "my" vesion of the code.
Hope it helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NameLen 80
void print_struct();
struct people
{
char name;
int age;
}; //defining a structure//
typedef struct people PERSON;
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
int i,j;
j = 10;
struct people list[10]; //maximum size of array of structs
for (i=0; i < 10; i++)
{
list[i].name = 'a';
list[i].age = 10-i;
}
printf("Unsorted Names: \n");
for(i=0;i<j;i++){
printf("Name : %c| Age : %d\n", list[i].name, list[i].age);}//possible error here?
printf ("Sorted by Age: \n");
quicksort(list,0 ,j-1);
for(i=0;i<j;i++){
printf("Name : %c| Age : %d\n", list[i].name, list[i].age);}//possible error here?
}
void quicksort(struct people list[],int first,int last)
{
struct people temp;
int i,j,pivot;
if(first<last){
pivot=first;
i=first;
j=last;
while(i<j)
{
while(list[i].age<=list[pivot].age&&i<last)
i++;
while(list[j].age>list[pivot].age)
j--;
if(i<j){
temp=list[i];
list[i]=list[j];
list[j]=temp;
}
}
temp=list[pivot];
list[pivot]=list[j];
list[j]=temp;
quicksort(list,first,j-1);
quicksort(list,j+1,last);
}
}
after applying all the comments, this is the resulting code, which cleanly compiles, but will not link due to the two missing functions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN (80)
struct people
{
char name [NAME_LEN + 1];
int age;
}; //defining a structure//
typedef struct people PERSON;
// print_struct( ptrToList, numElements )
void print_struct( PERSON *, int );
// quicksort( ptrToList, firstOffset, numElements )
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
//int i,j;
//j = 0;
//int l = ((argc/2)-1);
int l = argc/2;
struct people list[l]; //maximum size of array of structs
if (argc %2 == 0) //if the number of arguments is an even number
{
//printf("Invalid Arguments!\n");
fprintf( stderr, "Invalid Arguments!\n" );
//printf("Usage : ./hw5 name1 age1 name2 age2 ... "); //print error message and correct program usage
fprintf( stderr, "Usage : %s name1 age1 name2 age2 ... ", argv[0]);
// exit(0);
exit( EXIT_FAILURE );
}
//printf("You have entered %d persons(s) into the program \n",(argc/2));
printf("You have entered %d persons(s) into the program \n", l);
//for (int i=1; i < argc; i+=2)
for (int i=1, j=0; j < l; i+=2, j++)
{
//strcpy(list[j].name, argv[i]);
memset( list[i].name, '\0', NAME_LEN+1);
strncpy( list[j].name, argv[i], NAME_LEN );
list[j].age = atoi(argv[i+1]);
if(list[j].age == 0)
{
fprintf( stderr, "...Invalid age <=0. Try again.\n");
//exit(0);
exit( EXIT_FAILURE );
}
//j++;
}
printf("Unsorted Names: \n");
//print_struct(&list,argc);
print_struct( list, l );
//printf ("Sorted by Age: \n");
//quicksort(list,0 ,j);
quicksort( list, 0, l );
printf ("Sorted by Age: \n");
// //for(i=0;i<j;i++)
//for( int i=0; i<l; i++ )
//{
// printf("Name : %s| Age : %d\n", list[i].name, list[i].age);
//}//possible error here?
//}
print_struct( list, l);
} // end function: main
//Quicksort Function

Resources