CSCI 255 Pointers and Arrays

Areas of memory

Running C and C++ programs are considered to have several segments or sections, distinct areas of memory.

Some compilers may place const variables in read-only segments. In some implementation each shared or dynamic-link library has its own segments for text and data. This allows several running programs to share common library routines.

Example C program using all areas

uint32_t Aglobal[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
const uint32_t Aconst[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
uint32_t Abss[10] ;

void subr(void) {
  uint32_t ASlocal[10] ;
  return ;
}

int main(int argc, char** argv) {
  uint32_t AMlocal[10] ;
  uint32_t *Amalloc ;
  Amalloc = (uint32_t *)malloc(10*sizeof(uint32_t)) ;
  subr() ;
  return (EXIT_SUCCESS);
}

Some address for those variables

Variable64-bit linux16-bit PIC
Aglobal0000000000600B000850
Aconst00000000004007A09072
Abss0000000000600B600878
Amalloc000000000089701009AE
AMlocal00007FFF09C89C8009F2
ASlocal00007FFF09C89C300A24
main00000000004005411204
subr000000000040051411EA
printf00000000004003F80459

Pointers

Example C functions using pointers

void swap(int *p, int *q) {
  int t = *p ;
  *p = *q ;
  *q = t ;
}
void sort(int *mn, int *mx) {
  if (*mn > *mx) {
    swap(&mn, &mx) ;
  }
}
char *firstLetter(char *msg) {
  while (*msg && !isalpha(*msg)) {
    ++msg ;
  }
  return msg ;
}
char *firstLetter(char *msg) {
  while (*msg && !isalpha(*msg++)) ;
  return msg ;
}

Example C++ functions using references

void swap(int &p, int &q) {
  int t = p ;
  p = q ;
  q = t ;
}
void sort(int &mn, int &mx) {
  if (mn > mx) {
    swap(mn, mx) ;
  }
}

Examples of implementing pointers on the PIC

       MOV     x,W2            ;; W2 <- x
       MOV     #x,W3           ;; W3 <- &x
       MOV     [W3],W2         ;; W2 <- *W3
       MOV     W5,[W3]         ;; *W3 <- W5
       MOV     [W6],[W7]       ;; *W7 <- *W6
       MOV     [W8++],[++W9]   ;; *++W9 <- *W8++

Arrays and pointers in C

In C, an array declaration defines a constant pointer to a sequence of data values. For example:
        int A[] = {2, 3, 5} ;
is really the same type as:
        int * const A = {2, 3, 5} ;
In neither case can A be assigned a value. However, A[4] can be modified. Incidentally, these declarations are not the same as:
        const int A[] = {2, 3, 5} ;
or
        const int * A = {2, 3, 5} ;
Neither of these declarations allow assignments to A[4] can be modified.

Finally, all you Java programmers should be warned that the following, while encouraged in Java, is forbidden in C:
        int[] A = {2, 3, 5} ;
In C the brackets must follow the variable name.

Pointer arithmetic in C

If p is the address of an integer in C, then p+i is the address of the i’th integer stored in memory after the place p points to. This interpretation means that p[i] can be considered an abbreviation for *(p+i).

Two equivalent C loops

for (i=0; i<1000; ++i) {
  A[i] = B[i] ;
}
int *pA = &A[0]  ;
int *pB = &B[0]  ;
for (i=0; i<1000; ++i) {
  *pA++ = *pB++ ;
}

In the old days programmers obsessed with efficiency would often write obfuscated loops using pointer arithmetic. Today, optimizing compiler use techniques, such as loop unrolling, that produce faster code than the “hand optimized” code.

C Strings

In C a string is an array of characters, but instead of having a size it is terminated by a null character.

char maxC = '\0' ;
char *nextC = &buff[0] ;
while (*nextC != '\0') {
   if (*nextC > maxC) {
      maxC = *nextC ;
   }
   ++nextC ;
}

Examples of implementing arrays on the PIC

Assume that c is an array of 8-bit characters. Each character will require one byte.

       MOV.B   W2,x+5          ;; c[5] <- W2
       MOV.B   x+5,W2          ;; W2 <- c[5]
       MOV.B   W2,[W4+5]       ;; W4[5] <- W2
       MOV.B   [W4+5],W2       ;; W2 <- W4[5]
       MOV.B   [W4+W5],W2      ;; W2 <- W4[W5]

Now, assume that x is an array of 16-bit integers. Each integer will require two bytes.

       MOV     W2,x+10         ;; x[5] <- W2
       MOV     x+10,W2         ;; W2 <- x[5]
       MOV     W2,[W4+10]      ;; W4[5] <- W2
       MOV     [W4+10],W2      ;; W2 <- W4[5]
       ADD     W5,W5,W0        ;;
       MOV     [W4+W0],W2      ;; W2 <- W4[W5]

Getting the right address

The following two lines of PIC code will increase the value stored in W7 by one and the value stored in W8 by two.

       MOV.B   [++W7],W0
       MOV     [++W8],W0

Faster loops

The PIC instruction set has a REPEAT instruction that is designed to make loops a bit more succinct. Here is an implementation of the C for shown above that copied the first 1000 elements of B into A.

       MOV     #A,W5
       MOV     #B,W6
       REPEAT  #999
       MOV     [W6++],[W5++]

A brief look at structure

C has a non-heterogeneous data structure called the struct, resembling a method-less class in Java, where several fields are stored within a collection.

struct point3D {
  int x ;
  int y ;
  int z ;
}
struct point3D P ;
P.x = 5 ;
P.y = P.x + 1 ;
P.z = 7 ;

When implemented the fields are stored at fixed offsets from the beginning of the structure.

       MOV     P+2,W5          ;; W5 <- P.y 
       MOV     W5,P+4          ;; P.z <- W5

Trying out an example

int V[500] ;
int H[100] ;
int i ;
for (i=0; i<100; ++i) {
  H[i] = 0 ;
}
for (i=0; i<500; ++i) {
  ++H[V[i]] ;
}