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