How to correctly pass structures to functions - c

So the question I'm working on has me creating a structure with 5 elements: id number, name, department, course, and year. I have to write a function that prints the names of people with certain years and a function that prints all data based on id number input.
When I type in 2020 as an input I get a segmentation fault. What could be causing this?
#include <stdio.h>
struct stud
{
int id;
char name[50];
char dep[50];
char course[50];
int year;
};
void printbyyear(struct stud *student,size_t sz, int a);
void printspecific(struct stud *b,size_t sz, int a);
int main()
{
int yr,num,b;
struct stud students[]={
{1,"Jon","math","calc",2019},
{2,"Tim","Language arts","calc",2020},
};
printf("Input year to search for:");
scanf("%d",&yr);
printbyyear(students, sizeof(students),yr);
printf("Input ID # to search for:");
scanf("%d",&num);
printspecific(students, sizeof(students),num);
return 0;
}
void printbyyear(struct stud *b,size_t sz, int a)
{
int i;
for(i=0;i<sz;i++)
{
if (b[i].year==a)
{
printf("%d %c %c %c %d",b[i].id,b[i].name,b[i].dep,b[i].course,b[i].year);
}
}
}
void printspecific(struct stud *b,size_t sz, int a)
{
printf("%d %c %c %c %d",b->id,b->name,b->dep,b->course,b->year);
return 0;
}```

There are many mistakes in your programs.
printbyyear(struct stud,yr);
that is not how you call a function with struct variable, change it as printbyyear(b1,yr); or printbyyear(b2,yr);
you are not using array of structs , so you don't need to use loops at all for your code.
if (b.year == a)
{
printf("%d %s %s %s %d",b.id,b.name,b.dep,b.course,b.year);
}
finally if you want to store multiple records, then use array of struct's like below.
struct stud students[]= {
{2,"Tim","Language arts","calc",2020},
{1,"Jon","math","calc",2019}
};
and call it as below ( sizeof(students)/sizeof(students[0]) ) gives the number of elements you have in your structure)
printbyyear(students, sizeof(students)/sizeof(students[0]), yr);
now you can use loops for printing because you passed an array
void printbyyear(struct stud *student, size_t sz, int y)
{
int i;
for(i=0;i<sz;i++)
{
if (student[i].year == y)
{
printf("%d %s %s %s %d",student[i].id,student[i].name,student[i].dep,student[i].course,student[i].year);
}
}
}
and you declaration of function should be as below
void printbyyear(struct stud *b,size_t size, int a);

I guess that here
if (b[i]stud.year==a)
You are trying to access b1, b2 and any other possible student. To do that you need an array of type struct stud
struct stud b[5];
Now your if condition makes sense. The function call should be:
printbyyear(b,yr);
And the declaration
void printbyyear(struct stud *b, int a)
Also since you initialize only two students, i.e. only two elements of your array, the for loop should be for(i=1;i<=2;i++) with a 2 not a 5.
Accessing uninitialised elements or accessing an array out of bounds will result in an undefined behaviour.

Correct is an ambiguous term, so I will just say this method is one that I prefer:
Passing the address of an object of significant size is advantageous in that the address of that object is going to be smaller than the object itself.
So given for example your struct (typedefed for readability) I would make the following modifications (i.e. to pass by reference to the address of the object.)
Read in-line comments and note corrections in code:
typedef struct
{
int id;
char name[50];
char dep[50];
char course[50];
int year;
}stud_s;
//modify to accept pointer, and add size of array argument
void printbyyear(stud_s *s, int yr, size_t size);
int main()
{
int yr,num;
stud_s b1[] = { {1,"Jon","math","calc",2019},
{2,"Tim","Language arts","calc",2020},
{3,"Jen","the arts","calc",2021},
{4,"Bob","painting arts","calc",2022},
{5,"jed","numeric arts","calc",2023}
};
size_t size = sizeof(b1)/sizeof(b1[0]);
printf("Input year to search for:");
scanf("%d",&yr);
printbyyear(b1,yr, size);// b1 is a pointer to array of struct here.
printf("Input ID # to search for:");
scanf("%d",&num);
return 0;
}
void printbyyear(stud_s *b, int a, size_t size)
{
int i=0;
//for(i=1;i<=5;i++)//results in out of bounds access to array
for(i=0;i<size;i++) //change magic number for actual size of array
{
if (b[i].year==a)
{
//fix format specifiers
printf("%d %s %s %s %d\n",b[i].id,b[i].name,b[i].dep,b[i].course,b[i].year);
//printf("%d %c %c %c %d",b[i].id,b[i].name,b[i].dep,b[i].course,b[i].year);
i++;
}
}
}

Related

How can we access members of the structure ,when our struct is an array?

typedef struct grades{
char s1[DIM];
char s2[DIM];
int i;
float f;
}grades;
void read(grades *s[]);
void write(grades *g[]);
int main() {
grades v[5];
read (&v);
write(&v);
return 0;
}
void read (grades *s[]){
printf("enter the name of the student number and point");
int i;
for (i=0;i<5;i++){
scanf("%s %s %d %f",s[i]->s1,s[i]->s2,s[i]->i,s[i]->f );
}
}
void write(grades *g[]){
int i;
for (i=0;i<5;i++){
printf("%s %s %d %f\n",g[i]->s1,g[i]->s2,(g[i]->i)+5,(g[i]->f)+5 );
}
in this short program, I want to define a struct to get students name, surname, number and then grade.
then add 5 grades to their grade and print it.
when we use array of structs, should we refer to the array, when we use it with pointer?
You declared an array of structures
grades v[5];
So in this call
write(&v);
the expression &v has the type grades ( * )[5]. This pointer type is not compatible with the functions' parameter type that is implicitly adjusted to grades **g.
You need to declare the functions like
void read(grades *s, size_t n);
void write( const grades *g, size_t n);
and to call the functions like
read( v, 5 );
write( v, 5 );
This call of scanf
scanf("%s %s %d %f",s[i]->s1,s[i]->s2, s[i]->i, s[i]->f );
shall be rewritten at least like
scanf("%s %s %d %f",s[i].s1,s[i].s2, &s[i].i, &s[i].f );

Why am I getting garbage value after displaying the data

I am getting garbage value when I display the records.
I have to create a database of students in C using array of structures and without pointers.
Is there any other way of doing this?
How to use array of structures?
#include <stdio.h>
struct student {
char first_name[10],last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student);
void display(struct student);
void main() {
struct student S[10];
int n, i;
printf("Enter the number of records to enter : ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
accept(S[i]);
}
for (i = 0; i < n; i++) {
display(S[i]);
}
}
void accept(struct student S) {
scanf("%s", S.first_name);
scanf("%s", S.last_name);
scanf("%d", &S.roll);
scanf("%s", S.address);
scanf("%f", &S.marks);
}
void display(struct student S) {
printf("\n%s", S.first_name);
printf("\n%s", S.last_name);
printf("\n%d", S.roll);
printf("\n%s", S.address);
}
Everything in C is pass-by-value. Which means you are modifying variable copy in stack frame, while real variable passed as parameter remains untouched.
You have to pass an pointer to variable which you want to modify in function.
// Function declaration
void accept(struct student *);
// Call
accept(&S[i]);
// Usage in function via dereference operator
scanf("%s",S->first_name);
If you would like to enter unknown amount of records, you should use VLA (since c99) or dynamically allocate structures.
VLA
scanf("%d",&n);
struct student S[n];
Dynamic callocation
scanf("%d",&n);
struct student * S = malloc(sizeof(struct student) * n);
Because in your case, if user input more that 9 records you are touching outside of bounds, which has undefined behavior.
There are multiple issues in your code:
The standard prototype for main without arguments is int main(void)
You should allocate the array dynamically with calloc.
you should pass structure pointers to the accept and display functions instead of passing structures by value. Passing the destination structure by value is incorrect as the accept function cannot modify the structure in the main function, which remains uninitialized and causes garbage to be displayed. Note that it is actually undefined behavior to access uninitialized data so the program could behave in even worse ways.
You should provide scanf() with the maximum number of arguments to store into character arrays to avoid potential buffer overflows.
you should verify the return values of scanf() to avoid undefined behavior on invalid input.
you could use the %[^\n] scan set to allow embedded spaces in the address field.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct student {
char first_name[10], last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student *sp);
void display(const struct student *sp);
int main(void) {
struct student *S;
int n, i, j;
printf("Enter the number of records to enter : ");
if (scanf("%d", &n) != 1)
return 1;
S = calloc(sizeof(*S), n);
if (S == NULL) {
return 1;
}
for (i = 0; i < n; i++) {
accept(&S[i]);
}
for (i = 0; i < n; i++) {
display(&S[i]);
}
free(S);
return 0;
}
void accept(struct student *sp) {
if (scanf("%9s%9s&d %19[^\n]%f",
sp->first_name, sp->last_name, &sp->roll,
sp->address, &sp->marks) != 5) {
printf("missing input\n");
exit(1);
}
}
void display(const struct student *sp) {
printf("%s\n", sp->first_name);
printf("%s\n", sp->last_name);
printf("%d\n", sp->roll);
printf("%s\n", sp->address);
printf("%f\n", sp->marks);
printf("\n");
}

How to return an array of structure by reference?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
char name[20];
char lastname[25];
int age;
}person;
void insert(person *p,int *num);
int main()
{
int num;
person p;
insert(&p,&num);
printf("Name: %s",p[0].nome); /* Here i would print the first struct by
my array, but: is not array or not pointer Why?? */
}
void insert(person *p, int *num)
{
int dim;
person *arr;
printf("Insert how many people do you want? "); /* How many index the
array should have */
scanf("%d",&dim);
arr = (person *) malloc(dim*sizeof(person)); /* I'm not sure for
this explicit cast. */
for(int i = 0; i < dim; i++)
{
printf("Insert name: ");
scanf("%s",arr[i].name);
printf("Insert lastname: ");
scanf("%s",arr[i].lastname);
printf("Insert age:': ");
scanf("%d",&arr[i].age);
}
*num = dim;
*p = *arr;
}
I've tried: `person *insert(int *num)
And it's works,but how can pass an array reference?`
This programm should ask how many person do you want to insert ( in function insert) and with a for, he should ask name,surname,age.
After the insert, he should print, but for quick, i would tried with first element (index) of array (structs).
You can't return entire array from the function, but you can return the base location of the array. For example you can do like this : person *insert(int *sz);. But i see in your code you're passing &p and the &num variable into the insert method, maybe you want to modify them within that function and manipulate it afterwards in your main(). For that i would have these recommendations:
Change Line 16 person p to person *p. Since p is supposed to hold base value of an array. Remember array name is nothing but a base address to the first element of the list.
Change your function definition to recieve person** rather than person*. Since you want to modify a pointer variable and therefore you'd need a pointer to a pointer variable. Change it like this:` void insert(person **p, int *num)
Free the memory after usage; add a free(p) at the end of main.
`

C: Using strcpy to transfer one struct element to an array

Okay, so we're supposed to prompt a user to enter 25000 lines of text.
Each line contains three integers each. We are then to pass the third integer in that line to another struct, and connect each integer until you have 25000 interconnected integers.
Here's what I've tried:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct graph{
int begin;
int end;
int cost;
} PathEdge;
int comp_fcn(const void *a, const void *b) {
return ((PathEdge *) a)->cost - ((PathEdge *) b)->cost;
}
int main(void)
{
int nlines,i;
char r;
int ecost,ebegin,eend;
scanf("%d",&nlines);
PathEdge edges[nlines+1];
for(i=0;i<nlines;i++)
{
scanf("%d, %d, %dn",&ebegin, &eend, &ecost);
edges[i].begin = ebegin;
edges[i].end = eend;
edges[i].cost = ecost;
struct town
{
struct town *north;
int name[25000];
};
struct town *root, *current;
root = malloc(sizeof(struct town));
root->north = NULL;
strcpy (root->name,ecost);
current = malloc(sizeof(struct town));
current->north = root;
strcpy (current->name,ecost);
}
printf("Please enter a node that you want to examine. If you want to exit, please press 'X'.n");
scanf("%c",&r);
switch(r)
{
case 'X':
case 'x':
printf("You entered a wrong value. Gomen. Try againn.");
break;
default:
if((0<r)&&(r<25000))
{
printf("You have accessed node %dn",r);
printf("Its neighboring nodes are %dn",edges[r].cost);
printf("Its neighboring nodes are %dn",edges[i].cost);
}
else
{
printf("Invalid input again. Please do try again. Thanksn");
}
break;
}
return 0;
}
And there are warnings...
"passing argument 1 of strcpy from incompatible pointer type"
"passing argument 2 of strcpy makes pointer from integer without a cast"
expected char*__ restrict __ but argument is of type 'int'
plus when I inputted that 25000 lines of text, segmentation fault happens. Please help. Thank you!
strcpy is for copying strings (i.e. zero terminated byte char "arrays"), you maybe should use memcpy instead.
Or if you just want to assign a single integer to one element in the array, use plain assignment:
current->name[someIndex] = ecost;
Or, maybe you intend that thename member should be a string? Then you should be using an array of characters and not integers. And you need to convert integer values to strings, using e.g. sprintf:
sprintf(current->name, "%d", ecost);
you can convert the integer to string using itoa and copy the string into root->name.
char str[20];
itoa(ecost, str, 10);
strcpy(root->name, str);
You did not state your exact issue so I am assuming you are overwhelmed and in that case you should try partitioning your implementation into functions so that you can work on isolated problems instead of a web of interconnected problems.
Here is one example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct graph {
int begin;
int end;
int cost;
} PathEdge;
const char * GenerateInput()
{
static char local[2000];
static int last = 0;
int a, b, c;
a = last++;
b = last++;
c = last++;
sprintf_s(local, 2000, "%i %i %i", a, b, c);
return local;
}
void PathEdgeInitializeFromString(PathEdge * edge, const char * str)
{
sscanf_s(str, "%d %d %dn", &edge->begin, &edge->cost, &edge->end);
}
void QueryAndPrint(PathEdge * edges, int edges_n)
{
printf("Enter a number from 1 to %i: ", edges_n);
int index = 0;
scanf_s("%i", &index);
--index;
if (index < 0 || !(index < (edges_n)))
printf("Error");
else
printf("%i, %i, %i\n", edges[index].begin, edges[index].cost, edges[index].end);
}
int main() {
PathEdge edges[25000];
for (int i = 0; i < 25000; ++i)
{
const char * line = GenerateInput();
PathEdgeInitializeFromString(edges + i, line);
}
QueryAndPrint(edges, 25000);
return 0;
}

C program football team structure with pointer elements and dynamic allocation

I have a question about passing function to another function which both have structure as arguments. First I created two structures:
typedef struct
{
char name[25],surname[25];int number;
}PLAYER;
typedef struct
{
char nameofteam[25];int numberofplayers;char *players;
}TEAM;
Then I defined a function to read elements of one player:
void readplayer(PLAYER *);
void readplayer(PLAYER *pi)
{
printf("name:");scanf("%s",pi->name);
printf("surname:");scanf("%s",pi->surname);
printf("number of player:");scanf("%d",&pi->number);
}
My question is how to create function which prototype is void readteam(TEAM*) which will read data for one team, but using function readplayer and call it in main()? Here is what I have tried:
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
char name[25],surname[25];int number;
}PLAYER;
typedef struct
{
char nameofteam[25];int numberofplayers;char *players;
}TEAM;
void readplayer(PLAYER *pi)
{
printf("name:");scanf("%s",pi->name);
printf("surname:");scanf("%s",pi->surname);
printf("number of player:");scanf("%d",&pi->number);
}
void readteam(TEAM *pt)
{
char players[101];int i;
printf("name of team:");scanf("%s",pt->nameofteam);
printf("number of players in team:");scanf("%d",&pt->numberofplayers);
printf("players:");scanf("%s",players);
pt->players=(char *)calloc(length(players)+1,sizeof(char));
copy(pt->players,players);
for(i=0;i<pt->numberofplayers;i++)
{
printf("%d.",i+1);
readplayer(pt+i);
}
}
void erase(TEAM *);
void erase(TEAM *pt)
{
free(pt->players);
}
int length(char *s)
{
int d=-1;
while(s[++d]);
return d;
}
void copy(char *s1,char *s2)
{
while(*s1++ = *s2++);
}
int main()
{
int i,n;
TEAM *p;
do
{
printf("n=");scanf("%d",&n);
}
while(n<1);
p=(TEAM *)malloc(n * sizeof(TEAM));
for(i=0;i<n;i++)
{
printf("%d.",i+1);readteam(p+i);
}
free(p);
}
This gives me an error at the last input (in compiling, not debugging). Must be because of inappropriate use of dynamic allocation. I didn't use <string.h library. Obviously, only the readteam function has to be in main().
Thanks for the answers.
You are confused on how to store the playsrs. You have created a PLAYER struct, but you never use it. Instead, you insist that players must be a single string.
But it should work like this: You have n teams. Ecah team has m players. All team info is stored in your ´TEAMstruct. All player info is stored in yourPLAYERstruct. Because a team is made up of players, there should be aPLAYER` entry in your struct:
typedef struct {
char name[25];
char surname[25];
int number;
} PLAYER;
typedef struct {
char nameofteam[25];
int numberofplayers;
PLAYER *players;
} TEAM;
Then, when you read players, you read the bare team info in readteam. But you don't read anything about individual players there, because you delegate that to readplayer. Of course, the pointer you pass to that function must be that for a player, not one for a team:
void readplayer(PLAYER * pi)
{
printf("name:");
scanf("%s", pi->name);
printf("surname:");
scanf("%s", pi->surname);
printf("number of player:");
scanf("%d", &pi->number);
}
void readteam(TEAM * pt)
{
int i;
printf("name of team:");
scanf("%s", pt->nameofteam);
printf("number of players in team:");
scanf("%d", &pt->numberofplayers);
pt->players = calloc(pt->numberofplayers, sizeof(*pt->players));
for (i = 0; i < pt->numberofplayers; i++) {
printf("Player %d:\n", i + 1);
readplayer(pt->players + i);
}
}
Your cast to (char *) hides the warning about incompatible types. You should cast only when you know what you're doing. In this simple program, you don't need casts.
In your original code, there are warnings about "implicit declarations". These concern your copy and length functions. (By the way, what's wrong with strlen and strcpy?) You should move these functions to the top so that they are declared before they are called. ALternatively, provide prototypes at the beginning of your code or in a header file, which you #include at the top. (But now that you read into PLAYER structs, these functions are no longer needed.)

Resources