[ L2H ] – Pointers in C

Pointer ေတြက အေျခခံက်ျပီး Memory ကိုလည္း နားလည္ေစတဲ့အရာမလို႕ Pointer ေတြအေၾကာင္းကိုေရးထားျခင္းျဖစ္ပါတယ္။ Basic Syntax ေတြကိုေတာ့မေျပာေတာ့ပါဘူး။ Pointers ေတြပဲေလ့လာၾကတာေပါ့ ။

Memory and Variables

 

int a;

interger data type ျဖစ္တဲ့ a ကိုေၾကညာလိုက္ျပီဆိုတာနဲ႕ Memory မွာ 4 bytes စာေနရာယူသြားမွာျဖစ္ပါတယ္။ ဘယ္လိုယူတာလဲဆိုရင္ေတာ့

0000 0000 - Byte 3
0000 0000 - Byte 2
0000 0000 - Byte 1
0000 0000 - Byte 0

ပံုမွာျပထားတဲ့အတိုင္းဆိုရင္ 201 ကေန 204 ထိ 4 Bytes ကိုယူသြားတယ္ဆိုပါစို႕။ 201 ဆိုတာက Memory Address ကို ဥပမာေပးထားတာျဖစ္ပါတယ္။

a = 5;

အခုလို Assign လုပ္လိုက္တဲ့အခ်ိန္မွာ ဘယ္လိုျဖစ္သြားမလဲ?

0000 0000 0000 0000 0000 0000 0000 0101
2 power 0 and 2 power 2 = 4+1 = 5

Character ဆိုရင္ေတာ့ 1 byte ပဲ ယူပါတယ္။ Interger , float စတာေတြကေတာ့ 4 bytes စသျဖင့္ ရွိၾကပါတယ္။

#include <stdio.h>
int main()
{
	printf("Size of an Integer = %d bytes\n",sizeof(int));
	printf("Size of an Character = %d byte\n",sizeof(char));
	printf("Size of an Float = %d bytes\n",sizeof(float));
	printf("Size of an Double = %d bytes\n",sizeof(double));
}

Result

D:\C>size_of_data.exe
Size of an Integer = 4 bytes
Size of an Character = 1 byte
Size of an Float = 4 bytes
Size of an Double = 8 bytes

Pointers

Pointers ဆိုတာ Variable ပါပဲ။ ဘယ္လို Varaible လဲဆိုရင္ေတာ့ အျခား variable ရဲ႕ Address ကိုသိမ္းတဲ့ variable ျဖစ္ပါတယ္။

Example ေလးနဲ႕ ေလ့လာၾကည့္မယ္။

#include <stdio.h>
int main()
{
	int a;    // Declare variable a
	int *p;  // Declare pointer p
	a=5;    // value of a
	p=&a; // assign address of a to pointer

	printf("%d\n",p);
	printf("%d\n",*p );
	printf("%d\n",&a );
	printf("%d\n",a );
}

Result

D:\C>pointer_one.exe
6422312
5
6422312
5

ဒီလိုဆိုရင္ 6422312 ဟာ a ရဲ႕ Address ေပါ့ ။ pointers ေတြဟာ တျခား variable ေတြရဲ႕ address ကိုသိမ္းတယ္ဆိုတာက်ေနာ္တို႕နားလည္သြားျပီ။

Dereferencing

Pointer ေတြကိုအသံုးျပဳျပီး က်ေနာ္တို႕ pointer က point လုပ္ေနတဲ့ Value ကို assign လုပ္လို႕ရပါတယ္။ ဒါကိုေတာ့ dereferencing လို႕ေခၚပါတယ္။

Example

#include <stdio.h>
int main()
{
	int a;
	int *p;
	a=5;
	p=&a;
	printf("%d\n",a );
	*p=10;  // Dereferencing
	printf("%d\n",a );
}

Result

D:\C>pointer_def.exe
5
10

Pointer Arithemetic

Example

#include <stdio.h>
int main()
{
 int a;
 int* p; //another type of pointer declration
 p=&a;
 printf("%d\n",p );
 printf("%d\n",p+1 );
}

p ဟာ 2016 ဆိုပါေတာ့ p+1 ဟာ ဘယ္ေလာက္ျဖစ္မလဲ?

Result

D:\C>pointer_arithmetic.exe
6422312
6422316

p ဟာ interger pointer ျဖစ္တဲ့အတြက္ 4 bytes စာ ယူတာျဖစ္ပါတယ္။

Pointer Types

int*
char*
void*

Pointer types ေတြကိုေရြးတဲ့အခါမွာ integer pointer က 4bytes စာယူတယ္။ char pointer က 1 byte သာယူတယ္။ ဒီလို pointer type ေတြကြာတဲ့အခါမွာ က်ေနာ္တို႕က မွန္မွန္ကန္ကန္မေရြးေပးရင္ဘာေတြျဖစ္နိုင္မလဲ?

Example

