Lecture 18 Last Pointers

Joseph Haugh

University of New Mexico

Free Recall

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", *foo[1]);

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", *foo[1]);

4

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", (*foo)[1]);

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", (*foo)[1]);

2

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", **foo);

Review Quiz

What is the output of the following pieces of code?

int *foo[2];
int a[3] = {1, 2, 3};
int b[4] = {4, 5, 6, 7};
foo[0] = a;
foo[1] = b;
printf("%d\n", **foo);

1

Review Quiz

What is the output of the following pieces of code?

char s[] = "Hello, World!";
int i;
int j = 0;
for (i = 0; i < 5; i++) {
if (i >= j) {
    *(s + i) = *(s + j + 1);
    j += 2;
}
}
printf("%s\n", s);

Review Quiz

What is the output of the following pieces of code?

char s[] = "Hello, World!";
int i;
int j = 0;
for (i = 0; i < 5; i++) {
  if (i >= j) {
    *(s + i) = *(s + j + 1);
    j += 2;
  }
}
printf("%s\n", s);

eell,, World!

Review Quiz

What is the output of the following pieces of code?

int x = 0x40; // sizeof(int) == 4
int *p = x;
printf("%p\n", p);
p += 4;
printf("%p\n", p);

Review Quiz

What is the output of the following pieces of code?

int x = 0x40; // sizeof(int) == 4
int *p = x;
printf("%p\n", p);
p += 4;
printf("%p\n", p);

0x40
0x50

Command Line Arguments

