영어로 읽는 코딩

38 [C] 구조체와 함수

Structures and Functions (구조체와 함수)

 

The only legal operations on a structure are copying it or assigning to it as a unit, taking its address with &, and accessing its members. Copy and assignment include passing arguments to functions and returning values from functions as well. Structures may not be compared. A structure may be initialized by a list of constant member values; an automatic structure may also be initialized by an assignment.

Let us investigate structures by writing some functions to manipulate points and rectangles. There are at least three possible approaches: pass components separately, pass an entire structure, or pass a pointer to it. Each has its good points and bad points.

The first function, makepoint, will take two integers and return a point structure:

/* makepoint: make a point from x and y components */

struct point makepoint(int x, int y)

{

struct point temp;

 

temp.x = x;

temp.y = y;

return temp;

}

Notice that there is no conflict between the argument name and the member with the same name; indeed the re-use of the names stresses the relationship.

makepoint can now be used to initialize any structure dynamically, or to provide structure arguments to a function:

struct rect screen;

struct point middle;

struct point makepoint ( int, int) ;

 

screen.pt1 = makepoint (0, 0);

screen.pt2 = makepoint(XMAX, YMAX);

middle = makepoint((screen.pt1.x + screen.pt2.x)/2, (screen.pt1.y + screen.pt2.y)/2);

The next step is a set of functions to do arithmetic on points. For instance,

/* addpoint: add two points */

struct point addpoint(struct point p1, struct point p2)

{

p1.x + = p2.x;

p1.y += p2.y;

return p1;

}

Here both the arguments and the return value are structures. We incremented the components in p 1 rather than using an explicit temporary variable to emphasize that structure parameters are passed by value like any others.

As another example, the function ptinrect tests whether a point is inside a rectangle, where we have adopted the convention that a rectangle includes its left and bottom sides but not its top and right sides:

/* ptinrect: return 1 if p in r, 0 if not */

int ptinrect(struct point p, struct rect r)

{

return p.x >= r.pt1.x && p.x < r.pt2.x

&& p.y >= r.pt1.y && p.y < r.pt2.y;

}

This assumes that the rectangle is represented in a standard form where the pt 1 coordinates are less than the pt2 coordinates. The following function returns a rectangle guaranteed to be in canonical form:

#define min(a, b) ((a) < (b) ? (a) : (b))

#define max(a, b) ((a) > (b) ? (a) : (b))

/* canonrect: canonicalize coordinates of rectangle */

struct rect canonrect(struct rect r)

{

struct rect temp;

temp.pt1.x = min(r.pt1.x, r.pt2.x) ;

temp.pt1.y = min(r.pt1.y, r.pt2.y) ;

temp.pt2.x = max(r.pt1.x, r.pt2.x);

temp.pt2.y = max(r.pt1.y, r.pt2.y);

return temp;

}

 

If a large structure is to be passed to a function, it is generally more efficient to pass a pointer than to copy the whole structure. Structure pointers are just like pointers to ordinary variables. The declaration

struct point *pp;

says that pp is a pointer to a structure of type struct point. If pp points to a point structure, *PP is the structure, and (*PP). x and (*PP). y are the members. To use pp, we might write, for example,

struct point origin, *PP;

pp = &origin;

printf( ”origin is (%d,%d)\n” ' (*pp).x, (*pp).y);

The parentheses are necessary in (*pp).x because the precedence of the structure

member operator . is higher than *. The expression *PP. x means *(pp. x), which is illegal here because x is not a pointer.

Pointers to structures are so frequently used that an alternative notation is provided as a shorthand. If p is a pointer to a structure, then

p->member-of-structure

refers to the particular member. (The operator -> is a minus sign immediately followed by >.) So we could write instead

printf(”origin is (%d,%d)\n”, pp->x, pp->y);

Both . and -> associate from left to right, so if we have

struct rect r, *rp = &r;

then these four expressions are equivalent:

r.pt1.x

rp->pt1. x

(r.pt1). x

(rp->pt1) .x

The structure operators . and ->, together with ( ) for function calls and [ ] for subscripts, are at the top of the precedence hierarchy and thus bind very tightly. For example, given the declaration

struct {

int len;

char *str;

} *p;

then

++p->len

increments len, not p, because the implied parenthesization is ++(p->len). Parentheses can be used to alter the binding: (++p)->len increments p before accessing len, and (p++) -> len increments p afterward. (This last set of parentheses is unnecessary.)

In the same way, *P->str fetches whatever str points to; *P->str++ increments str after accessing whatever it points to (just like *s++); (*p->str)++increments whatever str points to; and *p++->str increments p after accessing whatever str points to.

 

 

[The C Programming Language p.129-132]

댓글

댓글 본문
버전 관리
Yoo Moon Il
현재 버전
선택 버전
graphittie 자세히 보기