Transcript Document

Structured Data Types
• A structure can be used to combine data of different
types into a single (compound) data value.
• Like all data types, structures must be declared and
defined.
• C has three different ways to define a structure
– variable structures
– tagged structures
– type-defined structures
1
Structured Data Types
A variable structure definition defines a struct variable.
struct
{
unsigned char red;
unsigned char green;
unsigned char blue;
} pixel;
variable name
Members
DON’T FORGET THE SEMICOLON
2
Structured Data Types
A tagged structure definition defines a type. We can use
the tag to define variables, parameters, and return types.
struct point_t
{
double x;
double y;
};
structure tag
Member names
DON’T FORGET THE SEMICOLON
To Use: struct point_t point1, point2;
3
Structured Data Types
• Example 2 (tagged structure definition)
struct pixel_t
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
Structure tag
Members
DON’T FORGET THE SEMICOLON
To Use: struct pixel_t pixel;
4
Structured Data Types
• A typed-defined structure is the most powerful way to
declare a structure. We can use the tag to define
variables, parameters, and return types.
typedef struct pixel_type
{
unsigned char red;
unsigned char green;
unsigned char blue;
} pixel_t;
New type name
• To declare a variable of the new type, use:
pixel_t pixel;
5
Structured Data Types
Example 2 (typed-defined structure)
typedef struct pointType
{
double x;
double y;
} point_t;
New type name
To declare variables of the type, use:
point_t point1;
point_t point2;
These structure variable definitions create member variables x and y
associated with the structure.
6
Structured data types
• Member variables of a struct are accessed using the dot
operator.
pixel1.red = 200;
pixel1.green = 200;
pixel1.blue = 0;
point1.x = 10.0;
point1.y = 5.5;
// type is double
// type is double
• These variables may be used exactly like any other
variables.
7
Example
typedef struct student_type
{
int id;
char grade;
} student_t;
int main( )
{
student_t student;
student.id = 2201;
student.grade = ‘A’;
fprintf(stdout, “id: %d, grade: %c\n”,
student.id, student.grade);
return 0;
}
8
Initializing Structures
• At declaration time, members of a struct can be initialized
in a manner similar to initializing array elements.
pixel_t pixel = {255, 0, 100};
• The sequence of values is used to initialize the successive
variables in the struct. The order is essential.
• It is an error to have more initializers than variables.
• If there are fewer initializers than variables, the initializers
provided are used to initialize the data members. The
remainder are initialized to 0 for primitive types.
9
Use of sizeof() with structures
• The sizeof() operator should always be used in dynamic
allocation of storage for structured data types and in
reading and writing structured data types. However, it is
somewhat easy to do this incorrectly.
10
Structures as parameters to functions
• A struct, like an int, may be passed to a function.
• The process works just like passing an int, in that:
– The complete structure is copied to the stack
– The function is unable to modify the caller's copy of
the variable
11
Structures as parameters to functions
#include <stdio.h>
typedef struct s_type
{
int a;
double b;
} sample_t;
void funct(sample_t x)
{
fprintf(stdout, "x.a = %d\n", x.a);
fprintf(stdout, "x.b= %lf\n", x.b);
x.a = 1000;
x.b = 55.5;
}
int main() {
sample_t y;
y.a = 99;
y.b = 11.5;
funct(y);
fprintf(stdout, "y.a = %d\n", y.a);
fprintf(stdout, "y.b = %lf\n", y.b);
return 0;
}
12
Structures as parameters to functions
Sample Run:
[11:26:47] rlowe:~ [142] ./a.out
x.a = 99
x.b= 11.500000
y.a = 99
y.b = 11.500000
13
Structures as parameters to functions
• The disadvantages of passing structures by value are
that copying large structures onto the stack
– is very inefficient and
– may even cause program failure due to stack
overflow.
typedef struct
{
int w[1024 * 1024];
} sample_t;
/* passing a struct of type sampleType above will cause */
/* 4 Terabytes to be copied onto the stack.
*/
sample_t fourMB;
for(i = 0; i < 1000000; i++)
{
slow_call(fourMB);
}
14
Passing the address of a struct
• A more efficient way is to pass the address of the struct.
• Passing an address requires that only a single word be
pushed on the stack, regardless of how large the
structure is.
• Furthermore, the called function can then modify the
structure.
15
Passing the address of a struct
#include <stdio.h>
typedef struct {
int a;
double b;
} sample_t;
/* Use the * operator. funct modifies the struct */
void funct (sample_t *x) {
fprintf(stdout, "x->a = %d\n", x->a);
// note the
use of -> operator
fprintf(stdout, "x->b = %lf\n", x->b);
x->a = 1000;
x->b = 55.5;
}
int main()
{
sample_t y;
y.a = 99;
y.b = 11.5;
/* use the address operator, &, in the call */
funct(&y);
fprintf(stdout, "y.a = %d\n", y.a);
fprintf(stdout, "y.b = %lf\n", y.b);
return 0;
}
16
Passing the address of a struct
Sample run:
[11:39:29] rlowe:~ [169] ./a.out
x->a = 99
x->b = 11.500000
y.a = 1000
y.b = 55.500000
17
Passing the address of a struct
• What if you do not want the recipient to be able to
modify the structure?
• In the prototype and function header, use the *
operator.
– Use the const modifier
void funct(const sample_t *x) ;
18
Using the const modifier
#include <stdio.h>
typedef struct s_type
{
int a;
double b;
} sample_t;
void funct(const sample_t *x) {
fprintf(stdout, "x.a = %d\n", x->a);
fprintf(stdout, "x.b = %d\n", x->a);
x->a = 1000;
x->b = 55.5;
}
int main( ) {
sample_t y;
y.a = 99;
y.b = 11.5;
/* to pass the address use the & operator */
funct(&y);
fprintf(stdout, "y.a = %d\n", y.a);
fprintf(stdout, "y.b = %d\n", y.b);
return 0;
}
– The above code will generate a compile-time error.
19
Using the const modifier
•
•
•
•
[11:34:04] rlowe:~ [147] gcc struc5.c
struc5.c: In function 'funct':
struc5.c:12: error: assignment of read-only location
struc5.c:13: error: assignment of read-only location
20
Arrays within structures
An element of a structure may be an array
typedef struct
{
char name[25];
double payRate;
int hoursWorked[7];
} timeCard_type;
timeCard_type myTime;
Elements of the array are accessed in the usual way:
myTime.hoursWorked[5] = 6;
21
Arrays of structures
• We can also create an array of structure types:
pixel_t pixelMap[400 * 300];
student_t roster[125];
• To access an individual element of the array,
pixelMap[20].red = 250;
roster[50].gpa = 3.75;
22
Arrays of structures containing arrays
• We can also create an array of structures that contain
arrays
timeCard_type employees[50];
• To access an individual element
employees[10].hoursWorked[3] = 10;
23
Structures containing structures
• It is common for structures to contain elements which
are themselves structures or arrays of structures. In
these cases, the structure definitions should apear in
"inside-out" order.
• This is done to comply with te usual rule of not
referencing a name before it is defined.
24
Structures containing structures
typedef struct {
unsigned char red;
unsigned char green;
unsigned char blue;
} pixel_t;
typedef struct {
int numRows;
int numCols;
pixel_t pixelData[400 * 300];
} image_t;
25
Structures as return values from functions
• Scalar values (int, float, etc) are efficiently returned in
CPU registers.
• Historically, the structure assignments and the return of
structures was not supported in C.
• But, the return of pointers (addresses), including
pointers to structures, has always been supported.
26
Structures as return values from functions
typedef struct {
int a;
double b;
} sampleType;
sample_t *funct ( ) {
sample_t s;
s->a = 1000;
s->b = 55.5;
return (&s);
}
int main() {
sample_t *y;
y = funct( );
fprintf(stdout, "y->a = %d\n", y->a);
return 0;
}
rlowe@hornet7 [160] ./a.out
returnParam.c: In function 'funct':
returnParam.c:8: warning: function returns address of local variable
27
Structures as return values from functions
• The reason for the warning is that the function is
returning a pointer to a variable that was allocated
on the stack during execution of the function.
• Such variables are subject to being wiped out by
subsequent function calls.
28
Structures as return values from functions
• It is possible for a function to return a structure.
• This facility depends upon the structure assignment
mechanisms which copies one complete structure to
another.
– This avoids the unsafe condition associated with
returning a pointer, but
– incurs the possibly extreme penalty of copying a
very large structure
29
Structures as return values from functions
#include <stdio.h>
typedef struct
int a;
double b;
} sample_t;
s_type
{
sample_t funct ( ) {
sample_t s;
s.a = 1000;
s.b = 55.5;
return s;
}
int main() {
sample_t y;
sample_t z;
y = funct();
z = y;
printf("%d %d\n", y.a, z.a);
return 0;
}
[11:51:51] lowerm@spider3:~ [184] ./a.out
1000 1000
30
Summary
• Passing/returning instances of structures potentially
incurs big overhead.
• Passing/returning addresses incurs almost no overhead
• Accidental modifications can be prevented with const
– Therefore, it is recommended that, in general, you
never pass nor return an instance of a structure
unless you have a very good reason for doing so.
• This problem does not arise with arrays.
– The only way to pass an array by value in the C
language is to embed it in a structure
– The only way to return an array is to embed it in a
structure.
31