Difference in declaring structures - c

I was using my structure like this. I don't like to typedef as I have told it can hide errors.
However, I was looking at some sample code and I have seen structures declared like this. And this is the normal way I declare them.
struct person
{
int age;
char name[32];
};
using like this:
struct person person_a;
person_a.age = 20;
etc.
However, I have seen structures declared like this:
struct
{
int age;
char name[32];
}person;
and
struct _person
{
int age;
char name[32];
}person;
What is the difference between all these different techniques, and how would you decide when it is the best to use each particular one.
Many thanks for any suggestions,

This:
struct
{
int age;
char name[32];
}person;
declares a variable person that is a struct. The struct has no name, but you still use the person variable the same way.
struct _person
{
int age;
char name[32];
}person;
This is identical to:
struct _person
{
int age;
char name[32];
};
struct _person person;
It declares a struct named _person and then makes a variable called person of type struct _person.

In both the last two structures, you've allocated storage for the structure called person.
What I mean is if you have something like this:
struct person
{
int age;
char name[32];
};
It's just a declaration; no variable allocation is there and hence cannot be used inside the code. You can start using this structure after you have declared as follows:
struct person p1;
Then, p1 can be utilized p1.age or p1.name, etc.
In terms of real-world code, instead of
struct _person
{
int age;
char name[32];
}person;
we usually see
typedef struct _person
{
int age;
char name[32];
} person_t;
In this case, we can save typing and more importantly the structure behaves like any other built-in type such as int, etc.
For example,
person_t p1;
person_t *p1;
And, so on.

For the first case (of second example), you will use this approach if you are sure that you do need another object for this structure. This looks clean and is fast to code :)
For the second case you have a ready object named 'person' and an option to create an object later on as
struct _person object2
This is to explain why you will use either approach. The difference between them has been explained well above.

There's no magic there really,
struct person
{
int age;
char name[32];
} var;
is the same thing as:
struct person
{
int age;
char name[32];
};
struct person var;

The 1st code just creates the person struct.
The 2nd code creates an instance of the person struct called person_a.
The 3rd code creates an unnamed struct and an instance of it called person.
The 4th code creates a struct named _person and an instance of it named person.

If the purpose of the structure definition is to declare a logical data structure that has meaning outside of the local module, then you would expect to see the first construct in a header file.
In real world C code, structures are often declared for purley pragmatic reasons that are local in scope. For example, formatting data that will be copied into a buffer. In these cases it's very handy and logical to merge the structure type and variable declaration. Also, using an anoymous declaration for the structure type avoids cluttering the namespace with a name that is not needed.
I do have one critisim of these examples: in C, names with a leading underscore are considered to be reserved for compiler vendors by convention. So I don't think the last example is consistent with best practice.

Related

Are these two the same in C programming language?