#include <stdio.h>
int main()
{
	int a;
	int *p;
	a=5;
	p=&a;
	printf("Size of an integer = %d\n",sizeof(int));
	printf("The address of a = %d , The value of a = %d \n",p,*p);
	char *p0;
	p0=(char*)p;  //typecasting
	printf("Size of an character = %d\n",sizeof(char));
	printf("The address of a = %d , The value of a = %d \n",p0,*p0);
}

example မွာေတာ့ interger pointer ကေန character pointer ကို typecasting လုပ္ထားတာျဖစ္ပါတယ္။

Result

D:\C>pointer_types.exe
Size of an integer = 4
The address of a = 6422308 , The value of a = 5
Size of an character = 1
The address of a = 6422308 , The value of a = 5

ဘာျပသနာမွမရွိတာကိုေတြ႕ရပါတယ္။ ဒါေပမဲ့ interger က 4 bytes ျဖစ္ျပီးေတာ့ character က 1 byte ပဲျဖစ္ေနတာဟာ a=5 ပဲမလို႕မသိသာတာျဖစ္ပါတယ္။ ဒီလိုဆိုရင္ 1025 ထည့္ၾကည့္မယ္။

D:\C>pointer_types.exe
Size of an integer = 4
The address of a = 6422308 , The value of a = 1025
Size of an character = 1
The address of a = 6422308 , The value of a = 1

character pointer မွာ 1 ပဲ ရွိတာကို ေတြ႕ရမွာျဖစ္ပါတယ္။

a=5 -> 0000 0000 0000 0000 0000 0000 0000 0101 
a=1025 -> 0000 0000 0000 0000 0000 0100 0000 0001

pointer ကို typecasting လုပ္လိုက္တဲ့အခ်ိန္မွာ 4 bytes ကေန 1 byte ျဖစ္သြားပါတယ္။

ဒါေၾကာင့္ ေနာက္ဆံုး 1 byte ကိုပဲယူလိုက္တဲ့အခ်ိန္မွာ value က 0000 0001 ဆိုေတာ့ 1 ပဲယူသြားတာျဖစ္ပါတယ္။

Void Pointer

Void pointer ကေတာ့ pointer ပဲရွိျပီးေတာ့ value ထည့္လို႕မရတဲ့ pointer အမ်ိဳးအစားျဖစ္ပါတယ္ ။

Example

#include <stdio.h>
int main()
{
 int a=5;
 void* p1;
 p1=&a;
 printf("The address of a = %d %d\n",p1,*p1);
}

Result

D:\C>gcc -o pointer_void pointer_void.c
pointer_void.c: In function 'main':
pointer_void.c:7:41: warning: dereferencing 'void *' pointer
 printf("The address of a = %d %d\n",p1,*p1);
 ^~~
pointer_void.c:7:2: error: invalid use of void expression
 printf("The address of a = %d %d\n",p1,*p1);

က်ေနာ္တို႕ void pointer မွာ value ကို return ျပန္လို႕မရပါဘူး။

#include <stdio.h>
int main()
{
	int a=5;
	void* p1;
	p1=&a;
	printf("The address of a = %d",p1);
}

Pointers to pointers

Pointer to pointer ကေတာ့ pointer ကေန ေနာက္ထပ္ pointer တစ္ခုကို ျပန္လုပ္တာျဖစ္ပါတယ္။

Example

#include <stdio.h>
int main()
{
	int a=5;
	int* p;
	p=&a;
	printf("p = %d , *p = %d \n",p,*p);
	int** p0;
	p0=&p;
	printf("p0 = %d , **p0 = %d or *(*p0) = %d \n",p0,**p0,*(*p0));
}

Result

D:\C>pointer_to_pointer.exe
p = 6422312 , *p = 5
p0 = 6422308 , **p0 = 5 or *(*p0) = 5

p0 ကို point ျပန္လုပ္မယ္ဆိုရင္ေတာ့ ***p1 ဟုသံုးနိုင္ပါတယ္။

Pointers & Arrays

int A[5]

Array မွာက pointer ကိုသံုးတဲ့အခါ အရင္ကလိုမဟုတ္ေတာ့ပါဘူး။ ဘာေၾကာင့္လဲဆိုရင္

int A[5];
int *p;
int p=&A[0];

Interger တုန္းက p+1 ကိုထုတ္တဲ့အခါ 4 bytes ေပါင္းသြားပါတယ္။ ဒါေပမဲ့ အဲ့ဒီ Adress မွာ Value ကထည့္မထားအတဲ့အတြက္ p+1 ဟာ တန္ဖိုးမရွိဘူးျဖစ္ေနပါတယ္။ Array မွာေတာ့ p+1 ဆိုရင္ A[1] ထဲက value ေတြရွိေနျပီေပါ့။ ဒီလိုဆို Example ေလးနဲ႕ၾကည့္မယ္။

Example

#include <stdio.h>
int main()
{
	int A[5]={1,2,3,4,5};
	int i;
	for (int i = 0; i < 5; ++i)
	{
		printf("A = %d , A[i] = %d , *A = %d , &A[i] = %d \n",A,A[i],*A,&A[i]);
	}

}

Result

