hvn-network

My Blog List

Thursday, September 8, 2016

[C programming] Pointers and arrays

We cover below parts.

- Pointers and addresses
- Pointers and function arguments
- Pointers and arrays
- Address arithmetic
- Character pointers and functions
- Pointer arrays; pointers to pointers
- Multi-dimensional arrays
- Initialization of pointer arrays
- Pointers vs multi-dimensional arrays
- Command-line arguments
- Pointer to functions
- Complicated declarations

1. Pointers and addresses
A pointer is a variable that contains the address of a variable.
Pointers and arrays are closely related.


char * p;
char c;
// assign the address of c to the variable p; p is said to point to c
p = &c; 

& operator only applies to objects in memory: variables and array elements. It cannot be applied to expressions, constants or register variables

operator * is the indirection or dereferencing operator; when applied to a pointer, it accesses the object the pointer points to.

int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */
ip = &x; /* ip now points to x */
y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */

a ``pointer to void'' is used to hold any type of pointer but cannot be dereferenced itself.

Unary operators like * and ++ associate right to left, so (*ip)++  ==  ++*ip  ##  *ip++

Pointers are variables, they can be used without dereferencing. For example, if iq is another pointer to int, iq = ip, copies the contents of ip into iq, thus making iq point to whatever ip pointed to.


2. Pointers and function arguments

C passes arguments to functions by value, there is no direct way to alter a variable in the calling function.
We need pass pointers to the values to be changed.
Remember the operator & produces the address of a variable, &a is a pointer to a.

Check how to swap two variables.


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

swap(&a, &b);




Check another example to convert input by breaking a stream of characters into integer values.
int  getint (int *pn);

int main ()
{
 for (;;) {
  int r, n;

  if ((r = getint(&n)) == EOF)
   return 0;
  else if (r != 0)
   printf("%d\n", n);
 }
}

// get character from buffer to consider valid or not
int getch (void);
// to put "unwanted" character to buffer (anything differ +, -, digit)
void ungetch (int c);

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 == '-')
  if (!isdigit(c = getch())) {
   ungetch(c);
   return 0;
  }

 for (*pn = 0; isdigit(c); c = getch())
  *pn = 10 * *pn + c - '0';

 *pn *= sign;

 if (c != EOF)
  ungetch(c);

 return c;
}

#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 characters!\n");
 else
  buf[bufp++] = c;
}



3. Pointers and arrays
There is strong relationship between pointers and arrays. 
Suppose:
int a[10]; *pa, x;

pa = &a[0]  // pa point to element zero of a;

x = *pa // copy contents of a[0] to x;

*(pa +i ) same with a[i]; 
pa = &a[0] same with pa=a;

A pointer is a variable, so pa=a and pa++ are legal, but an array name is not a variable so
a=pa and a++ are illegal (! recheck it).


When an array name is passed to a function, what is passed is the location of the initial element.

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

int main()
{
 char array[100] = "hello world";
 char *ptr ="hello world";
 
 // all below call works
 printf("%d\n", strlen("hello world")); // string constant
 printf("%d\n",strlen(ptr));
 printf("%d\n",strlen(array));
 
 return 0;
}

As formal parameters in a function definition, char s[]; and char *s; are equivalent; we prefer the latter because it says more explicitly that the variable is a pointer.

4. Address Arithmetic

The valid pointer operations are assignment of pointers of the same type, adding or subtracting a pointer and an integer, subtracting or comparing two pointers to members of the same array, and assigning or comparing to zero. All other pointer arithmetic is illegal.

Check another version of strlen() using pointer subtraction.

int strlen(char *s)
{
 char *p = s;
 while (*p != '\0')
 p++;
 return p - s;
}
5. Character pointers and functions
A string constant, written as "I am a string" is an array of characters. In the internal representation, the array is terminated with the null character '\0' so that programs can find the end. The length in storage is thus one more than the number of characters between the double quotes.

If pmessage is declared as
char *pmessage;
then the statement
pmessage = "now is the time";
assigns to pmessage a pointer to the character array. This is not a string copy; only pointers are involved. C does not provide any operators for processing an entire string of characters as a unit.

There is an important difference between these definitions:

char amessage[] = "now is the time"; /* an array */
char *pmessage = "now is the time"; /* a pointer */

