Pointers in C Programming

July 02, 2018 | 1 Tags | 0 Comment

Pointers in C Programming

A pointer in C language is a variable which holds the address of another variable of same data type. Pointers are used to access memory and manipulate the address.

Whenever a variable is defined, a memory allocation is assigned for it to hold the assigned value. We can easily check this memory address using the & symbol.

If var is the name of the variable, then &var will give its address.

#include <stdio.h>

int main() {
   int var = 7;
   printf("Value of the variable var is: %d\n", var);
   printf("Memory address of the variable var is: %x\n", &var);

   return 0;
}

; Like a variable, before using a pointer, you have to declare it. First, you specify the data type of the variable that the pointer point to. Second, you put an asterisk in front of the pointer name. Next you give the name for the pointer.

int *ptr;

To initialize a pointer, you assign the memory address of another variable to the pointer.

int a = 100;
int *ptr;
ptr = &a;

Once a pointer has been assigned the address of a variable, to access the value of the variable pointer, you use the indirection operator or dereferencing operator *.

#include <stdio.h>

int main()
{
    int a, *p;  // declaring the variable and pointer
    a = 10;
    p = &a;     // initializing the pointer

    printf("value of a : %d", *p);    //this will print the value of 'a'
    printf("value of a : %d", *&a);   //this will also print the value of 'a'
    printf("address of a : %u", &a);    //this will print the address of 'a'
    printf("address of a : %u", p);     //this will also print the address of 'a'
    printf("address of p : %u", &p);    //this will print the address of 'p'

    return 0;
}

If you are not sure about which variable’s address to assign to a pointer variable while declaration, it is recommended to assign a NULL variable to your pointer variable. A pointer which is assigned a NULL value is called a NULL pointer.

#include <stdio.h>

int main()
{
    int *ptr = NULL;
    return 0;
}
Pointer to Pointer

When a pointer variable stores the address of another pointer variable, it’s known as Pointer to Pointer variable or Double Pointer.

#include <stdio.h>

int main()
{
    int  a = 10;
    int  *p1;   // used to store the address of a variable
    int  **p2;  // used to store the address of a variable pointer

    p1 = &a;
    p2 = &p1;

    printf("Address of a = %u\n", &a);
    printf("Address of p1 = %u\n", &p1);
    printf("Address of p2 = %u\n\n", &p2);

    // below print statement will give the address of 'a'
    printf("Value at the address stored by p2 = %u\n", *p2);

    printf("Value at the address stored by p1 = %d\n\n", *p1);

    printf("Value of **p2 = %d\n", **p2);   // read this *(*p2)

    return 0;
}
Pointer to Array

We can use a pointer to point to an array, and then we can use that pointer to access the array elements.

#include <stdio.h>

int main()
{
    int i;
    int a[5] = {1, 2, 3, 4, 5};
    int *p = a;     // same as int *p = &a[0]
    for (i = 0; i < 5; i++)
    {
        printf("%d", *p);
        p++;
    }

    return 0;
}

The generalized form for using pointer with an array *(a+i) is the same as a[i].

The generalized form for using pointer with multidimensional arrays *(*(a + i) + j), which is the same as a[i][j].

Pointer can also be used to create strings. Pointer variables of char type are treated as string.

#include <stdio.h>

int main()
{
    char *str = "Hello";
    printf("%s\n", str);

    return 0;
}

The string created using char pointer can be assigned a value at runtime.

#include <stdio.h>

int main()
{
    char *str;
    str  = "Hello"
    printf("%s\n", str);

    return 0;
}

We can also have array of pointers. Pointers are very helpful in handling character array with rows of varying length.

char *name[3] = {
    "Adam",
    "chris",
    "Deniel"
};
Pointer to Structure

We can also have pointer to a single structure variable, but it is mostly used when we are dealing with array of structure variables.

A structure’s member can be accessed through pointer in two ways

  1. Accessing structure member through pointer by referencing pointer to another address to access the memory
  2. Accessing structure member through pointer using dynamic memory allocation

Accessing structure member through pointer by referencing pointer to another address to access the memory

#include <stdio.h>
typedef struct person
{
   int age;
   float weight;
   char name[30];
};

int main()
{
    struct person person1;
    struct person *personPtr;
    personPtr = &person1;            // Referencing pointer to memory address of person1

    printf("Enter name: ");
    scanf("%s", (*personPtr).name);

    printf("Enter age: ");
    scanf("%d", &(*personPtr).age);

    printf("Enter weight: ");
    scanf("%f", &(*personPtr).weight);

    printf("Displaying: ");
    printf("%s\t%d\t%f\n", (*personPtr).name, (*personPtr).age, (*personPtr).weight);

    return 0;
}

Accessing structure member through pointer using dynamic memory allocation

#include <stdio.h>
#include <stdlib.h>

struct person {
   int age;
   float weight;
   char name[30];
};

