Chinaunix首页 | 论坛 | 博客
  • 博客访问: 891828
  • 博文数量: 132
  • 博客积分: 9976
  • 博客等级: 中将
  • 技术积分: 1781
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-30 20:40
文章分类

全部博文(132)

文章存档

2013年(1)

2011年(1)

2010年(15)

2009年(77)

2008年(36)

2007年(2)

我的朋友

分类: C/C++

2009-04-09 20:18:58

C struct

===========================================================================
from:


How to declare a structure in a header that is to be used by multiple files in c?


If I have a source.c file and it uses a structure like
struct a
{
    int i;
    struct b
    {
        int j;
    }
};
if this structure is to be used by some other file func.c how to do it?
shall we open a new header file and declare the structure there and include that header in the func.c?
or can we define the total structure in header file and include that in both source.c and func.c?
then how to declare that structure as extern in both the files. ?
shall we typedef it then how? pleez help me..- Manoj

----------------------------------------------------------------

For a structure definition that is to be used across more than one source file, you should definitely put it in a header file. Then include that header file in any source file that needs the structure.

The extern declaration is not used for structure definitions, but is instead used for variable declarations (that is, some data value with a structure type that you have defined). If you want to use the same variable across more than one source file, declare it as extern in a header file like:

extern struct a myAValue;

Then, in one source file, define the actual variable:

struct a myAValue;

If you forget to do this or accidentally define it in two source files, the linker will let you know about this.


----------------------------------------------------------------
if this structure is to be used by some other file func.c how to do it?

When a type is used in a file (i.e. func.c file), it must be visible. The very worst way to do it is copy paste it in each source file needed it.

The right way is putting it in an header file, and include this header file whenever needed.
shall we open a new header file and declare the structure there and include that header in the func.c?

This is the solution I like more, because it makes the code highly modular. I would code your struct as:

#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME

struct a
{
    int i;
    struct b
    {
        int j;
    }
};

#endif

I would put functions using this structure in the same header (the function that are "semantically" part of its "interface").

And usually, I could name the file after the structure name, and use that name again to choose the header guards defines.

If you need to declare a function using a pointer to the struct, you won't need the full struct definition. A simple forward declaration like:

struct a ;

Will be enough, and it decreases coupling.
or can we define the total structure in header file and include that in both source.c and func.c?

This is another way, easier somewhat, but less modular: Some code needing only your structure to work would still have to include all types.

In C++, this could lead to interesting complication, but this is out of topic (no C++ tag), so I won't elaborate.
then how to declare that structure as extern in both the files. ?

I fail to see the point, perhaps, but Greg Hewgill has a very good answer in his post #228691.
shall we typedef it then how?

    * If you are using C++, don't.
    * If you are using C, you should.

The reason being that C struct managing can be a pain: You have to declare the struct keyword everywhere it is used:

struct MyStruct ; /* Forward declaration */

struct MyStruct
{
   /* etc. */
} ;

void doSomething(struct MyStruct * p) /* parameter */
{
   struct MyStruct a ; /* variable */
   /* etc */
}

While a typedef will enable you to write it without the struct keyword.

struct MyStructTag ; /* Forward declaration */

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

void doSomething(MyStruct * p) /* parameter */
{
   MyStruct a ; /* variable */
   /* etc */
}

It is important you still keep a name for the struct. Writing:

typedef struct
{
   /* etc. */
} MyStruct ;

will just create an anonymous struct with a typedef-ed name, and you won't be able to forward-declare it. So keep to the following format:

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

Thus, you'll be able to use MyStruct everywhere you want to avoid adding the struct keyword, and still use MyStructTag when a typedef won't work (i.e. forward declaration)
Edit:

Corrected wrong assumption about C99 struct declaration, as rightfully remarked by Jonathan Leffler.

----------------------------------------------------------------
a.h:

#ifndef A_H
#define A_H

struct a
{
    int i;
    struct b
    {
        int j;
    }
};

#endif
there you go, now you just need to include a.h to the files where you want to use this structure.

----------------------------------------------------------------

===========================================================================

An Introduction to struct

Prev:
Next:



What is a struct?

