C పాయింటర్లు: బేసిక్స్, మెమరీ అడ్రస్లు & Dereferencing (*, &)
ఒక పెద్ద 5-స్టార్ లగ్జరీ హోటల్ను ఊహించుకోండి. అందులో 500 గదులు ఉన్నాయి. గది నంబర్ 304 లో ఒక అమూల్యమైన బంగారు లాకెట్ లేదా నగదు భద్రపరచబడి ఉందనుకుందాం (Variable Value). మీరు ఆ నగదును మీ జేబులో పెట్టుకుని ఊరంతా తిరగడం బరువైనది, ప్రమాదకరమైనది. దానికి బదులుగా, మీ చేతిలో "Room #304" అని రాసి ఉన్న ఒక చిన్న ప్లాస్టిక్ కీ-కార్డు (Electronic Key Card) ఉంటే సరిపోతుంది కదా!
ఆ ప్లాస్టిక్ కీ-కార్డులో బంగారం ఉండదు; కానీ బంగారం దాగి ఉన్న గది యొక్క చిరునామా (Room Address) ఉంటుంది. మీరు ఆ కార్డును తీసుకెళ్లి రూమ్ నంబర్ 304 తలుపు వద్ద స్వైప్ చేస్తే — తాళం తెరుచుకుని లోపల ఉన్న అసలైన నగదు మీ చేతికి అందుతుంది. కంప్యూటర్ సైన్స్లో C పాయింటర్లు సరిగ్గా ఇలాగే పనిచేస్తాయి:
- రూమ్ లోపల ఉన్న నగదు = వేరియబుల్ విలువ (Value)
- హోటల్ రూమ్ నంబర్ = మెమరీ అడ్రస్ (& ఆపరేటర్)
- ప్లాస్టిక్ కీ-కార్డు = పాయింటర్ వేరియబుల్ (Pointer Variable)
- కార్డు ద్వారా తలుపు తెరిచి లోపలి నగదును అందుకోవడం = డిరిఫరెన్సింగ్ (* ఆపరేటర్)!
పాయింటర్లపై సంపూర్ణ పట్టు సాధించిన రోజే మీరు నిజమైన C ప్రోగ్రామర్గా అవతరిస్తారు. ఈ పదిహేనవ అధ్యాయంలో, పాయింటర్ల అంతర్గత నిర్మాణం, పాయింటర్ అరిథ్మెటిక్ (Pointer Arithmetic Scale Factor), వైల్డ్ & డాంగ్లింగ్ పాయింటర్లు, మరియు సిస్టమ్ RAM మెమరీని లోతుగా శోధించే మెమరీ ఇన్స్పెక్టర్ టూల్ను సమగ్రంగా నిర్మిద్దాం!
సిస్టమ్స్ ప్రోగ్రామింగ్, ఆపరేటింగ్ సిస్టమ్ కెర్నల్స్ మరియు హై-పెర్ఫార్మెన్స్ సాఫ్ట్వేర్లలో పాయింటర్లు అనేవి గుండెకాయ లాంటివి. ఈ అధ్యాయంలో కవర్ చేయబడే ప్రధానాంశాలు:
- పాయింటర్ ప్రాథమిక నిర్వచనం: మరొక వేరియబుల్ యొక్క మెమరీ అడ్రస్ను భద్రపరిచే ప్రత్యేక వేరియబుల్.
- RAM మెమరీ మోడల్ & హెక్సాడెసిమల్ అడ్రస్లు:
%pఫార్మాట్ స్పెసిఫైయర్ మరియు 64-బిట్ ఆర్కిటెక్చర్లో 8 బైట్ల పాయింటర్ సైజు. - రెండు మేజికల్ ఆపరేటర్లు:
&(Address-Of) మరియు*(Dereference / Indirection). - పాయింటర్ల డిక్లరేషన్ & ఇనిషియలైజేషన్:
int *ptr = &x;సింటాక్స్ అనాటమీ. - పాయింటర్ అరిథ్మెటిక్ రహస్యం:
ptr + 1అంటే 1 బైట్ కలపడం కాదు! డేటా టైప్ సైజు ఆధారంగా స్కేలింగ్ జరిగే విధానం. - పాయింటర్ సబ్ట్రాక్షన్ (Pointer Difference): రెండు పాయింటర్ల మధ్య తీసివేత ఫలితం
ptrdiff_t. - సమగ్ర తులనాత్మక పట్టిక: పాయింటర్ల రకాలు (Normal, NULL, Void, Wild, Dangling).
- జెనెరిక్ పాయింటర్లు (void* Pointers): ఏ డేటా టైప్ అడ్రస్నైనా పట్టుకునే సార్వత్రిక పాయింటర్ & టైప్ కాస్టింగ్.
- ప్రమాదకరమైన 4 పాయింటర్ బగ్స్: NULL Pointer, Wild Pointer, Dangling Pointer, మరియు Memory Leaks.
- const కీవర్డ్ మరియు పాయింటర్లు: Pointer to Const vs Const Pointer మధ్య ఉన్న కీలక వ్యత్యాసం.
- సమగ్ర రియల్ వరల్డ్ ప్రాజెక్ట్: RAM మెమరీ హెక్స్ డంపర్ & బైట్-బై-బైట్ వేరియబుల్ ఇన్స్పెక్టర్.
- బిగినర్స్ చేసే టాప్ 5 పాయింటర్ తప్పులు:
*లేకుండా అసైన్మెంట్, అన్ఇనిషియలైజ్డ్ పాయింటర్ డిరిఫరెన్స్, ఆపరేటర్ ప్రిసిడెన్స్. - స్వీయ మూల్యాంకన క్విజ్: 5 లోతైన ప్రాక్టికల్ ప్రశ్నలు & గేట్ ఎగ్జామ్ కాన్సెప్ట్స్.
కంప్యూటర్ RAM (Random Access Memory) ని వేలాది చిన్న చిన్న బైట్ల గదులుగా ఊహించుకోండి. ప్రతి 1 బైట్ మెమరీ గదికి ఒక ప్రత్యేకమైన సంఖ్య ఉంటుంది, దానినే మెమరీ అడ్రస్ (Memory Address) అంటారు. కంప్యూటర్లలో ఈ చిరునామాలను చదవడానికి సులభంగా ఉండటానికి హెక్సాడెసిమల్ (Hexadecimal - Base 16: 0x...) ఫార్మాట్లో సూచిస్తారు.
పాయింటర్ సైజు ఆర్కిటెక్చర్ నియమం:
ఒక పాయింటర్ char* అయినా, int* అయినా, లేదా double* అయినా — అన్ని పాయింటర్ల సైజు ఒకేలా ఉంటుంది! ఎందుకంటే పాయింటర్ కేవలం మెమరీ అడ్రస్ను మాత్రమే నిల్వ చేస్తుంది.
ఆధునిక 64-బిట్ ఆపరేటింగ్ సిస్టమ్లలో పాయింటర్ సైజు ఎల్లప్పుడూ సరిగ్గా 8 బైట్లు (64 bits) ఉంటుంది! పాత 32-బిట్ సిస్టమ్లలో 4 బైట్లు (32 bits) ఉంటుంది.
#include <stdio.h>
int main() {
int age = 25;
double salary = 75000.50;
char grade = 'A';
// పాయింటర్లు
int *pAge = &age;
double *pSalary = &salary;
char *pGrade = &grade;
printf("=== వేరియబుల్స్ & వాటి మెమరీ చిరునామాలు (%p ఫార్మాట్) ===\n");
printf("age విలువ: %d | మెమరీ అడ్రస్: %p\n", age, (void*)pAge);
printf("salary విలువ: %.2f | మెమరీ అడ్రస్: %p\n", salary, (void*)pSalary);
printf("grade విలువ: %c | మెమరీ అడ్రస్: %p\n", grade, (void*)pGrade);
printf("\n=== అన్ని రకాల పాయింటర్ల మెమరీ సైజు (sizeof) ===\n");
printf("sizeof(int*) = %zu బైట్లు\n", sizeof(pAge));
printf("sizeof(double*) = %zu బైట్లు\n", sizeof(pSalary));
printf("sizeof(char*) = %zu బైట్లు\n", sizeof(pGrade));
return 0;
}
పాయింటర్ల ప్రపంచంలో మొత్తం నియంత్రణ కేవలం రెండే రెండు ఆపరేటర్ల చేతుల్లో ఉంటుంది:
1. & ఆపరేటర్ (Address-Of)
ఒక సాధారణ వేరియబుల్ ముందు & ఉంచితే, అది ఆ వేరియబుల్ ఉన్న మెమరీ చిరునామాను అందిస్తుంది. (ఉదా: &x ➔ 0x7ffee1b2c458).
2. * ఆపరేటర్ (Dereference / Value-At)
ఒక పాయింటర్ వేరియబుల్ ముందు * ఉంచితే, అది ఆ చిరునామా లోపలికి నేరుగా వెళ్లి అక్కడ ఉన్న అసలైన విలువను చదవడానికి లేదా మార్చడానికి అనుమతిస్తుంది.
#include <stdio.h>
int main() {
int target = 100;
int *ptr = ⌖ // ptr ఇప్పుడు target యొక్క మెమరీ అడ్రస్ ని పట్టుకుంది
printf("ప్రారంభ విలువ: target = %d\n", target);
// *ptr ద్వారా అసలైన వేరియబుల్ లోని విలువను సవరిస్తున్నాం!
*ptr = 250;
printf("సవరించిన తర్వాత: target = %d (మారిపోయింది!)\n", target);
printf("పాయింటర్ ద్వారా చదివిన విలువ: *ptr = %d\n", *ptr);
return 0;
}
చాలా మంది కొత్త ప్రోగ్రామర్లకు ఆశ్చర్యం కలిగించే అంశం ఇది: సాధారణ సంఖ్యలకు 1 కలిపితే 1 పెరుగుతుంది. కానీ పాయింటర్కు 1 కలిపితే (ptr + 1) అది 1 బైట్ పెరగదు!
ది స్కేల్ ఫ్యాక్టర్ ఫార్ములా (Scale Factor Formula):
పాయింటర్ అరిథ్మెటిక్ ఎల్లప్పుడూ ఆ పాయింటర్ పాయింట్ చేస్తున్న డేటా టైప్ పరిమాణం (Data Type Size) ఆధారంగా స్కేల్ అవుతుంది:
$$ ext{New Address} = ext{Current Address} + Big( n imes ext{sizeof(DataType)} Big)$$char *p; p + 1➔ అడ్రస్ సరిగ్గా 1 బైట్ పెరుగుతుంది (sizeof(char) = 1).int *p; p + 1➔ అడ్రస్ సరిగ్గా 4 బైట్లు ముందుకు దూకుతుంది (sizeof(int) = 4).double *p; p + 1➔ అడ్రస్ సరిగ్గా 8 బైట్లు ముందుకు దూకుతుంది (sizeof(double) = 8).
#include <stdio.h>
int main() {
int arr[3] = {10, 20, 30};
int *p = &arr[0]; // మొదటి ఎలిమెంట్ అడ్రస్
printf("ప్రారంభ అడ్రస్ p = %p (arr[0] = %d)\n", (void*)p, *p);
p = p + 1; // 4 బైట్లు ముందుకు దూకుతుంది!
printf("p + 1 తర్వాత అడ్రస్ p = %p (arr[1] = %d)\n", (void*)p, *p);
p = p + 1; // మరో 4 బైట్లు ముందుకు దూకుతుంది!
printf("p + 1 తర్వాత అడ్రస్ p = %p (arr[2] = %d)\n", (void*)p, *p);
return 0;
}
C లో రెండు పాయింటర్లను కూడటం (Addition: p1 + p2) చట్టవిరుద్ధం, ఎందుకంటే రెండు మెమరీ అడ్రస్లను కూడితే వచ్చే చిరునామాకు ఏ అర్థం ఉండదు. కానీ రెండు పాయింటర్లను తీసివేయడం (Subtraction: p2 - p1) ఖచ్చితంగా చెల్లుతుంది!
ptrdiff_t అనే స్పెషల్ ఇంటిజర్ టైప్లో నిల్వ చేస్తారు.
#include <stdio.h>
#include <stddef.h>
int main() {
int numbers[] = {100, 200, 300, 400, 500};
int *ptrStart = &numbers[0]; // ఇండెక్స్ 0
int *ptrEnd = &numbers[4]; // ఇండెక్స్ 4
// రెండు పాయింటర్ల మధ్య దూరం
ptrdiff_t diff = ptrEnd - ptrStart;
printf("ptrStart అడ్రస్: %p\n", (void*)ptrStart);
printf("ptrEnd అడ్రస్ : %p\n", (void*)ptrEnd);
printf("రెండు పాయింటర్ల మధ్య ఎలిమెంట్స్ సంఖ్య: %td\n", diff);
return 0;
}
C ప్రోగ్రామింగ్లో కనిపించే వివిధ రకాల పాయింటర్ల సమగ్ర విశ్లేషణ:
| పాయింటర్ రకం | నిర్వచనం / అర్థం | ప్రవర్తన / లక్షణం | భద్రతా స్థితి |
|---|---|---|---|
| సాధారణ పాయింటర్ (Typed Pointer) | నిర్దిష్ట డేటా టైప్కు చెందిన అడ్రస్ పట్టుకుంటుంది (ఉదా: int*). |
స్కేల్ ఫ్యాక్టర్ ప్రకారం అరిథ్మెటిక్ నడుస్తుంది. | ✅ సురక్షితమైనది |
| NULL పాయింటర్ | ఎటువంటి చెల్లుబాటు అయ్యే మెమరీకి పాయింట్ చేయదు (ptr = NULL;). |
సురక్షితమైన గ్రౌండింగ్; డిరిఫరెన్స్ చేయకూడదు. | ✅ అత్యంత సురక్షితం |
| Void పాయింటర్ (Generic) | ఏ డేటా టైప్ అడ్రస్నైనా పట్టుకునే సార్వత్రిక పాయింటర్ (void*). |
డిరిఫరెన్స్ చేయడానికి టైప్ కాస్టింగ్ తప్పనిసరి. | ✅ జాగ్రత్తగా వాడాలి |
| వైల్డ్ పాయింటర్ (Wild Pointer) | ఇనిషియలైజ్ చేయకుండా వదిలేసిన పాయింటర్ (Garbage address). | ఏ అడ్రస్ కి వెళ్తుందో తెలీక మెమరీ క్రాష్ చేస్తుంది. | 🚨 అత్యంత ప్రమాదకరం! |
| డాంగ్లింగ్ పాయింటర్ (Dangling) | మెమరీ డిలీట్ అయిన తర్వాత కూడా ఆ పాత అడ్రస్నే పట్టుకున్న పాయింటర్. | యూజ్-ఆఫ్టర్-ఫ్రీ (Use-After-Free) సెక్యూరిటీ బగ్. | 🚨 అత్యంత ప్రమాదకరం! |
void* పాయింటర్ అనేది C లో ఒక సూపర్ పవర్ లాంటిది. దీనికి ఎటువంటి నిర్దిష్ట డేటా టైప్ ఉండదు. ఇది int, float, char లేదా ఏ స్ట్రక్చర్ అడ్రస్నైనా తనలో నిల్వ చేసుకోగలదు! సిస్టమ్ లైబ్రరీలలో మెమరీ మేనేజ్మెంట్ ఫంక్షన్లు (malloc, qsort) ఈ void* పైనే ఆధారపడి పనిచేస్తాయి.
void* పాయింట్ చేస్తున్న డేటా సైజు ఎంతో తెలియదు కాబట్టి, దానిని నేరుగా డిరిఫరెన్స్ (*ptr) చేయలేము లేదా ptr + 1 చేయలేము! దానిని ఉపయోగించే ముందు సరైన డేటా టైప్లోకి టైప్ కాస్ట్ (Typecast) చేయాలి!
#include <stdio.h>
void printValue(void *ptr, char type) {
if (type == 'i') {
// int* గా టైప్ కాస్ట్ చేసి డిరిఫరెన్స్ చేస్తున్నాం
printf("ఇంటిజర్ విలువ: %d\n", *(int*)ptr);
} else if (type == 'f') {
// float* గా టైప్ కాస్ట్
printf("ఫ్లోట్ విలువ: %.2f\n", *(float*)ptr);
} else if (type == 'c') {
// char* గా టైప్ కాస్ట్
printf("క్యారెక్టర్ విలువ: %c\n", *(char*)ptr);
}
}
int main() {
int n = 42;
float pi = 3.14159f;
char ch = 'Z';
printValue(&n, 'i');
printValue(&pi, 'f');
printValue(&ch, 'c');
return 0;
}
సైబర్ సెక్యూరిటీలో 70% కంటే ఎక్కువ సాఫ్ట్వేర్ లోపాలు తప్పుడు పాయింటర్ల వినియోగం వలనే వస్తాయి:
1. వైల్డ్ పాయింటర్ (Wild Pointer):
int *p; అని రాసి ఏ అడ్రస్ ఇవ్వకుండా వదిలేస్తే, అది గార్బేజ్ అడ్రస్ను పట్టుకుని ఉంటుంది. దానిని డిరిఫరెన్స్ చేస్తే సెగ్ఫాల్ట్ వస్తుంది. పరిష్కారం: ఎల్లప్పుడూ int *p = NULL; అని ఇనిషియలైజ్ చేయాలి.
2. డాంగ్లింగ్ పాయింటర్ (Dangling Pointer):
ఫంక్షన్ ముగిసి లోకల్ వేరియబుల్స్ నాశనమైన తర్వాత లేదా డైనమిక్ మెమరీ free() అయిన తర్వాత కూడా ఆ పాత అడ్రస్ను పట్టుకుని ఉండటం. పరిష్కారం: మెమరీ క్లియర్ కాగానే వెంటనే ptr = NULL; అని సెట్ చేయాలి.
పాయింటర్లలో const కీవర్డ్ ఎక్కడ ఉందో అనే స్థానం ఆధారంగా దాని ప్రవర్తన పూర్తిగా మారిపోతుంది. ఇంటర్వ్యూలలో అడిగే క్లాసిక్ పోలిక ఇది:
పాయింటర్ పట్టుకున్న విలువను మార్చలేము! కానీ పాయింటర్ వేరొక అడ్రస్కి మారవచ్చు.
*ptr = 50; // ❌ ERROR
ptr = &other; // ✅ OK
పాయింటర్ చిరునామా స్థిరమైనది, వేరే అడ్రస్కి మారదు! కానీ లోపల ఉన్న విలువను మార్చవచ్చు.
*ptr = 50; // ✅ OK
ptr = &other; // ❌ ERROR
ఒక పాయింటర్ కూడా RAM లో ఉండే ఒక సాధారణ వేరియబుల్ మాత్రమే. కాబట్టి పాయింటర్కు కూడా ఒక మెమరీ అడ్రస్ ఉంటుంది! ఆ పాయింటర్ యొక్క అడ్రస్ను పట్టుకునే మరొక పాయింటర్ను డబుల్ పాయింటర్ (Pointer to Pointer - **) అంటారు:
#include <stdio.h>
int main() {
int value = 777;
int *ptr1 = &value; // ptr1 -> value అడ్రస్
int **ptr2 = &ptr1; // ptr2 -> ptr1 అడ్రస్ (డబుల్ పాయింటర్!)
printf("value విలువ = %d\n", value);
printf("*ptr1 ద్వారా విలువ = %d\n", *ptr1);
printf("**ptr2 ద్వారా విలువ = %d (రెండుసార్లు డీరిఫరెన్స్!)\n", **ptr2);
return 0;
}
ఇప్పటివరకు నేర్చుకున్న పాయింటర్లు, char* బైట్-బై-బైట్ ట్రావర్సల్, మరియు హెక్సాడెసిమల్ ప్రింటింగ్ ఉపయోగించి ఒక వాస్తవ RAM మెమరీ హెక్స్ డంపర్ (Raw Memory Hex Inspector Tool) ను నిర్మిద్దాం. కంప్యూటర్ RAM లో ఏదైనా వేరియబుల్ లేదా స్ట్రింగ్ అంతర్గతంగా బైట్-బై-బైట్ ఎలా నిల్వ ఉందో కళ్లారా చూడవచ్చు:
#include <stdio.h>
// ఏ మెమరీ బ్లాక్నైనా బైట్-బై-బైట్ హెక్సాడెసిమల్లో ప్రింట్ చేసే ఇన్స్పెక్టర్
void dumpMemory(const void *startAddr, size_t numBytes) {
// 1 బైట్ చొప్పున చదవడానికి unsigned char* కి టైప్ కాస్ట్ చేస్తున్నాం
const unsigned char *bytePtr = (const unsigned char*)startAddr;
printf("====================================================\n");
printf(" RAM మెమరీ ఇన్స్పెక్టర్ (Raw Byte Hex Dumper)\n");
printf("====================================================\n");
printf("ప్రారంభ మెమరీ అడ్రస్: %p | మొత్తం బైట్లు: %zu\n", startAddr, numBytes);
printf("----------------------------------------------------\n");
printf("ఆఫ్సెట్ | మెమరీ అడ్రస్ | హెక్స్ విలువ | క్యారెక్టర్\n");
printf("----------------------------------------------------\n");
for (size_t i = 0; i < numBytes; i++) {
unsigned char b = bytePtr[i];
// ముద్రించదగిన అక్షరమా కాదా అని చెక్ చేయడం
char printable = (b >= 32 && b <= 126) ? b : '.';
printf("+%02zu | %p | 0x%02X | '%c'\n",
i, (void*)&bytePtr[i], b, printable);
}
printf("====================================================\n\n");
}
int main() {
// 1. ఒక ఇంటిజర్ వేరియబుల్ మెమరీని పరీక్షిద్దాం (Little-Endian ఆర్కిటెక్చర్)
int secretCode = 0x12345678;
printf("1. ఇంటిజర్ వేరియబుల్ RAM లేఅవుట్ (0x12345678):\n");
dumpMemory(&secretCode, sizeof(secretCode));
// 2. ఒక స్ట్రింగ్ మెమరీ లేఅవుట్ను పరీక్షిద్దాం
char message[] = "Mana C 2026";
printf("2. స్ట్రింగ్ వేరియబుల్ RAM లేఅవుట్ ("Mana C 2026"):\n");
dumpMemory(message, sizeof(message));
return 0;
}
int *p; *p = 10; అని రాస్తే గార్బేజ్ అడ్రస్లోకి రాతలు రాసి ఆపరేటింగ్ సిస్టమ్ సెగ్మెంటేషన్ ఫాల్ట్ ఇస్తుంది. ఎల్లప్పుడూ ఒక వేరియబుల్ అడ్రస్ లేదా NULL ఇవ్వాలి.
p = 10; అని రాస్తే పాయింటర్ అడ్రస్ 10 అయిపోతుంది! లోపల ఉన్న విలువను మార్చడానికి కచ్చితంగా *p = 10; అని రాయాలి.
void *p; printf("%d", *p); కంపైలర్ ఎర్రర్ ఇస్తుంది. కచ్చితంగా *(int*)p అని టైప్ కాస్ట్ చేయాలి.
*ptr++ రాస్తే పాయింటర్ అడ్రస్ పెరుగుతుంది; లోపల విలువను పెంచడానికి (*ptr)++ అని బ్రాకెట్లు వాడాలి.
double d = 5.5; int *p = &d; అని రాస్తే 4 బైట్లు మాత్రమే చదివి డేటా పూర్తిగా కరప్ట్ అవుతుంది!
ఈ పాఠంలోని లోతైన అంశాలను క్రింది 5 ప్రాక్టికల్ ప్రశ్నల ద్వారా పరీక్షించుకోండి:
❓ ప్రశ్న 1: 64-బిట్ కంప్యూటర్లో char* మరియు double* పాయింటర్ల మెమరీ సైజు ఎంత ఉంటుంది?
❓ ప్రశ్న 2: int *ptr ఉన్నప్పుడు 'ptr + 1' చేస్తే అడ్రస్ ఎన్ని బైట్లు పెరుగుతుంది?
❓ ప్రశ్న 3: void* పాయింటర్ను నేరుగా డిరిఫరెన్స్ చేయవచ్చా?
*(int*)ptr) టైప్ కాస్ట్ చేసిన తర్వాతే డిరిఫరెన్స్ చేయాలి.
❓ ప్రశ్న 4: వైల్డ్ పాయింటర్ (Wild Pointer) మరియు డాంగ్లింగ్ పాయింటర్ (Dangling Pointer) మధ్య తేడా ఏమిటి?
❓ ప్రశ్న 5: 'const int *p' మరియు 'int * const p' ల మధ్య తేడా ఏమిటి?
const int *p లో విలువను మార్చలేము (రీడ్-ఓన్లీ డేటా); int * const p లో చిరునామాను మార్చలేము (స్థిరమైన పాయింటర్).
పైన వివరించిన RAM మెమరీ హెక్స్ ఇన్స్పెక్టర్ మరియు పాయింటర్ అరిథ్మెటిక్ కోడ్లను మన ఆన్లైన్ C కంపైలర్లో ఓపెన్ చేసి స్వయంగా రన్ చేయండి. మీ వేరియబుల్స్ మెమరీలో బైట్-బై-బైట్ ఎలా స్టోర్ అయ్యాయో కళ్లారా చూడండి!
📌 అధ్యాయ సారాంశం (Quick Summary):
- పాయింటర్లు: మెమరీ చిరునామాలను నిల్వ చేసే ప్రత్యేక వేరియబుల్స్ (64-బిట్ లో 8 బైట్లు).
- & ఆపరేటర్: వేరియబుల్ ఉన్న మెమరీ అడ్రస్ను అందిస్తుంది.
- * ఆపరేటర్: పాయింటర్ అడ్రస్ లోపలికి వెళ్లి విలువను చదవడానికి/మార్చడానికి డిరిఫరెన్స్ చేస్తుంది.
- స్కేల్ ఫ్యాక్టర్:
ptr + 1అంటే 1 బైట్ కాదు, ఆ డేటా టైప్ పరిమాణం మేర ముందుకు దూకుతుంది. - void*: ఏ డేటా టైప్ నైనా పట్టుకునే సార్వత్రిక జెనెరిక్ పాయింటర్.