Structures, Unions, and Enumerations |
Q.1 |
What’s the difference between these two declarations? |
struct x1 { ... }; |
typedef struct { ... } x2; |
Ans: |
The first form declares a ‘structure tag’; the second declares a ‘typedef’. The main |
difference is that you subsequently refer to the first type as struct x1 and the second |
simply as x2.That is, the second declaration is of a slightly more abstract type-its |
users don’t necessarily know that it is a structure, and the keyword struct is not used |
when declaring instances of it. |
Q.2 |
Why doesn’t the following code work? |
struct x { ... }; |
x thestruct; |
Ans: |
C is not C++. Typedef names are not automatically generated for structure tags. |
Q.3 |
Can a structure contain a pointer to itself? |
Ans: |
Most certainly. |
Q4 |
What’s the best way of implementing opaque (abstract) data types in C? |
Ans: |
One good way is for clients to use structure pointers (perhaps additionally hidden |
behind typedefs) which point to structure types which are not publicly defined. |
Q.5 |
I came across some code that declared a structure like this: |
struct name { |
int namelen; |
char namestr[1]; |
}; |
and then did some tricky allocation to make the namestr array act like it had several |
elements. Is this legal or portable? |
Ans: |
This technique is popular, although Dennis Ritchie has called it ‘unwarranted |
chumminess with the C implementation’. An official interpretation has deemed that |
it is not strictly conforming to the C Standard, although it does seem to work under |
all known implementations. (Compilers which check array bounds carefully might |
issue warnings.) Another possibility is to declare the variable-size element very |
large, rather than very small; in the case of the above example: |
... |
char namestr[MAXSIZE]; |
where MAXSIZE is larger than any name which will be stored. However, it looks |
like this technique is disallowed by a strict interpretation of the Standard as well. |
Furthermore, either of these ‘chummy’ structures must be used with care, since the |
programmer knows more about their size than the compiler does. (In particular, |
they can generally only be manipulated via pointers.)C9X will introduce the con- |
cept of a ‘flexible array member’, which will allow the size of an array to be omitted |
if it is the last member in a structure, thus providing a well-defined solution. |
Q.6 |
Is there a way to compare structures automatically? |
Ans: |
No. There is no single, good way for a compiler to implement implicit structure |
comparison (i.e., to support the == operator for structures) which is consistent with |
C’s low-level flavor. A simple byte-by-byte comparison could founder on random |
bits present in unused ‘holes’ in the structure (such padding is used to keep the |
alignment of later fields correct; A field-by-field comparison might require unac- |
ceptable amounts of repetitive code for large structures. If you need to compare two |
structures, you’ll have to write your own function to do so, field by field. |
Q.7 |
How can I pass constant values to functions which accept structure arguments? |
Ans: |
As of this writing, C has no way of generating anonymous structure values. You will |
have to use a temporary structure variable or a little structure-building function. The |
C9X Standard will introduce ‘compound literals’; one form of compound literal |
will allow structure constants. For example, to pass a constant coordinate pair to a |
plotpoint() function which expects a struct point, you will be able to call |
plotpoint((struct point){1, 2});Combined with ‘designated initializers’ (another |
C9X feature), it will also be possible to specify member values by |
name:plotpoint((struct point){.x=1, .y=2}); |
Q.8 |
How can I read/write structures from/to data files? |
Ans: |
It is relatively straightforward to write a structure usingfwrite():fwrite(&somestruct, |
sizeof somestruct, 1, fp); |
and a corresponding fread() invocation can read it back in. However, data files so |
written will *not* be portable. Note also that if the structure contains any pointers, |
only the pointer values will be written, and they are most unlikely to be valid when |
read back in. Finally, note that for widespread portability you must use the “b” flag |
when fopening() the files; |
A more portable solution, though it’s a bit more work initially, is to write a pair of |
functions for writing and reading a structure, field-by-field, in a portable (perhaps |
even human- readable) way. |
Q.9 |
My compiler is leaving holes in structures, which is wasting space and preventing |
‘binary’ I/O to external data files. Can I turn off the padding, or otherwise control |
the alignment of structure fields? |
Ans: |
Your compiler may provide an extension to give you this control (perhaps a |
#pragma; but there is no standard method. |
Q.10 |
Why does sizeof() report a larger size than I expect for a structure type, as if there |
were padding at the end? |
Ans: |
Structures may have this padding (as well as internal padding), if necessary, to en- |
sure that alignment properties will be preserved when an array of contiguous struc- |
tures is allocated. Even when the structure is not part of an array, the end padding |
remains, so that sizeof() can always return a consistent size. |
Q.11 |
How can I determine the byte offset of a field within a structure? |
Ans: |
ANSI C defines the offsetof() macro, which should be used if available; see < |
stddef.h>. If you don’t have it, one possible implementation is #define offsetof(type, |
mem) ((size_t) \ ((char *)&((type *)0) > mem - (char *)(type *)0))This implemen- |
tation is not 100% portable; some compilers may legitimately refuse to accept it. |
Q.12 |
How can I access structure fields by name at run time? |
Ans: |
Build a table of names and offsets, using the offsetof() macro. The offset of field b |
in struct a is |
offsetb = offsetof(struct a, b) |
If structp is a pointer to an instance of this structure, and field b is an int (with offset |
as computed above), b’s value can be set indirectly with |
*(int *)((char *)structp + offsetb) = value; |
Q.13 |
This program works correctly, but it dumps core after it finishes. Why? |
struct list { |
char *item; |
struct list *next; |
} |
/* Here is the main program. */ |
main(argc, argv) |
{ ... } |
Ans: |
A missing semicolon causes main() to be declared as returning a structure. (The |
connection is hard to see because of the intervening comment.) Since structure- |
valued functions are usually implemented by adding a hidden return pointer, the |
generated code for main() tries to accept three arguments, although only two are |
passed (in this case, by the C start-up code). |
Q.14 |
Can I initialize unions? |
Ans: |
The current C Standard allows an initializer for the first-named member of a union. |
C9X will introduce ‘designated initializers’ which can be used to initialize |
any member. |
Q.15 |
What is the difference between an enumeration and a set of preprocessor #defines? |
Ans: |
At the present time, there is little difference. The C Standard says that enumerations |
may be freely intermixed with other integral types, without errors. (If, on the other |
hand, such intermixing were disallowed without explicit casts, judicious use of enu- |
merations could catch certain programming errors.)Some advantages of enumera- |
tions are that the numeric values are automatically assigned, that a debugger may be |
able to display the symbolic values when enumeration variables are examined, and |
that they obey block scope. (A compiler may also generate non-fatal warnings when |
enumerations and integers are indiscriminately mixed, since doing so can still be |
considered bad style even though it is not strictly illegal.) A disadvantage is that the |
programmer has little control over those non-fatal warnings; some programmers |
also resent not having control over the sizes of enumeration variables. |
Q.16 |
Is there an easy way to print enumeration values symbolically? |
Ans: |
No. You can write a little function to map an enumeration constant to a string. (For |
debugging purposes, a good debugger should automatically print enumeration con- |
stants symbolically. |
Q.14. |
What is the output of this program? |
struct num |
{ |
int no; |
char name[25]; |
}; |
void main() |
{ |
struct num n1[]={{25,“rose”},{20,”gulmohar”},{8,“geranium”},{11,“dahalia”}}; |
printf(“%d%d” ,n1[2].no,(*&n1+2)->no+1); |
} |
Ans: |
8 9 |
Q15 |
. What is the output of this program? |
struct Foo |
{ |
char *pName; |
}; |
main() |
{ |
struct Foo *obj = malloc(sizeof(struct Foo)); |
clrscr(); |
strcpy(obj->pName,“Your Name”); |
printf(“%s”, obj->pName);}. |
Ans: |
Your Name |
Q16. |
What is the output of this program? |
struct Foo |
{ |
char *pName; |
char *pAddress; |
}; |
main() |
{ |
struct Foo *obj = malloc(sizeof(struct Foo));
clrscr(); |
obj->pName = malloc(100); |
obj->pAddress = malloc(100); |
strcpy(obj->pName,“Your Name”); |
strcpy(obj->pAddress, “Your Address”); |
free(obj); |
printf(“%s”, obj->pName); |
printf(“%s”, obj->pAddress); |
} |
Ans: |
printd Nothing, as after free(obj), no memory is there containing |
obj->pName & pbj->pAddress |
Q.17 |
What is the output of this program? |
main() |
{ |
char *a = “Hello ”; |
char *b = “World”; |
clrscr(); |
printf(“%s”, strcat(a,b)); |
} |
Ans: |
Hello World |
Q.18 |
What is the output of this program? |
main() |
{ |
char *a = “Hello”; |
char *b = “World”; |
clrscr(); |
printf(“%s”, strcpy(a,b)); |
} |
Ans: |
World, copies World on a, overwrites Hello in a. |
Q.19 |
What is the output of this program? |
union u |
{ |
struct st |
{ |
int i : 4; |
int j : 4; |
int k : 4; |
int l; |
}st; |
int i; |
}u; |
main() |
{ |
u.i = 100; |
printf(“%d, %d, %d”,u.i, u.st.i, u.st.l); |
} |
Ans: |
100, 4, 0 |
Q.20 |
What is the output of this program? |
union u |
{ |
union u |
{ |
int i; |
int j; |
}a[10]; |
int b[10]; |
}u; |
main() |
{ |
printf(“n%d”, sizeof(u)); |
printf(“ %d”, sizeof(u.a)); |
// printf(“%d”, sizeof(u.a[4].i)); |
} |
Ans: |
20, 200, error for 3rd printf() |
|
No comments:
Post a Comment