A struct (short for STRUCTURE), is a collection of variables of different types. Structures are sometimes referred to as ABSTRACT DATA TYPES, or ADTs for short.

We already know how to store a group of variables of the same type using arrays.

Variables in a struct are called MEMBERS or FIELDS, and are accessed by their name.

Variables in an array are called ELEMENTS, and are accessed using square brackets an an index.



Declaring a Structure

Declaring a struct requires the struct keyword, followed by a name. Then you declare your collection of variables between a pair of curly brackets. For example:

struct human { 
char *name;
int age;
float height;
};
/* don't forget this
semi colon!!!! */

It's best to declare your struct before main.

human is now a structure type, with three fields: name, expressed as a string, an integer age and a floating point height.

You can put whatever data types you want. And you're not limited to normal variables either - arrays and pointers can also go into a struct, though, you must specify an array size.

You can NOT use the assignment operator with the struct declaration.

NOTE: The size of a struct is the sum of the sizes of all the variables it holds.



Declaring Structure Variables

Like with enum, you can insert a list of variables after the end bracket like this:

struct album { 
char *name;
char *artist;
int numTracks;
} CD1, CD2, CD3;

This declares three variables of the struct album type.

But if album was declared outside main, the three variables will be global variables.

So instead, you can write this inside main:

struct album CD1, CD2, CD3;

Or better still, declare your struct and write:

typedef struct album Album;

... then inside main:

Album CD1, CD2, CD3;

Try and group all your typedef statements outside main - it makes the code look neater and easier to maintain.



Initializing Structure Variables

Now that you know how to declare structure variables, there are two ways to initialize them: all the fields in one statement, or one field at a time.

To initialize all fields in one statement, you declare your variable as usual, but assign it a list of variables enclosed in brackets, like this:

struct human TR = {"Tony", 12, 1.5};

This is similar to the method of initializing arrays.

Now the struct human variable, TR has all three fields initialized: the name field holds the string, "Tony", the age field holds the integer, 12, and the height is 1.5.

To reference an individual field, you use the DOT OPERATOR to separate the struct variable name and the field name.

You can use the dot operator to initialize each field individually:

struct human TR;
TR.name = "Tony";
TR.age = 12;
TR.height = 1.5;

To access each field, use the dot operator again.

For example, TR.age will return 12.



Advantages of char *name Over char name[50]

When I first encountered structs I used a sized char array to store strings.

Suppose I redefine human:

struct human { 
char name[50];
int age;
float height;
};

The first disadvantage, is that the name array must have a size big enough to store any string I was going to use.

Secondly, the only (obvious) way to initialize a string field, is to do it all at once:

struct human TR = {"Tony", 12, 1.5};

TR.name = "Tony" won't work, simply because the only way of assigning a string into an array is when you declare an array: char name[5] = "Tony"; Recall that TR.name is actually a char pointer, but it's an R-value in this case. In other words, assigning a value into it wouldn't work, as it wasn't declared as a char *. But...

TR.name[0] = 'T'; 
TR.name[1] = 'o';
TR.name[2] = 'n';
TR.name[3] = 'y';
TR.name[4] = '\0';

... works because the elements of the name array are L-values.

If human was defined with char *name, you could use TR.name = "Tony"; because pointers are L-values: remember that strings are considered to be of type char * as well.



Arrays of Structure Variables

Like with the usual data types, you can store a group of similar typed variables in an array.

The method of declaring an array is the same as before, but initializing your elements isn't as simple as first thought...

#include 

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;
robots[2].name = "Martian Matt";
robots[2].energy = 30;

/* robots[0] = {"Lunar Lee", 50}; WON'T WORK,
BUT HERE'S ANOTHER WAY...

ROBOT robots[3] = { {"Lunar Lee", 50},
{"Planetary Pete", 20},
{"Martian Matt", 30} }; */


for(i=0 ; i<3 ; i++) {
printf("Robot %d is called %s ", i, robots[i].name);
printf("and has %d units of energy.\n", robots[i].energy);
}
return 0;
}

Output:

Robot 0 is called Lunar Lee and has 50 units of energy.
Robot 1 is called Planetary Pete and has 20 units of energy.
Robot 2 is called Martian Matt and has 30 units of energy.

