Why does where you declare function matter? - c

So im just learning C but from my understand we can create Function Prototypes anywhere right?
So then when i was experimenting with function and structure why is it that. If i put the function prototype before the structure declaration is does not work but when i put the function prototype after the structure declaration it does work ?.
Could some kind soul explain this?
Before structure declaration (Does not Work)
/* Function Prototypes */
void printID(struct studentID person);
/* Structure Decleration */
struct studentID{
char Name[50];
int Age;
int Birth_Year;
};
int main(){
struct studentID me = {"BOB", 25, 1996};
printID(me);
return 0;
}
/* Function Details */
void printID(struct studentID person){
printf("Your Name is %s\n", person.Name);
printf("Your Age is %d\n", person.Age);
printf("Your date of birth is %d\n", person.Birth_Year);
}
After Structure declaration (Does Work)
/* Structure Decleration */
struct studentID{
char Name[50];
int Age;
int Birth_Year;
};
/* Function Prototypes */
void printID(struct studentID person);
int main(){
struct studentID me = {"BOB", 25, 1996};
printID(me);
return 0;
}
/* Function Details */
void printID(struct studentID person){
printf("Your Name is %s\n", person.Name);
printf("Your Age is %d\n", person.Age);
printf("Your date of birth is %d\n", person.Birth_Year);
}

Data types must be defined before you can use them.
Since printID has a parameter of type struct studentID, the definition of struct studentID must come before the declaration of printID.
C compilers process files in a single pass, so all types must be defined before they can be used, and all functions must be at least declared before they can be called.
A type definition must be complete before you can create an instance (object) of that type. For struct, union, and enum types, the type definition isn’t complete until the closing }.
However, you can declare pointers to incomplete types; IOW, the following would be perfectly legal:
struct studentID; // incomplete type definition
void printID( struct studentID *person );
struct studentID {
...
}; // type definition is now complete
You would still need the definition of struct studentID to be complete before you could dereference it in the body of printID, so you would have to put the body of printID after this.

Related

Incompatible pointer types with array of structs

