Word Count: 1331
  • Post category:C
  • Post last modified:2023-01-24

Reference

Tutorial Point – C Tutorial

C Pointers

Pointers

Some tasks are performed more easily with pointers, and other tasks, such as dynamic memory allocation, cannot be performed without using pointers.

Every variable is a memory location and every memory location has its address defined which can be accessed using ampersand (&) operator, which denotes an address in memory.

pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address. The general form of a pointer variable declaration is −

type *var-name;
  • type – pointer’s base type, it must be a valid C data type.
  • var-name – name of the pointer variable.
  • * – used to declare var-name is a pointer.
// Examples
int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

How to Use Pointers?

There are a few important operations, which we will do with the help of pointers very frequently. (a) We define a pointer variable, (b) assign the address of a variable to a pointer and (c) finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand. The following example makes use of these operations −

#include <stdio.h>

// The address formater is %p

int main () {

   int  var = 20;   /* actual variable declaration */

   int  *ip;   /* pointer variable declaration */
   ip = &var;  /* store address of var in pointer variable*/
   /* One line to both declare and initialize: int *ip = &var;  */

   printf("Address of var variable: %p\n", &var  );

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %p\n", ip );

   /* access the value using the pointer */
   printf("Value of *ip variable: %d\n", *ip );

   return 0;
}

When the above code is compiled and executed, it produces the following result −

Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20

Another Example:

// C++ compilation
#include <iostream>

using namespace std;

int main()
{

	int var1 = 100;
	int *pVar1 = &var1;

	int var2 = 200;
	int *pVar2;
	pVar2 = &var2;

	cout << "var1 is " << var1 << "\n";
	cout << "*pVar1 is " << *pVar1 << "\n";
	cout << "pVar1 is " << pVar1 << "\n";
	cout << endl;

	cout << "var2 is " << var2 << "\n";
	cout << "*pVar2 is " << *pVar2 << "\n";
	cout << "pVar1 is " << pVar2 << "\n";
	cout << endl;

	cout << "Now update var1 to 300 via the pointer\n";

	*pVar1 = 300;
	
	cout << "var1 is " << var1 << "\n";
	cout << "*pVar1 is " << *pVar1 << "\n";
	cout << "pVar1 is " << pVar1 << "\n";
	cout << endl;

	return 0;
}


// The above produces the below result:

var1 is 100
*pVar1 is 100
pVar1 is 0x7fc419a9b0

var2 is 200
*pVar2 is 200
pVar1 is 0x7fc419a9b4

Now update var1 to 300 via the pointer
var1 is 300
*pVar1 is 300
pVar1 is 0x7fc419a9b0

NULL Pointers?

It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer. This also implies that the pointer is pointing to Nothing.

Pointers in Detail

Pointer arithmetic

There are four arithmetic operators that can be used in pointers: ++, –, +, –

Array of pointers

You can define arrays to hold a number of pointers.

Example: int *ptr[MAX]; then run a loop to assign the pointer to each element in ptr.

Pointer to an Array

#include <iostream>

using namespace std;

int main() {
	int arr[3] = {100, 200, 300};
	int *p1_arr = arr;  // assign a pointer to the array.

	// the above has the same effect as:
	int *p2_arr = &arr[0];  // assign a pointer to the same array.

	p1_arr++;  // pointer arithmetic for moving to next element
	p2_arr++;

	cout << endl;
	cout << "second element of arr: " << *p1_arr << endl;
	cout << "second element of arr: " << *p2_arr << endl;
	cout << "So p1_arr and p2_arr are pointing to the same array\n\n";
	return 0;
}

/*** The output of the above:  **/
second element of arr: 200
second element of arr: 200
So p1_arr and p2_arr are pointing to the same array

Pointer to pointer

  • C allows you to have pointer on a pointer and so on.
  • When we define a pointer to a pointer, the first pointer contains the address of the second pointer, which points to the location that contains the actual value.
  • A variable that is a pointer to a pointer must be declared as such. This is done by placing an additional asterisk in front of its name likes this: int **var;

Passing pointers to function

Passing an argument by reference or by address enable the passed argument to be changed in the calling function by the called function.

The function, which can accept a pointer, can also accept an array.

#include <stdio.h>
#include <time.h>
 
void getSeconds(unsigned long *par);

int main () {

   unsigned long sec;
   getSeconds( &sec );

   /* print the actual value */
   printf("Number of seconds: %ld\n", sec );

   return 0;
}

void getSeconds(unsigned long *par) {
   /* get the current number of seconds */
   *par = time( NULL );
   return;
}

Return pointer from function

C allows a function to return a pointer to the local variable, static variable, and dynamically allocated memory as well.

The function has to be declared in the form:

int * myFunction() {
. . .
}

It is not a good idea to return the address of a local variable outside the function, so you would have to define the local variable as static variable, otherwise, you would get the warning “address of local variable ‘r’ returned.

Example:

#include <iostream>
using namespace std;

/* Function to return 5 numbers*/
int *the5Num()
{
	static int r[5] = {15, 14, 13, 12, 11};
	return r;  // r is the address of the first element of array
} // the5Num()

int main()
{
	int *p;
	int i;

	p = the5Num();

	cout << endl;
	cout << "The value of p: " << p << endl;
	cout << "The address of p[0]: " << &p[0] << endl;
	cout << "The value of *p: " << *p << endl;
	cout << "The value of *(p + 3) i.e., the 4th element: " << *(p + 3) << endl;
	return 0;
}

/*  Result:  */
The value of p: 0x558b170010
The address of p[0]: 0x558b170010
The value of *p: 15
The value of *(p + 3) i.e., the 4th element: 12

function(void *arg)

It is just a general pointer passing to the function, your function should know what is the actual type of the pointer – and cast it appropriatly before accessing the data.

It is mostly used in the Callbacks (CB), when library is provided with CB address and some context address.
Library does not need to know the type of the data – so the pointer is stored as void* and supplied to the CB, when it is called from the library code

the CB – which is part of the application code – knows exactly what is the data type passed as a context and could cast the pointer accordingly

Common Mistakes

int c, *pc;

// pc is address but c is not
pc = c;  // Error

// &c is address but *pc is not
*pc = &c;  // Error

// both &c and pc are addresses
pc = &c;  // Not an error

// both c and *pc are values 
*pc = c;  // Not an error