Instinctively, I first declared my array of robots, then I tried initializing each element one by one like this:

robots[0] = {"Lunar Lee", 50};

Unfortunately, MSVC++ complained, and so I initialized each name and energy field separately for each robot, as shown above.

There is a quicker way of initialization, as shown in the commented section. It involves initializing the entire array all at once. Notice how I separated each array element with a line break for clarity. Also note that a group of fields must be enclosed in brackets as well: {"Lunar Lee", 50}, for example.



Prev:
Next:

Copyright © 2001-2003
Unauthorized copying not permitted

Designed and Developed Using


===========================================================================

Structs Part 2

Prev:
Next:



Using an Array as a Field

Just thought I'll show you an example of using an array as a field (apart from char arrays!)...

#include 

struct human {
char *name;
int age[2];
};

struct human {
char *name;
int age[2];
};

int main() {
struct human user;
int m;

printf("What is your name? ");
gets(user.name);

printf("\nHow old are you?\nYears: ");
scanf("%d", &user.age[0]);

printf("\nMonths: ");
scanf("%d", &user.age[1]);

m = user.age[1];

printf("\nYour name is %s and you are %d years ",
user.name, user.age[0]);
printf("and %d %s old.\n", m, (m==1 ? "month" : "months"));

return 0;
}

Output will depend on what you entered.

I must confess things didn't go according to plan: I declared user to be a global variable by placing it after the definition of a struct human, but MSVC++ didn't like it (something about assertion failure whatever that meant!). So I declared user inside main.

gets is used to get your name - we pass a char * into gets, which is ok here.

Then 2 scanfs are used to get your age: first the years, then the months. The program stores these values in the age array.

The rest is pretty much self explanatory: the (m==1 ? "month" : "months") part basically does a grammar correction.



Pointing to Structures and Using the Arrow Operator ->

Like with arrays, you can create pointers to structures. This time, the pointer stores the memory address of a structure variable.

Declaring you pointer follows along the same lines as with arrays, for example, if user was of type HUMAN (where HUMAN is struct human):

HUMAN *human_ptr = &user;

Or:

HUMAN *human_ptr;
human_ptr = &user;

- Both of these would do the trick. However, make sure you've declared all your program variables before initializing pointers, else you'd encounter problems later on!

Your compiler might complain if you try and declare variables after creating pointers, so it's best if you declare all your variables at the beginning of main, rather than "on the fly" e.g. halfway through main.

Now that you've created a pointer, you now access fields using the arrow operator, which is made up of two characters: a hyphen, then the greater than sign: ->. This replaces the dot operator, but other than that, accessing structure fields is similar:

human_ptr->name = "Martin";

Is the equivalent of:

user.name = "Martin";

Here's the last example rewritten using pointers:

#include 

typedef struct human HUMAN;

struct human {
char name[50];
int age[2];
};

int main() {
HUMAN user;
HUMAN *human_ptr;
int m; /* Declare m here... */

human_ptr = &user;

printf("What is your name? ");
gets(human_ptr->name);

printf("\nHow old are you?\nYears: ");
scanf("%d", &(human_ptr->age[0]));

printf("\nMonths: ");
scanf("%d", &(human_ptr->age[1]));

/* int m; Declaring m here caused a compilation error!! */

m = human_ptr->age[1];

printf("\nYour name is %s and you are ", human_ptr->name);
printf("%d years and ", human_ptr->age[0]);
printf("%d %s old.\n", m, (m==1 ? "month" : "months"));

return 0;
}

If you compare this example to the previous, you'll notice how similar it looks. The only difference is the pointer to user, human_ptr. Every occurrence of user. has been replaced by
human_ptr->
, as well as a few brackets added for clarity.



Passing Structures to Functions

This is similar to passing arrays to functions.

In the function declaration you need to specify the structure's type, then a name and any other arguments.

Passing pointers is a better way, but for demonstration purposes, here's a function that expects a ROBOT variable and displays some info:

#include 

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
int IQ;
float velocity;
};

void info(ROBOT r); /* declare function */