D:\C>pointer_arrays.exe
A = 6422296 , A[i] = 1 , *A = 1 , &A[i] = 6422296
A = 6422296 , A[i] = 2 , *A = 1 , &A[i] = 6422300
A = 6422296 , A[i] = 3 , *A = 1 , &A[i] = 6422304
A = 6422296 , A[i] = 4 , *A = 1 , &A[i] = 6422308
A = 6422296 , A[i] = 5 , *A = 1 , &A[i] = 6422312

Array ဟာ Pointer ပဲျဖစ္တဲ့အတြက္ ေအာက္ကလိုမ်ိဳးလဲေရးလို႕ရပါတယ္။

A+i 
*(A+i)

Result

D:\C>pointer_arrays.exe
A+i = 6422296 , *(A+i) = 1
A+i = 6422300 , *(A+i) = 2
A+i = 6422304 , *(A+i) = 3
A+i = 6422308 , *(A+i) = 4
A+i = 6422312 , *(A+i) = 5

Pointers as Function Arguments – Call by reference

Call by reference ကိုမေလ့လာခင္ Call by value ကိုအရင္ၾကည့္လိုက္မယ္။ ဒါဆိုရင္ ဘာေၾကာင့္ pointer ေတြကို Argument အေနနဲ႕သံုးဖို႕လိုလဲဆိုတာသိရပါလိမ့္မယ္။

Example

#include <stdio.h>

int Increment(int a)
{
	a=a++;
}

int main()
{
	int a=5;
	Increment(a);
	printf("%d\n",a );
}

Result

D:\C>call_by_value.exe
5

a ကို Increment လုပ္လိုက္ေပမဲ့ Result မွာၾကည့္လိုက္ရင္ a=5 ပဲျဖစ္ေနတာကိုေတြ႕ရမွျဖစ္ပါတယ္။ ဘာေၾကာင့္ ဒီလိုျဖစ္တာလဲ ?

Address ေတြမတူၾကလို႕လား

#include <stdio.h>

int Increment(int a)
{
	a=a++;
	printf("The address of a = %d\n",&a );
}

int main()
{
	int a=5;
	Increment(a);
	printf("%d\n",a );
	printf("The address of a = %d\n",&a );
}

Result

D:\C>call_by_value.exe
The address of a = 6422288
5
The address of a = 6422316

ဟုတ္တယ္ Address ေတြမတူၾကဘူး ။ ဘာလို႕လဲ?

Memory မွာ သိမ္းတဲ့အခါ Function ေတြ Local variables ေတြကို Stack ထဲမွာသိမ္းၾကပါတယ္။ Function တစ္ခုစီအတြက္ Stack Frame တစ္ခုစီရွိၾကတယ္။

Example

300-Increment() stack frame -> &a = 304

200-main() stack frame -> &a = 204

ဒီေတာ့ printf နဲ႕ထုတ္လိုက္တဲ့အခ်ိန္မွာ main ထဲမွာရွိတယ္ local variable တန္ဖိုးပဲထြက္လာတာျဖစ္ပါတယ္။

တကယ္လို႕ Pointer ကို argument အေနနဲ႕သံုးမယ္ဆိုရင္ေရာ ? Call by reference လို႕ေခၚပါတယ္။

Example

#include <stdio.h>

int Increment(int *p)
{
	*p=(*p)+1;
	printf("The address of a = %d\n",p );
}

int main()
{
	int a=5;
	Increment(&a);
	printf("%d\n",a );
	printf("The address of a = %d\n",&a );
}

Result

D:\C>call_by_reference.exe
The address of a = 6422316
6
The address of a = 6422316

Pointer ကို Argument အေနနဲ႕သံုးတဲ့အတြက္ Address တစ္ခုတည္းကိုပဲ function ၂ ခုလံုးမွာ သံုးတဲ့ပံုစံျဖစ္သြားပါတယ္။ ဒီေတာ့ a ကိုထုတ္လိုက္တဲ့အခ်ိန္မွာ 6 ျဖစ္သြားတာေပါ့။ reference type နဲ႕ပတ္သတ္ျပီး တစ္ခုဖတ္ဖူးပါတယ္။ ဘယ္မွာလဲေတာ့မမွတ္မိေတာ့ဘူး။

ပန္းသီး ၅ လံုးရွိတယ္ဆိုပါေတာ့ ။

ေမာင္ေမာင္က ေအာင္ေအာင္ကို အဲ့ပန္းသီး ၅ လံုးကိုေပးလိုက္တယ္။ ေအာင္ေအာင္ ၂လံုးစားရင္ ေမာင္ေမာင္မွာလဲ ၃ လံုးပဲက်န္တာေပါ့။ ေနာက္ထပ္ ၅ လံုးဝယ္ေပးလိုက္တာမဟုတ္ပါဘူး။ ဒါကို ခုလို pointer နဲ႕ေသခ်ာျမင္ရေတာ့ ေတာ္ေတ္ာေလးရွင္းသြားပါတယ္။ ပန္းသီးေတြမလိုေတာ့ဘူး

To be continued

2 Comments

1 Trackback / Pingback

  1. 0x0F – Introduction to Heap – Legion of LOL

Comments are closed.