I'm trying to write a function that reads a file into an array of structs and returns said array. When I do test runs, it seems to be working appropriately (i.e. prints each entry as anticipated). But I keep getting a warning:
main.c:53:16: warning: incompatible pointer types returning 'struct Vehicles *' from a
function with result type 'struct Vehicles *' [-Wincompatible-pointer-types]
return inventory;
Which sounds a little funny because, come on, struct Vehicles * is incompatible with struct Vehicles *? Can anyone help me understand why I am getting this warning and possibly provide additional insight into how to appropriately return an array of structs?
The 'hw2.data' file I am testing this with only has three entries (but our instructor will test with 100 entries) and looks like this:
F150 5.4 28000 white
RAM1500 5.7 32000 orange
TOYOTA 2.1 16000 red
And my function (so far), looks like this:
struct Vehicles *readFile(char file_name[16]) {
struct Vehicles {
char vehicle[16];
float engine;
int price;
char color[16];
};
struct Vehicles *inventory = malloc(sizeof(struct Vehicles)*100);
FILE *input;
char vehicle[16];
float engine;
int price;
char color[16];
int count = 0;
//struct Vehicles inventory[3];
input = fopen(file_name, "r");
while (fscanf(input, "%s %f %d %s", vehicle, &engine, &price, color) == 4) {
strcpy(inventory[count].vehicle, vehicle);
strcpy(inventory[count].color,color);
inventory[count].engine = engine;
inventory[count].price = price;
printf("%s %.2f %d %s\n", inventory[count].vehicle, inventory[count].engine, inventory[count].price, inventory[count].color);
count++;
}
fclose(input);
return inventory;
}
int main(void) {
readFile("hw2.data");
return 0;
};
You define the struct inside the function, which means it can only be used inside the scope of the function (its body). Thus, you can't make it a return type.
Move the struct out of the function's body:
struct Vehicles {
char vehicle[16];
float engine;
int price;
char color[16];
};
struct Vehicles *readFile(char file_name[16]) {
struct Vehicles *inventory = malloc(sizeof(struct Vehicles)*100);
// ...
}
Two declarations of a structure in different scopes declare different types, per C 2018 6.7.2.3 5: “Two declarations of structure, union, or enumerated types which are in different scopes or use different tags declare distinct types.”
In struct Vehicles *readFile(char file_name[16]) {…, the structure declaration is at file scope.
The declaration inside the function, struct Vehicles {… is at block scope.
Therefore, these two uses of struct Vehicles, even though they use the same tag, refer to different types.

struct Employee {} compare struct {} Employee

I read a tutorial in which there is this struct:
struct
{
char Name[25];
int Age;
float SkillRating;
} Employee;
defines a new aggregate, called Employee, containing fields called Name (of type character), Age (of type integer), and SkillRating (of type float).
In contrast, the C statement:
struct EmployeeType
{
char Name[25];
int Age;
float SkillRating;
};
does not define a new aggregate variable, but defines a new aggregate type,
EmployeeType.
This new data type could then be used to declare variables in the
same way as a primitive data type. That is, in the same way that C allows the
variable x to be declared as an integer using the statement
I am confused here. Does the distinction exist if place 'Emplyee` on different position?
I guess they are identical.
In the first case, the struct is unnamed and Employee is a variable of that unnamed struct. You can directly modify it like this:
int main()
{
Employee.Age = 100;
return 0;
}
In the second case, EmployeeType is just a type, but you didn't make any instance of it yet. You can make any amount of instances:
int main()
{
struct EmployeeType a; // employee on the stack
a.Age = 100;
struct EmployeeType *b = malloc(sizeof(struct EmployeeType)); // employee on the heap
if (b) { // set the age of b if the allocation succeeded
b->Age = 100;
}
free(b); // malloc-allocated memory must be freed afterwards
return 0;
}
You can even do both at once:
struct EmployeeType
{
char Name[25];
int
Age;
float SkillRating;
} Employee;
Here, Employee is one instance of it, but you can make additional instances:
int main()
{
Employee.Age = 100;
struct EmployeeType a; // employee on the stack
a.Age = 100;
return 0;
}
struct A_s { int memb; }; // declares a struct A_s
struct A_s a; // declares a variable a of type struct A_s
now you can combine struct declaration with variable declaration:
// declares struct A_s and in the same line declares variable a
struct A_s { int memb; } a;
Now you can create an anonymous struct by omitting the structure tag name:
// declares anonymous struct and in the same line declares variable a
struct { int memb; } a;
Now structure declaration can be really put anywhere:
int func(int a, struct A_s { int memb; } b);
struct A_s { int memb; } func(int a);
struct B_s {
int memb1;
struct A_s {
int memb2;
} a;
};
I think the description of the C code of the field "name" in your post is invalid. The field name inside "aggregate" (read as: structure) has the type "array of 25 characters", not character type.
struct keyword in C can be used to declare aggregate datatypes, aggregate data objects or both.
In your first declaration (and definition), a tag name is missing, so an anonymous object 'Employee' is created. 'Employee' remains the only object of this struct. You cannot create more objects from this struct anywhere else in the code.
In your second declaration, you have created a struct type which can be instantiated many times (i.e., multiple instances of this struct can exist) as shown below -
struct EmployeeType employee_1;
struct EmployeeType employee_2;
Both these syntax are useful depending on the use case.

What this Declaration meant in C

I have a structure in C and at end have some declration which not able to decode
struct Student
{
int roll;
char name;
int age;
};
extern struct Student dev[];
what does last statement mean in C??
extern struct Student dev[];
Tells the compiler that dev is an array of the type struct Student and it is defined somewhere else(other translation unit).
It means that dev[] is not declared in this C/object file, but in another. You'll have to link that other object to your binary to be able to use that variable.
struct students
{
int num;
char name[100];
char dept[100];
} extern struct students student[];
student[] is the structure array.its used for the access the structure members
like num,name,dept.
int j=100;
#include<stdio.h>
main(){
for(i=0;i<j;i++)
{
scanf("%d",&student[i].num);
scanf("%s",student[i].name);
scanf("%s",student[i].dept);
}
for(i=0;i<j;i++)
{
printf("%d\n",student[i].num);
printf("%s\n",student[i].name);
printf("%s\n",student[i].dept);
}
}
It is used to the access the 100 records of members of the structure

Passing struct to function

I'm a new C programmer and I wanted to know how I can pass a struct through to a function. I'm getting an error and can't figure out the correct syntax to do it. Here is the code for it....
Struct:
struct student{
char firstname[30];
char surname[30];
};
struct student person;
Call:
addStudent(person);
Prototype:
void addStudent(struct student);
and the actual function:
void addStudent(person)
{
return;
}
Compiler errors:
line 21: warning: dubious tag declaration: struct student
line 223: argument #1 is incompatible with prototype:
This is how to pass the struct by reference. This means that your function can access the struct outside of the function and modify its values. You do this by passing a pointer to the structure to the function.
#include <stdio.h>
/* card structure definition */
struct card
{
int face; // define pointer face
}; // end structure card
typedef struct card Card ;
/* prototype */
void passByReference(Card *c) ;
int main(void)
{
Card c ;
c.face = 1 ;
Card *cptr = &c ; // pointer to Card c
printf("The value of c before function passing = %d\n", c.face);
printf("The value of cptr before function = %d\n",cptr->face);
passByReference(cptr);
printf("The value of c after function passing = %d\n", c.face);
return 0 ; // successfully ran program
}
void passByReference(Card *c)
{
c->face = 4;
}
This is how you pass the struct by value so that your function receives a copy of the struct and cannot access the exterior structure to modify it. By exterior I mean outside the function.
#include <stdio.h>
/* global card structure definition */
struct card
{
int face ; // define pointer face
};// end structure card
typedef struct card Card ;
/* function prototypes */
void passByValue(Card c);
int main(void)
{
Card c ;
c.face = 1;
printf("c.face before passByValue() = %d\n", c.face);
passByValue(c);
printf("c.face after passByValue() = %d\n",c.face);
printf("As you can see the value of c did not change\n");
printf("\nand the Card c inside the function has been destroyed"
"\n(no longer in memory)");
}
void passByValue(Card c)
{
c.face = 5;
}
The line function implementation should be:
void addStudent(struct student person) {
}
person is not a type but a variable, you cannot use it as the type of a function parameter.
Also, make sure your struct is defined before the prototype of the function addStudent as the prototype uses it.
When passing a struct to another function, it would usually be better to do as Donnell suggested above and pass it by reference instead.
A very good reason for this is that it makes things easier if you want to make changes that will be reflected when you return to the function that created the instance of it.
Here is an example of the simplest way to do this:
#include <stdio.h>
typedef struct student {
int age;
} student;
void addStudent(student *s) {
/* Here we can use the arrow operator (->) to dereference
the pointer and access any of it's members: */
s->age = 10;
}
int main(void) {
student aStudent = {0}; /* create an instance of the student struct */
addStudent(&aStudent); /* pass a pointer to the instance */
printf("%d", aStudent.age);
return 0;
}
In this example, the argument for the addStudent() function is a pointer to an instance of a student struct - student *s. In main(), we create an instance of the student struct and then pass a reference to it to our addStudent() function using the reference operator (&).
In the addStudent() function we can make use of the arrow operator (->) to dereference the pointer, and access any of it's members (functionally equivalent to: (*s).age).
Any changes that we make in the addStudent() function will be reflected when we return to main(), because the pointer gave us a reference to where in the memory the instance of the student struct is being stored. This is illustrated by the printf(), which will output "10" in this example.
Had you not passed a reference, you would actually be working with a copy of the struct you passed in to the function, meaning that any changes would not be reflected when you return to main - unless you implemented a way of passing the new version of the struct back to main or something along those lines!
Although pointers may seem off-putting at first, once you get your head around how they work and why they are so handy they become second nature, and you wonder how you ever coped without them!
You need to specify a type on person:
void addStudent(struct student person) {
...
}
Also, you can typedef your struct to avoid having to type struct every time you use it:
typedef struct student{
...
} student_t;
void addStudent(student_t person) {
...
}
Instead of:
void addStudent(person)
{
return;
}
try this:
void addStudent(student person)
{
return;
}
Since you have already declared a structure called 'student' you don't necessarily have to specify so in the function implementation as in:
void addStudent(struct student person)
{
return;
}

What am i doing wrong in this code?

#include <stdio.h>
main()
{
typedef struct{
char *name;
int age;
}person[5];
int i;
for (i=0;i<5;i++){
printf ("name:");
scanf("%s",person[i].name);
printf("\nage:");
scanf("%d",&person[i].age);}
for (i=0;i<5;i++){
printf ("person:%d",i);
printf ("name:%s",person[i].name);
printf ("age:%d",person[i].age);
}
}
this is the sample program i have. But while compiling i keep getting the error "expected expression before person in line 10,12,16 and 17? What am i doing wrong?
To fix the syntax error, remove the typedef keyword (you're trying to declare a variable, not a type).
Better yet, change to:
typedef struct{
char *name;
int age;} Person;
Person person[5];
Also, the following is wrong:
scanf("%s",person[i].name);
You need to first allocate memory for person[i].name (for example, using malloc()).
Lastly, the %s format specifier in the following line is not correct:
printf ("age:%s",person[i].age);
person is a type, not an object. You cannot "scanf() into a type: person".
I'd simply remove the typedef and just leave the struct definition outside the body of main; and create an object inside
struct person { /* ... */ };
int main(void) {
struct person person[5];
/* ... */
return 0;
}

Resources