int main() {
ROBOT r1 = {"Earthling Ed", 100, 231, 4.1}; /* initialize 2 ROBOTs */
ROBOT r2 = {"Toxic Tom", 150, 254, 2.5};

info(r1);
info(r2);

return 0;
}

void info(ROBOT r) {
printf("%s has %d units of energy, an IQ of %d...\n",
r.name, r.energy, r.IQ);
printf("... and a velocity of %0.1f metres per second.\n",
r.velocity);
}

Output:

Earthling Ed has 100 units of energy, an IQ of 231...
... and a velocity of 4.1 metres per second.
Toxic Tom has 150 units of energy, an IQ of 254...
... and a velocity of 2.5 metres per second.

Notice how I moved the function declaration below the typedef statement, since I used the defined type, ROBOT, in the function's argument section.

info returns nothing, hence the void data type, and expects a ROBOT variable. r is a local variable that is created whenever info is called.

The %0.1f format specifier in the second printf displays the velocity correct to 1 decimal place. The zero is the minimum field width (the least number of spaces the number will occupy when displayed on screen).



Prev:
Next:

Copyright © 2001-2003
Unauthorized copying not permitted

Designed and Developed Using



===========================================================================

Structs Part 3

Prev:
Next:



Passing Pointers to Structures to Functions

Now suppose we want to create a function that modifies a structure. Now we'll turn to pointers...

#include 

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
int IQ;
float velocity;
};

void info(ROBOT r); /* declare functions */
void harm(ROBOT *r);

int main() {
ROBOT r1 = {"Martian Martin", 140, 213, 5.1};
ROBOT r2 = {"Planetary Pete", 170, 309, 4.5};

ROBOT *ptr_r1 = &r1;

printf("Before damage: \n\n");

info(r1);
info(r2);

harm(ptr_r1);
harm(&r2);

printf("\nAfter damage: \n\n");

info(r1);
info(r2);

return 0;
}

void info(ROBOT r) {
printf("%s: Energy: %d IQ: %d ", r.name, r.energy, r.IQ);
printf("Velocity: %0.1f\n", r.velocity);
}

void harm(ROBOT *r) {
r->energy -= 20;
r->velocity -= 1;
}

Output:

Before damage:

Martian Martin: Energy: 140 IQ: 213 Velocity: 5.1
Planetary Pete: Energy: 170 IQ: 309 Velocity: 4.5

After damage:

Martian Martin: Energy: 120 IQ: 213 Velocity: 4.1
Planetary Pete: Energy: 150 IQ: 309 Velocity: 3.5

I would like to take this opportunity to apologize for the unimaginative names!!!

The info function is almost the same as before - just modified the way it displayed the information. I had to use two separate printfs because using one distorted the web page!

harm expects a ROBOT pointer as an argument. Then it takes the ROBOT passed in, and decreases its energy by 20, and its velocity by 1 (that should teach it a lesson).

You can see by the output that the fields have been modified when I called harm using the two different methods: passing a pointer to r1 I created earlier, or simply passing the address of r2.



Structures Within Structures

You can have fields of any data type in a structure, as well as pointers and arrays AND other structures.

You must create a struct before you use it in another struct, but declaring the field is similar to declaring an array.

#include 

typedef struct weapon WEAPON;
typedef struct robot ROBOT;

struct weapon {
int ammo;
char *name;
int damage;
};

struct robot {
WEAPON weapon1; /* struct within a struct */
char *name;
int energy;
};

int main() {
ROBOT boss = { {100, /* boss.weapon1.ammo */
"Laser Gun", /* boss.weapon1.name */
25}, /* boss.weapon1.damage */
"Krypton Kathy", /* boss.name */
250}; /* boss.energy */

ROBOT *ptr1;
WEAPON *ptr2;

/*boss.weapon1.ammo = 100; alternative initialization -
notice I had to put:
boss.weapon1.name = "Laser Gun";

this is AFTER declaring the 2 pointers above
boss.weapon1.damage = 25;
boss.name = "Krypton Kathy";
boss.energy = 250;*/


ptr1 = &boss;
ptr2 = &boss.weapon1;

printf("You have encountered %s.\n", ptr1->name);
printf("She has %d units of energy.\n", ptr1->energy);
printf("Her weapon is the deadly %s.\n", ptr2->name);
printf("Each hit takes up to %d units of energy off you.\n",
ptr2->damage);
printf("She has %d shots left.\n", ptr1->weapon1.ammo);
printf("You have 10 units of energy left. ");
printf("Situation critical.\n Abort mission.\n");

return 0;
}

