Computer Systems Organization

Start Lecture #7

  ip = &x;
  *ip = *ip + 10;
  y = *ip + 1;
  *ip += 1;
  ++*ip;
  (*ip)++;
  *ip++;

The first line on the right re-establishes ip as a pointer to x so the second line increments x by 10 and the next line sets y=x+1;.

The next line increments x by 1 as does the following line (because the unary operators ++ and * are right associative).

The next line also increments x, but the last line does not. By right associativity we see that the increment precedes the dereference, but the full story awaits section 5.4 below.

5.2: Pointers and Function Arguments

  void bad_swap(int x, int y) {
    int temp;
    temp = x;
    x = y;
    y = temp;
  }

The program on the right is what a FORTRAN programer just learning C (or Java) would write. It is supposed to swap its two arguments but fails due to call by value semantics for function calls in C. That is, when a user writes swap(A,B) the values of A and B are transmitted, A and B are not changed.

But programs that change their arguments are useful!

Actually, what is useful is to be able to change the value of variables used in the arguments and that distinction is the key. Just because we want to swap the values of A and B, doesn't mean the arguments have to be exactly A and B.

  void swap(int *px, int *py) {
    int temp;
    temp = *px;
    *px = *py;
    *py = temp;
  }

The program on the right has two parameters x and y each of which is a pointer to an integer (*px and *py are the integers). Since C is a call-by-value language, changes to the parameters, which are the pointers x and y would not result in changes to the corresponding arguments. But the program on the right doesn't change the pointers at all, just the values that they point to.

Since the parameters are pointers to integers, so must be the arguments. A typical call to this function would be swap(&A,&B).

swap

Understanding how this call results in A receiving the value previously in B and B receiving the value previously in A is very important.

On the right is pictorial explanation from the book. A has a certain address. The call swap(&A,&B) places the address of A into the first parameter, which is px. Thus the value of px is the address of A, which is indicated by the arrow. Similarly for B and py.

Homework: Write rotate3(A,B,C) that sets A to the old value of B, sets B to old C, and C to old A.

Homework: Write plusminus(x,y) that sets x to old x + old y and sets y to old x - old y.

5.2A: A Larger Example—getch(), ungetch(), and getint()

#include <stdio.h>
#define BUFSIZE 100
char buf[BUFSIZE];
int  bufp = 0;
int getch(void) {
  return (bufp>0) ? buf[--bufp] : getchar();
}
void ungetch(int c) {
  if (bufp >= BUFSIZE)
    printf("ungetch: too many chars\n");
  else
    buf[bufp++] = c;
}

#include <stdio.h> #include <ctype.h> int getch(void); void ungetch(int); int getint(int *pn) { int c, sign; while (isspace(c=getch())) ; if (!isdigit(c) && c!=EOF && c!='+' && c!='-') { ungetch(c); return 0; } sign = (c=='-') ? -1 : 1; if (c=='+' || c=='-') c = getch(); for (*pn = 0; isdigit(c); c=getch()) *pn = 10 * *pn + (c-'0'); *pn *= sign; if (c != EOF) ungetch(c); return c; }

The program pair getch() and ungetch generalize getchar() by supporting the notion of unreading a character, i.e., having the effect of pushing back several already read characters.

Also shown is getint(), which reads an integer from standard input (stdin) using getch() and ungetch().

getint() returns the integer as a parameter (using a pointer of course). The value of the function itself gives the status, zero means the next characters do not form an integer, EOF (which is negative) means end of file, positive means an integer has been found. The idea is

    Skip blanks
    Check for legality
    Determine sign
    Evaluate number
      one digit at a time
  

Note some corner cases

If, in real life, you were asked to produce a getint() function you would have three tasks.

  1. Write, in precise English, what is to happen in all cases.
  2. Write a C program implementing this specification.
  3. Get the C syntax right.
The third is clearly the easiest task. I suspect that the first is the hardest.

5.3: Pointers and Arrays

In C pointers and arrays are closely related. As the book says

Any operation that can be achieved by array subscripting can also be done with pointers.
The authors go on to say
The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.
The second clause is doubtless correct; but perhaps not the first. Remember that the 2e was written in 1988 (1e in 1978). Compilers have improved considerably in the past 20+ years and, I suspect, would turn out equally fast code for many of the subscripted versions.

int a[5], *pa
int i, x;
pa = &a[0];

x = *pa; x = *(pa+1); x = a[0]; x = *a; x = a[i]; x = *(a+i);

array-ptr

On the far right we see some code involving pointers and arrays. After the first three lines are executed we get the diagram shown. pa is a pointer to the first element of the array a.

The next line sets x=a[0]; the line after that sets x=a[1].

Then we explicitly set x=a[0];; the line after that has the same effect! That is because in C a has the same value as &a[0].

Similarly, the next two lines form a pair having the same effect.

Array Name vs Pointer to First Element

int mystrlen(char *s) {
  int n;
  for (n=0; *s!='\0'; s++,n++);
  return n;
}

char str[50], *pc; // calculate str and pc mystrlen(pc); mystrlen(str); mystrlen("Hello, world.");

The code on the right shows how well the C pointers, arrays, and strings mesh. What a tiny program to find the length!

Also note the ways it can be called: The first call shown exactly matches the function declaration. The second matches as well, when we remember that an array name has the same value as a pointer to the first value. Finally, the third is like the second since a string is a character array.