Can i ask if the syntax for these two are the same? I keep getting confused because typedef construct have the struct name after the closing of the curly brace but for here it seems like the variable names are the ones defined after the closing of the curly brace.
struct{
int age;
float height;
}person1,*personPtr;
VS
struct person{
int age;
float height;
};
struct person person1;
struct person *personPtr;
In this declaration
struct{
int age;
float height;
}person1,*personPtr;
there are declared an unnamed structure an object of the structure type and a pointer to an object of the structure type.
You will be unable to refer the structure type in your program because it is unnamed.
These declarations
struct person{
int age;
float height;
};
struct person person1;
struct person *personPtr;
differ from the preceding declaration in the way as there is declared a named structure that can be referred in the program.
The code snippet would be equivalent if the first declaration will be rewritten like
struct person{
int age;
float height;
}person1,*personPtr;
Other answer addresses the question: "if the syntax for these two are the same?". Here, I will focus on the following statement:
"I keep getting confused because typedef construct have the struct name after the closing of the curly brace but for here it seems like
the variable names are the ones defined..."
So, although your post does not actually include a snippet showing a typedef struct {, I will include one here to help identify the differences between two cases, the unnamed struct and a typedef struct.
The difference between a typedef, for example...
typedef struct{
int age;
float height;
} person_s; //creates a new type "person_s"
person_s person1; //illustrates using new type to create an instance of the struct
...and one similar to your unnamed struct: (leaving off the pointer instance for simplification)
struct{
int age;
float height;
}person1;// create single instance of struct, but this instance
// cannot be used to create new instances
... is that the typedef version creates a new data type person_s. person_s can be used to create new instances of the struct anywhere in your code, within the scope in which it was created.
While the unnamed struct creates only one instance of the unnamed struct. And while the instance person1 can be used and referenced in several places of your code (limited only by the scope in which it was created.) but no new instances of the unnamed struct can be created beyond that initial instance person1.
So in summary,
person1 is a single instance of the unnamed struct and person_s is a brand new type. The new type can be used to create new instances of that variable like any other type. (eg int, float, ...), but no new instances of the unnamed struct can be created.
Can i ask if the syntax for these two are the same?
No, they are not.
The first version declares an anonymous struct (as it has no name) and two variables using that type,
The second version names the type, and then uses the type name to declare the variables.
I keep getting confused because typedef construct have the struct name
after the closing of the curly brace but for here it seems like the
variable names are the ones defined after the closing of the curly
brace.
Yes, variable declarations and typedef declarations are designed to be very similar, on purpose.
For example, int age; declares a variable called age. By adding a typedef before the declaration, as in typedef int age; we instead made age a type and not a variable. We can then use it to declare a variable
age my_age;
same as
int my_age;
And it works the same for structs
struct
{
int age;
float height;
} person;
declares a variable person, while
typedef struct
{
int age;
float height;
} person;
says that person is a type.
The design of making a typedef declaration look very similar to a variable declaration might have seemed like a good idea at the time, but perhaps it was not. More confusing than brilliant?

Why does this typedef code not create an instance

My understanding of the following structure code is that the last "s1" creates an instance of our new data type;
struct student
{
int age;
char *name;
}s1;
The addition of s1 is as if I had typed the following (after creating the structure type)
struct student s1;
However, if I use typedef, the code does not create an instance; instead it just makes s1 a synonym for struct student. Is this interpretation correct? I ask only because I find it odd that it doesn't work the same as the first block of code
typedef struct student
{
int age;
char *name;
}s1;
This doesn't create an instance of struct student called s1; it makes s1 the equivalent of typing struct student. What I find odd about this is that I thought typedef itself was enough to avoid typing struct student all the time. That is, if I had excluded s1 from the code block above, I could simply type
student s1;
instead of
struct student s1;
thanks to the addition of typedef.
If that is the case, then isn't this redundant:
typedef struct student
{
int age;
char *name;
} student;
I am already able to type simply student have C "substitute" in struct student simply by the first line of that last code block??
That's the way typedef works. By prepending it to what would otherwise be a variable definition, you create a declaration of a type alias. It's easier to see with a fundamental type:
int a; // a is a variable of type int
typedef int b; // b is a synonym for the type int
"What I find odd about this is that I thought typedef itself was enough to avoid typing struct student all the time. That is, if I had excluded s1 from the code block above, I could simply type student s1;"
No, that wouldn't work. Try it.
A typedef without a trailing name is syntactically correct, but meaningless.
int; // compiles, does nothing
typedef int; // compiles, does nothing

Clarification of C struct syntax

As usual, Wikipedia's article on structs is less than clear. It gives the syntax for structs as this:
[typedef] struct [struct_name]
{
type attribute;
type attribute2;
/* ... */
[struct struct_name *struct_instance;]
} [struct_name_t] [struct_instance];
What would the typedef keyword do here?
What does the [struct_name] mean? (Is it the name you're giving to the new struct data type?)
What does the [struct_name_t] mean?
what does the [struct_instance] mean? (Is it creating a single instance of the struct?)
I presume [struct struct_name *struct_instance;] creates a pointer in the struct which would point to a second instance of the struct). Correct?
I would greatly appreciate an example: Say I have three files: main.c, sub.c and sub.h. I want to declare an instance of a struct in sub.h, and instantiate and use it it in sub.c. Say I want a Song type struct, with members char name[20] and char artist[10], and say I want to make an instance, mySong, {"Me singing", "Me"}, how would this look in sub.c and sub.h?
Thanks
•What would the typedef keyword do here?
It would allow you to create a typedef of your structre, just like any other type. This allow you to not have to type struct xxx struct_name everytime. You don't need this, hence the []
•What does the [struct_name] mean? (Is it the name you're giving to the new struct data type?)
Yes, if you chose too. You can also make a nameless struct so you don't need to give it a name.
•What does the [struct_name_t] mean?
That's the typedef'd name, if you chose to typedef the struct
•what does the [struct_instance] mean? (Is it creating a single instance of the struct?)
Yes, it's for creating one or more instance(s) of the sturct
•I presume [struct struct_name *struct_instance;] creates a pointer in the struct which would point to a second instance of the struct). Correct?
Right, this would be usefull for a "next" type pointer in a linked list.
struct example:
typedef struct foo{
int count;
struct foo *next;
} foo_t myfoo;
is an example of that filled in; this allows you to declare a new struct via:
foo_t new_foo_struct;
because of the typedef and typedef'd name. If you omit those like this:
struct foo{
int count;
struct foo *next;
} myfoo;
Now you'd have to use the struct key word for every instance, such as:
struct foo new_foo_struct;
to break it up over more than 1 file:
/*sub.h*/
typedef struct{
char name[20];
char artist[10];
}song;
Then in the source:
/*sub.c*/
#include "sub.h"
/*this needs to go into a function or something...*/
song mysong;
strcpy(mysong.name, "Mesinging");
strcpy(mysong.artist, "Me");
That article is just wrongly mixing different concepts, rectified this now. A struct is declared through
struct tagname {
... fields ...
};
that's just it, only that the tagname part is optional in some contexts.
In addition you may
declare an alias for the struct type through typedef
or a variable of the struct type
"in one go", but I don't think that it is good style and should be separated.
sub.h
------
typedef struct{
char name[20];
char artist[10];
}song;
sub.c
----
song mysong={"Me Singing","Me"};
typedef struct struct_name
{
char name[20];
char artist[10];
}struct_name_t structInstance;
typedef - this means that you are creating a new type (struct_name_t)
So, in C code you can create an instance like this:
struct_name_t myVariable;
or you can explicitly write:
struct struct_name myVariable;
The structInstance at the end means that you want to create an instance of your struct at the same moment you defined it (and the name of that variable is structInstance). It's not something you will use all the time, but it is useful in some situations.
If you want to create an instance of your struct and assign/initialize members at the creation time, you can do it like this:
struct_name_t myVariable = { "Foo", "bar" };
The 'name' member will contain "Foo" and the artist member will contain "bar".
Note:
If you write this:
struct_name_t myVariable = { 0 };
That will fill your entire struct with zeroes!

Making a Linked List

typedef struct{
char name[25];
int yearOfBirth;
int district;
char gender;
int age;
CitizenType *next;
}CitizenType;
When I try to make a Linked List in this format in Visual Studio, I get all sorts of errors relating to syntax. (102 in total) but when I comment out the CitizenType *next; I get no errors. I realize it has something to do with referencing the structure before it has been completely declared, but I have no idea how to fix this.
Declare the typedef before (and separately from) the structure.
typedef struct citizen_type CitizenType;
struct citizen_type {
...
CitizenType *next;
};
The problem is that
CitizenType
enters into the namespace of types only after the structure ends.
So you can use the new type only after its declaration.
You can use instead of it a struct name (giving a name to the struct), or declaring the type before to declare the structure with a name, as in previous post.
Try this:
typedef struct node{
char name[25];
int yearOfBirth;
int district;
char gender;
int age;
struct node *next;
}CitizenType;
Check this stack overflow answer for more information about self referenced structs in C. From the answer:
A CitizenType cannot contain another CitizenType as it becomes
a never-ending recursion.
Hope it helps!

array type has incomplete element and field 'status' has incomplete type

Im a NOOB with programming and Im really stumped. I get "array type has incomplete element and field 'status' has incomplete type" errors when i compile this code. I have this linked with another pile of code "which is thankfully error free". the errors are identified in this section so any help will be appreciated.
Thank you. here's the C code
struct name;
struct book;
struct Library{
struct Book collection[100];
struct person patrons[100];
int totalBooks;
int totalPatrons;
};
struct person{
char first[32];
char last[32];
enum Stat status;
};
struct Book{
char title[32];
char author[32];
int id;
int year;
int status;
};
enum Stat{ACTIVE=1, INACTIVE=2, CHECKED_OUT=3, CHECKED_IN=4, UNDER_REPAIR=5, LOST=6};
~
Looks like you've come from a C background - unfortunately it isn't valid C# code.
Arrays are defined as char[] first; (also size isn't relevant at this point)
Enums do not need an enum prefix when defining the variables. Same with structs.
You don't need to declare structs for name and book
In fact, I think you're probably wanting to use a string variable instead of char arrays.
struct Library{
Book[] collection;
Person[] patrons;
};
struct Person{
string first;
string last;
Stat status;
};
struct Book{
string title;
string author;
int id;
int year;
int status;
};
enum Stat{ACTIVE=1, INACTIVE=2, CHECKED_OUT=3, CHECKED_IN=4, UNDER_REPAIR=5, LOST=6};
There are basically two things wrong with the section of code you showed that the compiler is complaining about:
C is case sensitive: struct book and struct Book are two different types.
In C, you cannot refer to a type until it has been declared; that is, you cannot define a field of type enum Stat before you define enum Stat.
The actual problem, then, is that the compiler doesn't know what a struct Book is at the point where you try to define an array of them. Similarly, it doesn't know what an enum Struct is at the point where you define a field of that type.
(Mostly unimportant tangent: The reason you are getting the "incomplete type" errors instead of something slightly more useful is because the compiler allows you, in certain cases, to use struct types that you don't actually have the full definition of, but only if you use them through so-called "opaque" pointers (that is, you never actually use the type, you just pass pointers to them around.) In your case you are telling the compiler you want an array of struct Book, which requires a completely define type, which you don't have.)
To fix it you just need to reorder your type definitions so that none of them are used before they're defined, and use consistent casing throughout. Also, while it's legal to continue to refer to struct foo and enum bar in the rest of your program, most people would create a typedef (basically, type aliases) instead. For example:
typedef enum tagStat {
ACTIVE=1,
INACTIVE=2,
CHECKED_OUT=3,
CHECKED_IN=4,
UNDER_REPAIR=5,
LOST=6
} Stat;
typedef struct tagPerson {
char first[32];
char last[32];
Stat status;
} Person;
typedef struct tagBook {
char title[32];
char author[32];
int id;
int year;
int status;
} Book;
typedef struct tagLibrary {
Book collection[100];
Person patrons[100];
int totalBooks;
int totalPatrons;
} Library;
It looks like you are trying to use the Stat enum in your definition of person before you declare/define it. Add enum Stat; where you have the struct statements at the top of the file.

Resources