Output:

You have encountered Krypton Kathy.
She has 250 units of energy.
Her weapon is the deadly Laser Gun.
Each hit takes up to 25 units of energy off you.
She has 100 shots left.
You have 10 units of energy left. Situation critical.
Abort mission.

In the definition of struct robot, you can see that I've used a struct weapon variable as one of the fields. struct weapon must been defined before struct robot, otherwise your compiler will complain about an undefined struct.

Inside main, I've declared and initialized a ROBOT variable. Look closely and you'll see that there are 2 brackets surrounding the first three items - this is because the first three items belong to the struct weapon field.

After that, I declared two pointers - one that points to the boss and the other points to the weapon1 field of boss.

The first four printf statements make use of ptr1 and ptr2 to access certain fields, but in the fifth, notice that it's ptr1->weapon1.ammo and not ptr1->weapon1->ammo. This is because weapon1 is not a pointer to a struct weapon, but an actual struct weapon field, hence the dot operator.



Prev:
Next:

Copyright © 2001-2003
Unauthorized copying not permitted

Designed and Developed Using


===========================================================================
from:


There are several ways by which a structure can be initialized. In the first way, we first declare the structure variable and initialize the fields of the structure with its name along with the variable name.
i.e., Suppose consider a structure ‘student

structure student {

int roll;

int class;

char name;

};

Now we declare variable for the structure student st1
Now to initialize this variable, we access the elements of the structure using the variable
i.e.,

      st1.roll  = 21;

strncpy (st1.name, "Albert", 10);

There can be case in which we do not initialize some elements of the structure, like in the above case, we did not initialize the element class for the variable st1. This can be considered as a big disadvantage. Because we may forget initializing some fields.

In the second way, we initialize the structure elements using the set notation.
like the variable st2 can be initialized as

     struct student st2 = {22, 10, "Alan"};

Unlike the first way, where we can initialize the elements of the structure in any order, here we must remember the order of the elements in the structure. But chances of not initializing a particular element is very less.

The following program demonstrates these two ways of structure initialization. Also check the way an array of structures is initialized.

/*Different Ways of structure initialization*/#include &lt;stdio.h>

#include &lt;string.h>

#define NAME_LEN 25

typedef unsigned short age_t;

typedef unsigned int roll_t;

typedef struct student{

char name[NAME_LEN];

roll_t rno;

age_t age;

}student;

int main()

{

/*

* Method 1a:Commonly seen initialization of a structure
    */student st;strcpy(st.name,"Albert");

    st.age=23;

    st.rno=1034;


printf("%s %hi %u\n\n",st.name,st.age,st.rno);

/*

* Method 1b: For initialing an array of structures

*Commonly seen initialization of a structure

*/
    student st1 [2];strcpy(st1[0].name,"Albert");st1[0].age=23;

    st1[0].rno=1034;


strcpy(st1[1].name,"Alvin");

st1[1].age=24;

st1[1].rno=1035;

printf("%s %hi %u\n%s %hi %u\n\n",st1[0].name,st1[0].age,

st1[0].rno,st1[1].name,st1[1].age,st1[1].rno);

/*

* Method 2a:Initializing like a set, the only requirement is

* that the order by which these elements are entered

* should be as in the declaration

*/
    student st2={"Alvin",1035,22};printf("%s %hi %u\n\n",st2.name,st2.age,st2.rno);


/*

* Method 2b: For Initializing an array of structures

*/
    student st2b[2]={ {"Alan",1036,23}, {"Eric",1037,22}};


printf("%s %hi %u\n%s %hi %u\n\n",st2b[0].name,st2b[0].age,

st2b[0].rno, st2b[1].name,st2b[1].age,st2b[1].rno);

}



--------------------------------------------------------------------------

Possibly related posts: (automatically generated)

« »
--------------------------------------------------------------------------

One Response to “C: Structure Initialization”

