اشاره گر ها در C و C++
اشاره گر, به انگلیسی pointer یک متغیر است که بجای داده با معنی, آدرس یک نقطه از memory را در خود ذخیره میکند.
عملگر ها
عملگر *
بعد از data type
عملگر ستاره یا * بعد از data type یک pointer را تعریف میکند که آدرس شروع memory allocation را در خود حفظ میکند.
// pointer to int
int * pointer;
نکته مهم در رابطه با pointer ها این است که اندازه آن ها مستقل از data type متغیر است.
sizeof(int*) == sizeof(char*) == sizeof(double*)
قبل از آدرس
عملگر ستاره قبل از آدرس, مقدار ذخیره شده در memory را از نقطه شروع allocation تا به طول data type که پایان memory allocation برای یک data type میباشد را به ما میدهد.
int number = 3000;
printf("%d", *&number);
عملگر &
عملگر & آدرس شروع memory allocation یک متغیر را به ما میدهد.
// Define an int pointer and a variable.
int pointer, x = 2000;
// Assign the memory address of the variable to the pointer
pointer = &x;
// Print pointer value
printf("%d", *pointer);
آرایه ها در C
آرایه ها در C و CPP یک pointer با آدرس شروع داده در memory هستند به همراه data type هستند.
char * pointer;
char message [] = "INPUT";
// Equivalent to pointer = &message[0]
pointer = message;
برای دسترسی به محتوای خانه ها از ساختار زیر استفاده میکنیم.
* (pointer + index)
توجه شود که با اشاره گر void نمیتوان index اشاره گر را تغیر داد زیرا طول هر index به data type آرایه وابسته است, و طول void صفر بایت است که نمیتواند معیار تغیر index باشد.
int numbers[] = {1, 2, 3, 4};
int *ptr1 = numbers;
int *ptr2 = &numbers[0];
printf("%x - %x - %x
", numbers, ptr1, ptr2);
printf("%d - %d - %d
", *(numbers + 0), *(ptr1 + 0), *(ptr2 + 0));
کَست کردن اشاره گر ها
منظور از cast کردن اشاره گر تغیر نوع داده (data type) اشاره گر میباشد. هنگامی که از علمگر * پیش از اشاره گر ها استفاده میکردیم, بر اساس طول data type اشاره گر بایت های مقابل آدرس خوانده میشد, اما اگر اشاره گر را به data type جدیدی کَست کنیم این طول به طول data type جدید تغیر خواهد کرد.
char c[] = "c";
void * ptr = &c;
printf("%c", * (char *) ptr);
printf("%d", * (int *) ptr);
-+----+----+----+----+----+----+-
| | c | ?₁ | ?₂ | ?₃ | ?₄ |
-+----+----+----+----+----+----+-
^
|
ptr
با g++ main.cpp -o output -w && ./output میتوانید آن را اجرا کنید؛ در خط بالا اشاره گر ما از نوع void میباشد که طول data type آن صفر است. بنابر این, خواندن داده از آن اشاره گر ممکن نیست, اما با استفاده از cast ها میتوانیم نوع data type اشاره گر را عوض کنیم تا باید های مقابل آدرس را بخوانیم. اگر اشاره گر void را به int کست کنیم, بخاطر اینکه تنها ۱ بایت مقابل آن اشغال شده و طول int برابر با ۴ بایت است, ۳ باید دیگر ما مجهول و تصادفی خواهد بود.
مثال
بازنویسی حافظه
در کد زیر, هر char از آدرس شروع متغیر message در حافظه رونویسی میشود.
int main() {
// Define pointer
char * pointer;
// Store a message in memory
char message[] = "This is just a quote.";
// Assign variable address to the pointer
pointer = &message[0];
printf("From the first character stored in memory, fill each all the characters.\n");
// Print data
for(int i = 0; i <= sizeof(message) + 5; i++) {
// Override all the characters stored in the char array
if (i == sizeof(message)) * (pointer+i) = '\0';
// If the index is out of the range
else if (i > sizeof(message)) * (pointer+i) = '-';
else * (pointer+i) = 'x';
// Print each character
printf("%c", * (pointer+i));
}
// Print the current value of the char array
printf("\n\nMessage stored in memory:\n%s\n", message);
return 0;
}