We will illustrate more aspects of pointers and arrays by studying versions of strcpy() and strcmp().
// Copy t to s
void strcpy1(char *s, char *t) // wrong version
{
 // s, t is local variable, 
 // just copy pointer value, not content that pointer point to
 s = t; 
}

void strcpy2(char *s, char *t) // array subscript version
{
 int i = 0;
 while ((s[i] = t[i]) != '\0')
  i++;
}

void strcpy3(char *s, char *t) // pointer version 1
{
 while ((*s = *t) != '\0') {
  s++;
  t++;
 }  
}

void strcpy4(char *s, char *t) // pointer version 2
{
 while ((*s++ = *t++) != '\0')
  ;
}

void strcpy5(char *s, char *t) // pointer version 3
{
 while (*s++ = *t++)
  ;
}

/* strcmp: return <0 0="" if="" s="=t," t="">0 if s>t */
int strcmp(char *s, char *t)
{
 int i;
 for (i = 0; s[i] == t[i]; i++)
 if (s[i] == '\0')
 return 0;
 return s[i] - t[i];
}

int strcmp(char *s, char *t) // pointer version
{
 for ( ; *s == *t; s++, t++)
 if (*s == '\0')
 return 0;
 return *s - *t;
}


6. Pointer arrays; pointers to pointers


This example sorts character arrays from input.
#define MAXLINES 5000
#define MAXCHARS 100000
#define RED     "\x1b[31m"
#define RESET   "\x1b[0m"

char *lineptr[MAXLINES];
char linebuf[MAXCHARS];

int readlines (char *lineptr[], int maxlines, char linebuf[]); 
void writelines (char *lineptr[], int nlines);
void _qsort (char *v[], int left, int right);

int main ()
{
 int nlines;

 if ((nlines = readlines(lineptr, MAXLINES, linebuf)) >= 0) {
  _qsort(lineptr, 0, nlines - 1);
  writelines(lineptr, nlines);
  return 0;
 } else {
  printf("Error: Input too big to sort!\n");
  return 1;
 }
}

#define MAXLEN 1000

int _getline (char line[], int limit);
int readlines (char *lineptr[], int maxlines, char linebuf[])
{
 int len, nlines;
 char *p, line[MAXLEN];

 nlines = 0;
 p = linebuf;
 while ((len = _getline(line, MAXLEN)) > 0) 
  //if (nlines >= maxlines || p + len > linebuf + MAXCHARS) 
  /*if don't use malloc, we need increase p pointer as p += len, it is faster than malloc */
  if (nlines >= maxlines || (p = malloc(len))== NULL) 
   return -1;
  else 
  {
   /* Delete newline, correct if no line reaches MAXLEN
    * length, otherwise last character is lost. 
     */

   line[len - 1] = '\0';
   
   strcpy(p, line);
   lineptr[nlines++] = p;
   //p += len; 
  }
  
 return nlines;
}

void writelines (char *lineptr[], int nlines)
{
 int i;
    printf(RED "\nAfter sorting \n" RESET);
 for (i = 0; i < nlines; i++)
  printf("%s\n", lineptr[i]);
}

int _getline (char line[], int limit)
{
        int     i, c;

        for (i = 0; i < limit - 1 && (c = getchar()) != EOF && c != '\n'; i++)
   line[i] = c;
  
        if (c == '\n') {
            line[i] = c;
            i++;
        }
        line[i] = '\0';

        return i;
}

void swap (char *v[], int i, int j);

void _qsort (char *v[], int left, int right)
{
 int i, last;

 if (left >= right)
  return;

 swap(v, left, (left + right) / 2);
 last = left;
 for (i = left + 1; i <= right; i++)
  if (strcmp(v[i], v[left]) < 0)
   swap(v, ++last, i);

 swap(v, left, last);

 _qsort(v, left, last - 1);
 _qsort(v, last + 1, right);
}

void swap (char *v[], int i, int j)
{
 char *temp;

 temp = v[i];
 v[i] = v[j];
 v[j] = temp;
}

// suppose v is an int array, note below swap works
// pass as swap2(v,i,j)
void swap2 (char v[], int i, int j)
{
 char temp;

 temp = v[i];
 v[i] = v[j];
 v[j] = temp;
}

No comments:

Post a Comment