[...] structures. These way utilizes the benefits of both the ways of structure initialization described here. That is we are able to initialize the elements of the structure using the set notation and also we [...]

===========================================================================
from:


There is one more way by which we can initialize structures. These way utilizes the benefits of both the ways of structure initialization described . That is we are able to initialize the elements of the structure using the set notation and also we need not remember the order of the elements of the structure.

Suppose consider the structure ‘student‘ we already used

struct student {

int roll;

int class;

char name;

};

Now let’s declare a variable st3 and initialize using the third method

student st3={

.name = "Mark", //Notice the equal to and the comma

.class = 10,

.roll = 1038

};

As you can see the way by which the variable st3 has been initialized. It has used the set notation and also see the order is not the same as in the case of the structure ‘student


The following program demonstrates this. Note the different ways by which the array of structures has been initialized

/*

*Different Ways of structure initialization

*/#include &lt;stdio.h>

#include &lt;string.h>

#define NAME_LEN 25

typedef unsigned short age_t;

typedef unsigned int roll_t;

typedef struct student{

char name[NAME_LEN];

roll_t rno;

age_t age;

}student;

int main()

{

/* Method 3a: Just like the Method 2a, but here you do not

* need to know order of the elements in the declaration

*/

student st3={

.name = "Mark",//Notice the equal to and comma

.age = 23,
.rno = 1038
};

printf("%s %hi %u\n\n",st3.name,st3.age,st3.rno);

/*

* Method 3b: For Initializing an array of structures

*/

student st4[]={
{

.name = "Neil",

.age = 23,

.rno = 1039 },

{

.name = "Peter",

.age = 23,

.rno = 1040

}
};

printf("%s %hi %u\n%s %hi %u\n\n",st4[0].name,st4[0].age,

st4[0].rno, st4[1].name,st4[1].age,st4[1].rno);

/*

* Method 3c : Change the order of initialization of the

* elements of the array. Normally as seen in Method 2b,

* the 0th array element is initialized then 1st, then

* 2nd and so on. So by using a variation of Method 3b,

* we can initialize the array elements in any order

*/

student st5[5]={

[3]={

.name = "Titus",

.age = 22,

.rno = 1041 },

[2]={

.name = "Stephen",

.age = 23,

.rno = 1042

}

/*As you can see only 2nd and 3rd array elements has

* been initialized and that too not in order. Such

* an initialization is useful, if we wish to allocate

* some fixed size array but only initialize some element

*/
};

printf("%s %hi %u\n%s %hi %u\n\n",st5[2].name,st5[2].age,

st5[2].rno, st5[3].name,st5[3].age,st5[3].rno);


}
The Methods 3a, 3b and 3c are the ways of structure initialization that I have seen in the kernel code. If you find any other way to do the structure initialization, kindly comment.

------------------------------------------------------------------------------------------

Possibly related posts: (automatically generated)

------------------------------------------------------------------------------------------
« »
------------------------------------------------------------------------------------------

4 Responses to “C: Structure Initialization (Advanced)”

  1. Just a note that this is NOT C++ compatible (it’s part of C99). Confirmed with gcc C++ 4.1.2 and Microsoft Visual Studio 2008 C++.

    Is there anything else that is “C only”? Kinda bugs me, being a C++ guy. :P

  2. Just check this : . This is completely C based. Hope this will help you.

  3. Yep, those are the older ways to get the job done.

    The new “set notation” way you explained here is nice though. Wish it were in C++ too. I was surprised by it because I thought C was strictly a subset of C++. Set notation proves that statement wrong. Thanks for the post about it.

  4. I saw this utilization when I referred to the Linux Kernel. I thought this would be useful to share. If you have any suggestions, feel free to give any comment

------------------------------------------------------------------------------------------
from:

Structures

  • A structure in C is a collection of items of different types. You can think of a structure as a "record" is in Pascal or a class in Java without methods.
  • Structures, or structs, are very useful in creating data structures larger and more complex than the ones we have discussed so far. We will take a cursory look at some more complex ones in the next section.

