Comp111: Operating Systems
Classroom Exercise 6 Answers
Fall 2018

In class we have briefly discussed concepts and dangers inherent in pointers. Let's review some important concepts

  1. Consider the following code.
    int a[5]; int *p = a + 3; p[-2] = 20; 
    Draw a picture of memory after this code fragment, indicating contents of memory (and marking unknowns with ?'s).
    Answer: Please excuse the roughness of this text answer:
        a         +---+
        |         | | |
        |         +-+-+
        |           |
        V           V
      | ? | 20| ? | ? | ? |
        ^   ^   ^   ^   ^
        |   |   |   |   |
      a+0 a+1 a+2 a+3 a+4
      p-3 p-2 p-1 p   p+1
    The values are not initialized, so one cannot count on any value other than the ones that are set.
  2. Consider the following code:
    const char *c = "hello"; char d[20]; int i;
    for (i=4; i>=0; i--) d[4-i]=c[i]; 
    d[5]=0; /*here*/
    What does this print? What happens if we leave out the line marked /*here*/?
    Answer: It prints "olleh". If the statement is left out, the effect is that d is an undelimited string, so that printing will continue until a zero is encountered.

    Please note that 0 and '\0' are synonymous in C; both refer to the termination character for a string. C assignments are downcast to the type of the target with truncation. Thus

    char a = '\0'; 
    actually means
    char a = (char) '\0';
  3. Consider the following code:
    struct bar { int none; };
    void foo(void *v) { 
       struct bar *b = (struct bar *)v; 
       b[2].none = 1; b[4].none = 50; 
    main() { 
        void *d = (void *) malloc (5*sizeof(struct bar)); // the original had a '*'; sorry!
    1. Draw a picture of memory before the end of foo, identifying the values of d, b, and v and the memory to which they point. Indicate memory whose contents you don't know with '?'.
      Answer: Again, please excuse the rough graphics. A conceptual model (that ignores padding issues) would be as follows:
       |   |   | 1 |   |50 |
      All pointers point to the exact same place.

      If one does not ignore potential padding issues, there is the possibility that there is padding after the struct. However, ANSI standard layout for structs pads only so that the next address is aligned properly, so that there will be no padding in this case.

      This is exactly what happens when the operating system stores data for an extension. It does not try to embody the types for the extension, but instead provides untyped storage.

    2. Do "d+1" or "*d" mean anything? Why or why not?
      Answer: One cannot access nor add to a void pointer, because the void type has no length.
  4. Considering the declarations:
    struct foo { 
       int i; 
       struct foo *g; 
       const char *which; 
    } f, *h;
    Which of the following statements will compile?
    1. f.g=&f;
      Answer: It will compile, self-reference is allowed.
    2. f.which="ho there";
      Answer: It will compile; both sides are "const char *".
    3. h=&f;
      Answer: It will compile; both sides are "struct foo *".
    4. h=f.g;
      Answer: It will compile; both sides are "struct foo *".
    5. h=g.which;
      Answer: It will not compile; pointers are not type-conformal and there is no cast.
    6. h=(struct foo *)(g.which);
      Answer: This will compile, due to an explicit cast, even though it is meaningless.
  5. (Advanced) In an operating system, it is often the case that the operating system stores something as type void and then a subsystem remembers its type when manipulating it. Why would the operating system wish to avoid remembering the appropriate type?
    Answer: This allows the operating system to store data for many distinct subsystems in the same enveloping structures, thus utilizing a limited form of polymorphism. The module system is one example of this, and -- specifically -- the driver subsystem. There can be many modules described in the same array, even though modules differ drastically in purpose and function. If the data for every subsystem had to be declared explicitly, we would not be able to insert modules dynamically; we would have to recompile the whole operating system. This was in fact the reality until the modern system of information hiding took hold.