int main()
{
   struct person *ptr;
   int i, num;

   printf("Enter number of persons: ");
   scanf("%d", &num);

   ptr = (struct person*) malloc(num * sizeof(struct person));   // allocates the memory for n structures with pointer personPtr pointing to base address

   for(i = 0; i < num; ++i)
   {
       printf("Enter name, age and weight of the person respectively:\n");
       scanf("%s%d%f", (ptr+i)->name, &(ptr+i)->age, &(ptr+i)->weight);
   }

   printf("Displaying Infromation:\n");
   for(i = 0; i < num; ++i)
       printf("%s\t%d\t%.2f\n", (ptr+i)->name, (ptr+i)->age, (ptr+i)->weight);

   return 0;
}
Pointers as Function Argument

Pointer as a function argument is used to hold addresses of arguments passed during function call. This is also known as call by reference. When a function is called by reference any change made the reference variable will effect the original variable.

#include <stdio.h>

void swap(int *a, int *b);

int main()
{
    int m = 10, n = 20;
    printf("m = %d\n", m);
    printf("n = %d\n\n", n);

    swap(&m, &n);    //passing address of m and n to the swap function
    printf("After Swapping:\n\n");
    printf("m = %d\n", m);
    printf("n = %d", n);
    return 0;
}

/*
    pointer 'a' and 'b' holds and
    points to the address of 'm' and 'n'
*/
void swap(int *a, int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

A function can also return a pointer to the calling function.

#include <stdio.h>

int* larger(int*, int*);

void main()
{
    int a = 15;
    int b = 92;
    int *p;
    p = larger(&a, &b);
    printf("%d is larger", *p);
}

int* larger(int *x, int *y)
{
    if(*x > *y)
        return x;
    else
        return y;
}
Pointer to Function

A function pointer is a pointer that refers to the address of a function.

#include <stdio.h>

int sum(int x, int y)
{
    return x+y;
}

int main()
{
    int (*fp)(int, int);  // declaring a function pointer
    fp = sum;  // initializing a function pointer
    int s = fp(10, 15);
    printf("Sum is %d", s);

    return 0;
}
How to Read Complex C Variables

Reading C simple declarations

int      foo[5];     // foo is an array of 5 ints
char    *foo;        // foo is a pointer to char
double   foo();      // foo is a function returning a double
* is read as pointer to ...
[] is read as array of ...
() is read as function returning ...

The “array of” [] and “function returning” () type operators have higher precedence than “pointer to” *. So these are the rules to read complex variable declaration:

  • always start with the variable name: foo is …
  • always end with the data type : foo is … int
  • the “filling in the middle” part can be summarized with this rule: “go right when you can, go left when you must”

We will start with a simple example

long **foo[7];

Steps to read the declaration as follow

  • start with the variable name and end with the data type:
    long **foo[7]
    foo islong
  • then, the rule is to go right when you can:
    long **foo[7]
    foo is array of 7long
  • because we’ve gone as far right as possible, now we go left:
    long **foo[7]
    foo is array of 7 pointer to pointer to long

Next, we will start with a more complex example

char *(*(**foo [][8])())[];

Steps to read the declaration as follow

  • start with the variable name and end with the data type:
    char *(*(**foo [][8])())[]
    foo ischar
  • the rule is to go right when you can:
    char *(*(**foo [][8])())[]
    foo is array ofchar
  • because we still can go right then we go right:
    char *(*(**foo [][8])())[]
    foo is array of array of 8char
  • now, we’ve hit parenthesis used for grouping and this halts our march to the right. So we have to backtrack to the left:
    char *(*(**foo [][8])())[]
    foo is array of array of 8 pointer tochar
  • we still can go left:
    char *(*(**foo [][8])())[]
    foo is array of array of 8 pointer to pointer tochar
  • now we’ve hit parenthesis used for grouping, this finished off the entire parenthesized subexpression. then we go right again:
    char *(*(**foo[][8])())[]
    foo is array of array of 8 pointer to pointer to function returningchar
  • again we are backtracking to the left:
    char *(*(**foo[][8])())[]
    foo is array of array of 8 pointer to pointer to function returning pointer tochar
  • again we hit grouping parenthesis, so backtrack to the right:
    char *(*(**foo[][8])())[]
    foo is array of array of 8 pointer to pointer to function returning pointer to array ofchar
  • finally, we’re left with only “pointer to” on the left:
    char *(*(**foo[][8])())[]
    foo is array of array of 8 pointer to pointer to function returning pointer to array of pointer to char

Things to notice when declaring complex variables:

  • can’t have array of function returning. Use array of pointer to function returning instead
  • Functions can’t return functions. Use function returning pointer to function returning instead
  • in arrays, only the leftmost [] can be undimensioned. char foo[] and char foo[][5] are legal, but char foo[5][] is not
  • void type is restricted. pointer to void void *foo and function returning void void foo() are legal, but array of void void char[] and declaring a variable of type void are not legal
C
Samuel Yang image
Samuel Yang

If you like this tutorial, you can support me

Donate Now