int main(int argc, char *argv[]) {

Call program: ./a.out Hello World

argv -> argv[0] -> a.out\0
argv[1] -> Hello\0
argv[2] -> World\0

argv is a pointer to an array of pointers.

Each pointer is the address of the first char in a null terminated string.

Echo Arguments: Array Style

void main(int argc, char *argv[]) { 
  int i;
  printf("Number of arguments = %d\n", argc);
  for (i = 0; i < argc; i++) { 
    printf("  argv[%d]=%s\n", i, argv[i]);
  }
}

a.out pi is 3.1415

Number of arguments = 4

argv[0]=a.out

argv[1]=pi

argv[2]=is

argv[3]=3.1415

argv[i] is the address of a null terminated string

Echo Arguments: Pointer Style

void main(int argc, char *argv[]) { 
  printf("main(): argc=%d\n", argc);
  while (argc-- > 0) { /* test first, then decrement */
    printf("argc=%d: %s\n", argc, *argv++);
  }
}

What is going on with *argv++?

  1. Dereference argv. This is argv[0]: a pointer to the first argument.
  2. Send that pointer to %s.
  3. Increment argv, not *argv. Now points to argv[1].

a.out Hello World

main(): argc=3

argc=2: a.out

argc=1: Hello

argc=0: World

More About *argv++

void main(int argc, char *argv[]) {
  printf("%p: %p->%s\n", argv, *argv, *argv);
  argv++;
  printf("%p: %p->%s\n", argv, *argv, *argv);
}
> ./a.out Hello World
0x7ffd6a971038: 0x7ffd6a972be8->./a.out
0x7ffd6a971040: 0x7ffd6a972bf0->Hello

Why do the addresses differ by 8?

That is the size of char*.

Double Echo Arguments: Array Style

void main(int argc, char *argv[]) { 
  int i, k;
  char* str;
  printf("Number of arguments = %d\n", argc);
  for (i = 0; i < argc; i++) { 
    printf("argv[%d]=%s\n", i, argv[i]);
    k=0;
    str = argv[i];
    while (str[k]) { 
      printf(" %c ",str[k]);
      k++;
    }
    printf("\n");
  }
}
> ./a.out Hello World
Number of arguments = 3
argv[0]=./a.out
 .  /  a  .  o  u  t 
argv[1]=Hello
 H  e  l  l  o 
argv[2]=World
 W  o  r  l  d 

charCompCaseInsensitive()

int charCompCaseInsensitive(char c1, char c2) {
  int lowerCaseOffset = 'A' - 'a';
  if (c1 >= 'a' && c1 <= 'z') { 
    c1 += lowerCaseOffset;
  }
  if (c2 >= 'a' && c2 <= 'z') { 
    c2 += lowerCaseOffset;
  }
  return c1 == c2;
}

findSubstringCaseInsensitive()

char *findSubstringCaseInsensitive(char *haystack,
                                   char *needle)  { 
  int len = strlen(needle);
  int matchCount = 0;
  while (*haystack) { 
    if (charCmpCaseInsensitive(*(needle+matchCount),
                               *haystack)) { 
      matchCount++;
      if (matchCount == len) { 
        return (haystack - len) + 1;
      }
    } 
    else { haystack -= matchCount; matchCount = 0; }
    haystack++;
  }
  return NULL;
}

Redone with Single Exit Code Style

char *findSubstring(char *haystack, char *needle)  { 
  int len = strlen(needle);
  int matchCount = 0, done = 0;
  char *startPt = NULL;
  while (*haystack && !done) { 
    if (charCmpCaseInsensitive(*(needle+matchCount), 
                               *haystack)) { 
      matchCount++;
      if (matchCount == len) { 
        startPt = (haystack - len) + 1;
        done = 1;
      }
    } 
    else { haystack -= matchCount; matchCount = 0; }
    haystack++;
  }
  return startPt;
}

Scanf: Read from stdin

void main(void) { 
  int n, m, a;
  float x;
  scanf("%d %d %f %d", &n, &m, &x, &a);
  printf("%d %d %f %d\n", n, m, x, a);
}
Input:
1 2 3.1415 
128
Output:
1 2 3.141500 128

See Kernighan and Ritchie, 7.4 Formatted Input for more details.

Sscanf: Read from string

void main(void) {
  char sentence[] = "Rudolph is 12 years";
  char s1[20], s2[20];
  int i;
  
  sscanf (sentence,"%s %s %d",s1,s2,&i);
  printf ("[%s] [%s] [%d]\n",s1,s2,i);
}
Output:
[Rudolph] [is] [12]

fgets: Get a String From a Stream

char *fgets(char *s, int n, FILE *stream);

The fgets() function reads bytes from a stream into the array pointed to by s until n-1 bytes are read, or a newline is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null character.

strtol: Convert String to Long Integer

long int strtol(const char *nptr, char **endptr, int base);

The strtol() function converts the initial part of the string pointed to by nptr to a long integer value according to the given base, which must be between 2 and 36 inclusive, or be the special value 0. The first unrecognized character ends the conversion and is pointed to by endptr.

strtol: Example

void main(void) { 
  char *endPtr;
  long n = strtol("1001", &endPtr, 2);
  printf("n=%ld, char at endPtr=[%c]\n", n, *endPtr);
  n = strtol("1011a", &endPtr, 2);
  printf("n=%ld, char at endPtr=[%c]\n", n, *endPtr);
}
Output:
n=9, char at endPtr=[]
n=11, char at endPtr=[a]

Pointer and Index to the Same Place

void main(void) { 
  char data[] = "Hello World";
  data[2] = 'X';
  char *linePt = &data[3];
  *linePt = 'Z';
  printf("[%s], [%s]\n", data, linePt);
}

What is the output?

[HeXZo World], [Zo World]

Power of Pointers

  • Pointers if used incorrectly, lead to very difficult bugs: bugs that only sometimes manifest.
  • Code that uses pointers is often harder for humans to read
  • Code that uses pointers is much harder for compilers to optimize

Find First Zero

int array[] = {4, 5, 8, 9, 8, 1, 0, 1, 9, 3};
int *array_ptr;
       
int main()  {
  array_ptr = array;
     
  while ((*array_ptr) != 0) {
    ++array_ptr;
  }
       
  printf("# of elements before zero %d\n", array_ptr - array);
  return 0;
}