Structures :: Declaration and Syntax

  • So how is a structure declared and initialized? Let's look at an example:
      struct student {
    char *first;
    char *last;
    char SSN[9];
    float gpa;
    char **classes;
    };

    struct student student_a, student_b;
    Another way to declare the same thing is:
      struct {
    char *first;
    char *last;
    char SSN[10];
    float gpa;
    char **classes;
    } student_a, student_b;
    As you can see, the tag immediately after struct is optional. But in the second case, if you wanted to declare another struct later, you couldn't.
  • The "better" method of initializing structs is:
      struct student_t {
    char *first;
    char *last;
    char SSN[10];
    float gpa;
    char **classes;
    } student, *pstudent;
    Now we have created a student_t student and a student_t pointer. The pointer allows us greater flexibility (e.g. Create lists of students).
  • How do you go about initializing a struct? You could do it just like an array initialization. But be careful, you can't initialize this struct at declaration time because of the pointers.
  • But how do we access fields inside of the structure? C has a special operator for this called "member of" operator denoted by . (period). For example, to assign the SSN of student_a:
      strcpy(student_a.SSN, "111223333\0");

Structures :: Pointers to Structs

  • Sometimes it is useful to assign pointers to structures (this will be evident in the next section with self-referential structures). Declaring pointers to structures is basically the same as declaring a normal pointer:
      struct student *student_a;
    But how do we dereference the pointer to the struct and its fields? You can do it in one of two ways, the first way is:
      printf("%s\n", (*student_a).SSN);
    This would get the SSN in student_a. Messy and the readability is horrible! Is there a better way? Of course, programmers are lazy! :)
  • To dereference, you can use the infix operator: ->. The above example using the new operator:
      printf("%s\n", student_a->SSN);
  • If we malloc'd space for the structure for *student_a could we start assigning things to pointer fields inside the structure? No. You must malloc space for each individual pointer within the structure that is being pointed to.

Structures :: typedef

  • There is an easier way to define structs or you could "alias" types you create. For example:
      typedef struct {
    char *first;
    char *last;
    char SSN[9];
    float gpa;
    char **classes;
    } student;

    student student_a;
    Now we get rid of those silly struct tags. You can use typedef for non-structs:
      typedef long int *pint32;

    pint32 x, y, z;
    x, y and z are all pointers to long ints. typedef is your friend. Use it.

Structures :: Unions

  • Unions are declared in the same fashion as structs, but have a fundamental difference. Only one item within the union can be used at any time, because the memory allocated for each item inside the union is in a shared memory location. Why you ask? An example first:
      struct conditions {
    float temp;
    union feels_like {
    float wind_chill;
    float heat_index;
    }
    } today;
    As you know, wind_chill is only calculated when it is "cold" and heat_index when it is "hot". There is no need for both. So when you specify the temp in today, feels_like only has one value, either a float for wind_chill or a float for heat_index.
  • Types inside of unions are unrestricted, you can even use structs within unions.

Structures :: Enumerated Types

  • What if you wanted a series of constants without creating a new type? Enter enumerated types. Say you wanted an "array" of months in a year:
      enum e_months {JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
    typedef enum e_months month;

    month currentmonth;
    currentmonth = JUN; /* same as currentmonth = 6; */
    printf("%d\n", currentmonth);
    We are enumerating the months in a year into a type called month. You aren't creating a type, because enumerated types are simply integers. Thus the printf statement uses %d, not %s.
  • If you notice the first month, JAN=1 tells C to make the enumeration start at 1 instead of 0.
  • Note: This would be almost the same as using:
    #define JAN 1
    #define FEB 2
    #define MAR 3
    /* ... etc ... */

Structures :: Abilities and Limitations

  • You can create arrays of structs.
  • Structs can be copied or assigned.
  • The & operator may be used with structs to show addresses.
  • Structs can be passed into functions. Structs can also be returned from functions.
  • Structs cannot be compared!

Structures Review

  • Structures can store non-homogenous data types into a single collection, much like an array does for common data (except it isn't accessed in the same manner).
  • Pointers to structs have a special infix operator: -> for dereferencing the pointer.
  • typedef can help you clear your code up and can help save some keystrokes.
  • Enumerated types allow you to have a series of constants much like a series of #define statements.

===========================================================================


===========================================================================


===========================================================================


阅读(1051) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~