C లూప్స్ (while, do-while, for) & ఇటరేషన్ సైకిల్
ఒక వ్యాయామశాలలో (Gym) లేదా రన్నింగ్ ట్రాక్లో కోచ్ మిమ్మల్ని "మైదానం చుట్టూ సరిగ్గా 10 రౌండ్లు పరిగెత్తండి" అని ఆదేశించారనుకుందాం. మీరు ఏం చేస్తారు? మొదటి రౌండ్ ప్రారంభించే ముందు మీ మైండ్లో ల్యాప్ కౌంటర్ను సున్నాకి (0) సెట్ చేసుకుంటారు. ప్రతి రౌండ్ పూర్తయిన తర్వాత కౌంటర్ను 1 పెంచుతారు (1, 2, 3...). 10 రౌండ్లు ముగియగానే అలసటతో పరుగు ఆపేసి విశ్రాంతి తీసుకుంటారు. ఈ ప్రక్రియలో మూడు కీలక అంశాలున్నాయి: ఎక్కడ మొదలుపెట్టాలి? ఎప్పుడు ఆపాలి? ప్రతి అడుగులో లెక్కింపును ఎలా పెంచాలి?
కంప్యూటర్ సైన్స్లో ఈ పునరావృత చర్యనే లూపింగ్ (Looping) లేదా ఇటరేషన్ (Iteration) అంటారు. మనుషులమైన మనం ఒకే పనిని వంద సార్లు చేయాలంటే విసుగు చెందుతాం, అలసిపోతాం, మధ్యలో లెక్క తప్పి తప్పులు చేస్తాం. కానీ సిలికాన్ ప్రాసెసర్లు ఒకే పనిని సెకనుకు కోట్లాది సార్లు నానోసెకన్ల వేగంతో, బొత్తిగా అలసట లేకుండా, మైక్రోస్కోపిక్ ఖచ్చితత్వంతో పునరావృతం చేయగలవు!
ఈ ఏడవ అధ్యాయంలో, C లాంగ్వేజ్లోని మూడు ప్రధాన లూపింగ్ ఆయుధాలు: while, do-while, మరియు for లూప్ల అంతర్గత నిర్మాణం, వాటి 4-దశల ఎగ్జిక్యూషన్ చక్రం (Execution Lifecycle), కంపైలర్ లెవల్ లూప్ అన్రోలింగ్ (Loop Unrolling), మరియు ప్రమాదకరమైన ఆఫ్-బై-వన్ (Off-by-One) ఎర్రర్లను నివారించే సీక్రెట్లను లోతుగా అన్వేషిద్దాం!
కంట్రోల్ ఫ్లో ప్రోగ్రామింగ్లో లూప్స్ అనేవి గుండెకాయ వంటివి. డేటాను ప్రాసెస్ చేయాలన్నా, ఫైళ్లను చదవాలన్నా, గ్రాఫిక్స్ రెండర్ చేయాలన్నా లూప్స్ లేకుండా ఏ కంప్యూటర్ సాఫ్ట్వేర్ పనిచేయదు. ఈ పాఠంలో కవర్ చేయబడే సమగ్ర అంశాలు:
- లూపింగ్ ప్రాథమిక ఆవశ్యకత: కోడ్ డూప్లికేషన్ (DRY - Don't Repeat Yourself) నివారణ మరియు మెమరీ పొదుపు.
- లూప్ 4-దశల లైఫ్సైకిల్: Initialization, Condition Evaluation, Body Execution, మరియు Update/Step Expression.
- while లూప్ (Entry-Controlled): కండిషన్ ట్రూ అయితేనే లోపలికి అనుమతించే సెక్యూరిటీ గార్డ్ ఆర్కిటెక్చర్.
- do-while లూప్ (Exit-Controlled): కండిషన్ ఫాల్స్ అయినా కనీసం ఒక్కసారైనా రన్ అయ్యే గ్యారెంటీడ్ మోడల్.
- for లూప్ (Compact Iteration): 3 ఎక్స్ప్రెషన్లు ఒకే లైన్లో ఉండే క్లీన్ ఇంజనీరింగ్ డిజైన్.
- C99 వేరియబుల్ స్కోపింగ్:
for (int i = 0; ...)ద్వారా లూప్ లోపల వేరియబుల్స్ ఐసొలేట్ చేయడం. - తులనాత్మక విశ్లేషణ పట్టిక: for vs while vs do-while - ఏ సందర్భంలో దేనిని ఎంచుకోవాలి?
- ఇన్ఫినిట్ లూప్స్ (Infinite Loops):
while(1),for(;;)ఎప్పుడు వాడాలి? CPU 100% స్టాల్ అవ్వకుండా ఎలా ఆపాలి? - ఆఫ్-బై-వన్ (Off-by-One / Fencepost) బగ్స్: ప్రపంచ ప్రసిద్ధ సాఫ్ట్వేర్ క్రాష్లకు కారణమయ్యే
<vs<=పొరపాట్లు. - ప్రీ-ఇంక్రిమెంట్ (++i) vs పోస్ట్-ఇంక్రిమెంట్ (i++): లూప్ హెడర్లో ఏది వేగవంతమైనది?
- కంపైలర్ ఆప్టిమైజేషన్స్: లూప్ అన్రోలింగ్ (Loop Unrolling) మరియు బ్రాంచ్ ప్రిడిక్షన్ (Branch Prediction).
- రియల్ వరల్డ్ ప్రాజెక్ట్ 1: 3-స్టెప్ ATM పిన్ వాలిడేషన్ & ఖాతా తాత్కాలిక లాకౌట్ సిస్టమ్.
- రియల్ వరల్డ్ ప్రాజెక్ట్ 2: ఫైనాన్షియల్ కాంపౌండ్ ఇంట్రెస్ట్ ప్రొజెక్షన్ టేబుల్ జనరేటర్.
- ఇంటరాక్టివ్ స్వీయ మూల్యాంకన క్విజ్: 5 లోతైన విశ్లేషణాత్మక ప్రశ్నలు & ఎగ్జామ్ కాన్సెప్ట్స్.
C లాంగ్వేజ్లో మీరు ఏ లూప్ రాసినా (అది while అయినా, do-while అయినా, లేదా for అయినా) ప్రతి లూప్ కచ్చితంగా 4 కీలక దశలను (Four Core Phases) కలిగి ఉంటుంది. ఈ నాలుగు దశలలో ఏ ఒక్కటి లోపించినా, మీ ప్రోగ్రామ్ విఫలమవ్వడమో లేదా నిరంతరం తిరుగుతూ కంప్యూటర్ను హ్యాంగ్ చేయడమో జరుగుతుంది!
1. ఇనిషియలైజేషన్ (Initialization)
లూప్ కౌంటర్ వేరియబుల్కు ప్రారంభ విలువను ఇవ్వడం (ఉదా: int count = 1;). ఇది పరుగు ఎక్కడి నుండి మొదలవుతుందో నిర్దేశిస్తుంది.
2. కండిషన్ చెక్ (Condition Test)
లూప్ కొనసాగాలా లేదా ఆగిపోవాలా అని నిర్ణయించే బూలియన్ టెస్ట్ (ఉదా: count <= 10;). ఇది ట్రూ (non-zero) అయితేనే లూప్ బాడీ రన్ అవుతుంది.
3. లూప్ బాడీ (Body Execution)
కండిషన్ నెరవేరిన ప్రతిసారీ ఎగ్జిక్యూట్ అయ్యే అసలైన స్టేట్మెంట్లు (ఉదా: డేటాను ప్రింట్ చేయడం, కాలిక్యులేషన్ చేయడం).
4. అప్డేట్ / స్టెప్ (Increment/Decrement)
కౌంటర్ వేరియబుల్ను ముగింపు వైపుకు నడిపించే దశ (ఉదా: count++). ఇది లేకపోతే లూప్ ఎప్పటికీ ముగియక ఇన్ఫినిట్ లూప్గా మారుతుంది.
while లూప్ అనేది C లాంగ్వేజ్లోని అత్యంత ప్రాథమికమైన లూప్. దీనిని ఎంట్రీ-కంట్రోల్డ్ లూప్ (Entry-Controlled Loop) అంటారు. ఎందుకంటే లూప్ బాడీ లోపలికి ప్రవేశించే ముందే మెయిన్ గేటు వద్ద సెక్యూరిటీ గార్డులా కండిషన్ను తనిఖీ చేస్తుంది. కండిషన్ ట్రూ అయితేనే లోపలికి అనుమతిస్తుంది; మొదటి ప్రయత్నంలోనే కండిషన్ ఫాల్స్ అయితే, లూప్ బాడీ జీరో సార్లు (సున్నా సార్లు) రన్ అవుతుంది!
సింటాక్స్:
while (కండిషన్) {
// లూప్ బాడీ (స్టేట్మెంట్స్)
అప్డేట్_ఎక్స్ప్రెషన్;
}
క్రింది ఉదాహరణలో 1 నుండి 5 వరకు సంఖ్యలను ప్రింట్ చేసే సింపుల్ while లూప్ను గమనించండి:
#include <stdio.h>
int main() {
int i = 1; // 1. Initialization
printf("--- while లూప్ ప్రారంభం ---\n");
while (i <= 5) { // 2. Condition Test
printf("కౌంటర్ విలువ: %d\n", i); // 3. Body Execution
i++; // 4. Update / Increment
}
printf("--- లూప్ ముగిసింది. తుది విలువ i = %d ---\n", i);
return 0;
}
లూప్ మొదట
i = 1 తో స్టార్ట్ అవుతుంది. 1 <= 5 ట్రూ కాబట్టి 1 ప్రింట్ అవుతుంది, i విలువ 2 అవుతుంది. ఇలా 5 వరకు ప్రింట్ అయిన తర్వాత, i++ జరిగి i = 6 అవుతుంది. అప్పుడు 6 <= 5 ఫాల్స్ అయి లూప్ నుండి కంట్రోల్ బయటకు వస్తుంది. అందుకే లూప్ బయట i విలువ సరిగ్గా 6 ఉంటుంది!
do-while లూప్ అనేది while లూప్కు ఖచ్చితమైన వ్యతిరేకమైనది. దీనిని ఎగ్జిట్-కంట్రోల్డ్ లూప్ (Exit-Controlled Loop) అంటారు. ఇందులో కండిషన్ చెక్ అనేది లూప్ చివరన జరుగుతుంది. దీని అర్థం ఏమిటంటే:
కండిషన్ మొదటిసారే పూర్తిగా ఫాల్స్ (False) అయినప్పటికీ, లూప్ బాడీ కచ్చితంగా కనీసం ఒక్కసారైనా (At least once) ఎగ్జిక్యూట్ అవుతుంది!
సింటాక్స్ & సెమికోలన్ హెచ్చరిక:
do {
// లూప్ బాడీ
అప్డేట్_ఎక్స్ప్రెషన్;
} while (కండిషన్); // <-- ఇక్కడ సెమికోలన్ (;) తప్పనిసరి!
while లూప్ హెడర్ పక్కన సెమికోలన్ పెట్టకూడదు, కానీ do-while లూప్ చివరన ఉన్న while(...); పక్కన కచ్చితంగా సెమికోలన్ ఉండాలి! సెమికోలన్ మర్చిపోతే GCC expected ';' before '}' అనే సింటాక్స్ ఎర్రర్ విసురుతుంది.
క్రింది ఉదాహరణలో కండిషన్ score > 100 అనేది మొదటి నుంచే ఫాల్స్. అయినా బాడీ ఎలా రన్ అవుతుందో చూడండి:
#include <stdio.h>
int main() {
int score = 50;
printf("do-while లోపలికి ప్రవేశిస్తున్నాం...\n");
do {
printf("ఈ మెసేజ్ కనీసం ఒక్కసారైనా ప్రింట్ అవుతుంది! Current score = %d\n", score);
score += 10;
} while (score > 100); // 60 > 100 అనేది FALSE!
printf("do-while ముగిసింది! Condition ఫాల్స్ అయినా బాడీ ఒక్కసారి రన్ అయింది.\n");
return 0;
}
రియల్ వరల్డ్ ప్రాక్టికల్ అప్లికేషన్:
సాఫ్ట్వేర్ ఇంజనీరింగ్లో యూజర్ ఇన్పుట్ వాలిడేషన్ మరియు ఇంటరాక్టివ్ మెనూలు రూపొందించడానికి do-while సర్వోత్తమమైనది. ఎందుకంటే యూజర్కు ముందుగా మెనూ లేదా ప్రాంప్ట్ చూపించాలి, తర్వాతే యూజర్ ఇచ్చిన ఇన్పుట్ సరైనదా కాదా అని లూప్ కండిషన్లో చెక్ చేయాలి!
C లాంగ్వేజ్లో అత్యంత ఎక్కువగా వాడబడే లూప్ for లూప్. ఎందుకంటే లూప్కు అవసరమైన 3 ముఖ్యమైన దశలను (ఇనిషియలైజేషన్, కండిషన్, అప్డేట్) ఒకే బ్రాకెట్ లోపల కాంపాక్ట్గా అమర్చుకునే అద్భుతమైన సౌలభ్యం ഇതിൽ ఉంది!
for లూప్ అనాటమీ & ఎగ్జిక్యూషన్ ఆర్డర్:
// దశ 3: లూప్ బాడీ
}
CPU ఎగ్జిక్యూషన్ క్రమం (Exact Micro-Order):
- Step 1 (ఇనిషియలైజేషన్): లూప్ ప్రారంభంలో కేవలం ఒక్కసారి మాత్రమే జరుగుతుంది.
- Step 2 (కండిషన్ చెక్): కండిషన్ ట్రూ అయితే Step 3 కి వెళ్తుంది. ఫాల్స్ అయితే వెంటనే లూప్ ముగుస్తుంది.
- Step 3 (బాడీ ఎగ్జిక్యూషన్): కర్లీ బ్రేసెస్ లోపల ఉన్న స్టేట్మెంట్లు ఎగ్జిక్యూట్ అవుతాయి.
- Step 4 (అప్డేట్): కౌంటర్ వేరియబుల్ ఇంక్రిమెంట్ లేదా డిక్రిమెంట్ అవుతుంది.
- ఇప్పుడు మళ్లీ Step 2 కి తిరిగి వెళ్లి కండిషన్ చెక్ చేస్తుంది. లూప్ ముగిసే వరకు Step 2 ➔ Step 3 ➔ Step 4 చక్రీయంగా తిరుగుతాయి!
#include <stdio.h>
int main() {
int n = 7; // 7వ ఎక్కం (Table of 7)
printf("=== 7వ ఎక్కం (7 Table using for loop) ===\n");
for (int i = 1; i <= 10; i++) {
printf("%d x %2d = %2d\n", n, i, n * i);
}
return 0;
}
C99 వేరియబుల్ స్కోపింగ్ (Block Scope in for Loops):
పాత C89 స్టాండర్డ్లో లూప్ కౌంటర్ వేరియబుల్ను ఫంక్షన్ మొదట్లోనే డిక్లేర్ చేయాల్సి వచ్చేది. కానీ ఆధునిక C99 / C11 / C17 స్టాండర్డ్స్ ప్రకారం, for (int i = 0; ...) లాగా నేరుగా లూప్ హెడర్లోనే వేరియబుల్ను డిక్లేర్ చేయవచ్చు. దీనివలన ఆ వేరియబుల్ కేవలం ఆ లూప్ లోపల మాత్రమే బ్రతుకుతుంది (Block Scope), లూప్ బయట వేరే వేరియబుల్స్తో ఘర్షణ పడదు (No Namespace Pollution)!
ఏ సందర్భంలో ఏ లూప్ వాడాలి? అనేది ప్రతి కొత్త ప్రోగ్రామర్ను వేధించే అతిపెద్ద సందేహం. ఈ క్రింది సమగ్ర పట్టికను పరిశీలించండి:
| ఫీచర్ / అంశం | while లూప్ | do-while లూప్ | for లూప్ |
|---|---|---|---|
| కంట్రోల్ రకం | ఎంట్రీ-కంట్రోల్డ్ (Entry-Controlled) | ఎగ్జిట్-కంట్రోల్డ్ (Exit-Controlled) | ఎంట్రీ-కంట్రోల్డ్ (Entry-Controlled) |
| మినిమం ఎగ్జిక్యూషన్స్ | 0 సార్లు (కండిషన్ ఫాల్స్ అయితే) | కనీసం 1 సారి (గ్యారెంటీడ్) | 0 సార్లు (కండిషన్ ఫాల్స్ అయితే) |
| సింటాక్స్ స్ట్రక్చర్ | ఇనిషియలైజేషన్, కండిషన్, అప్డేట్ విడివిడిగా ఉంటాయి | చివరన while(...); సెమికోలన్ ఉంటుంది |
అన్నీ ఒకే హెడర్ బ్రాకెట్ లోపల కాంపాక్ట్గా ఉంటాయి |
| ఉత్తమ వినియోగ సందర్భం | ఇటరేషన్ల సంఖ్య ముందే తెలియనప్పుడు (ఉదా: ఫైల్ రీడింగ్, సెన్సార్ డేటా) | యూజర్ ఇన్పుట్ వాలిడేషన్ & కన్సోల్ మెనూ ఎంపికలు | ఇటరేషన్ల సంఖ్య ముందే స్పష్టంగా తెలిసినప్పుడు (ఉదా: 1 నుండి 100 వరకు) |
| రీడబిలిటీ | మధ్యస్థం (అప్డేట్ మర్చిపోయే అవకాశం ఉంది) | మధ్యస్థం | చాలా ఎక్కువ & క్లీన్ స్ట్రక్చర్ |
ఒక లూప్ యొక్క కండిషన్ ఎప్పటికీ ఫాల్స్ కాకపోతే, ఆ లూప్ అంతం లేకుండా నిరంతరం రన్ అవుతూనే ఉంటుంది. దీనినే ఇన్ఫినిట్ లూప్ (Infinite Loop) అంటారు. సాధారణంగా అనుభవం లేని బిగినర్స్ పొరపాటున ఇన్ఫినిట్ లూప్స్ సృష్టించి తమ ప్రోగ్రామ్లను క్రాష్ చేస్తుంటారు.
ఇన్ఫినిట్ లూప్స్ ఎలా ఏర్పడతాయి?
while (1) {
// ఎప్పటికీ ఆగదు, 1 ఎల్లప్పుడూ TRUE!
}
// పద్ధతి 2: for తో అనంత లూప్ (అన్ని ఎక్స్ప్రెషన్లు ఖాళీగా వదిలేస్తే)
for (;;) {
// ఇది కూడా ఇన్ఫినిట్ లూప్!
}
ఇన్ఫినిట్ లూప్స్ సాఫ్ట్వేర్ ఇంజనీరింగ్లో నిజంగా అవసరమా?
అవును! ఆపరేటింగ్ సిస్టమ్ల కెర్నల్స్ (OS Event Loops), మైక్రోకంట్రోలర్లు (Arduino/Embedded Systems లో while(1)), వెబ్ సర్వర్లు (రెక్వెస్ట్ల కోసం వేచి ఉండే లిజనర్లు), మరియు వీడియో గేమ్ల రెండరింగ్ లూప్స్ అన్నీ ఇన్ఫినిట్ లూప్స్ పైనే నడుస్తాయి. అయితే, వాటిలో కచ్చితంగా యూజర్ 'Quit' బటన్ నొక్కినప్పుడు బయటపడటానికి break స్టేట్మెంట్ అమర్చబడి ఉంటుంది!
#include <stdio.h>
int main() {
int num, sum = 0;
printf("=== సంఖ్యల కూడిక (ఆపడానికి -1 ఎంటర్ చేయండి) ===\n");
while (1) { // కంట్రోల్డ్ ఇన్ఫినిట్ లూప్
printf("ఒక సంఖ్యను ఎంటర్ చేయండి: ");
scanf("%d", &num);
if (num == -1) {
printf("సెంటినెల్ విలువ (-1) గుర్తించబడింది. లూప్ నుండి బయటకు వస్తున్నాం...\n");
break; // లూప్ నుండి తక్షణ నిష్క్రమణ!
}
sum += num;
printf("ప్రస్తుత మొత్తం (Current Sum): %d\n", sum);
}
printf("తుది మొత్తం: %d\n", sum);
return 0;
}
ప్రపంచవ్యాప్తంగా సీనియర్ సాఫ్ట్వేర్ ఇంజనీర్లు సైతం తరచుగా చేసే అత్యంత మోసపూరితమైన తప్పు ఆఫ్-బై-వన్ బగ్ (Off-by-One Error - OBOE). ఒక పనిని అనుకున్నదానికంటే సరిగ్గా ఒక్కసారి తక్కువగానో లేదా ఒక్కసారి ఎక్కువగానో రన్ చేయడమే ఈ బగ్!
ది ఫెన్స్పోస్ట్ ఎనాలజీ (The Fencepost Metaphor):
మీ ఇంటి చుట్టూ 10 మీటర్ల కంచె వేయాలనుకుంటున్నారు. ప్రతి 1 మీటరుకు ఒక స్తంభం (Post) పాతి వాటి మధ్య తీగ కట్టాలి. మీకు ఎన్ని స్తంభాలు కావాలి? సహజంగా చాలామంది వెంటనే "10 స్తంభాలు" అంటారు. కానీ వాస్తవానికి మీకు 11 స్తంభాలు కావాలి! (మొదటి స్తంభం 0 మీటర్ల వద్ద, 10వ మీటరు వద్ద చివరి స్తంభం). స్తంభాల సంఖ్య వేరు, మధ్యలోని ఖాళీల (Sections) సంఖ్య వేరు. లూప్స్లో < మరియు <= మధ్య తేడాను సరిగ్గా అర్థం చేసుకోకపోతే ఈ ఫెన్స్పోస్ట్ సమస్య వస్తుంది!
| లూప్ కండిషన్ | ఎగ్జిక్యూట్ అయ్యే సంఖ్యలు | మొత్తం ఇటరేషన్లు | ఫలితం / ప్రమాదం |
|---|---|---|---|
for (int i = 0; i < 5; i++) |
0, 1, 2, 3, 4 | 5 సార్లు | ఆదర్శవంతమైన C అర్రే ఇండెక్సింగ్! (0 నుండి N-1) |
for (int i = 0; i <= 5; i++) |
0, 1, 2, 3, 4, 5 | 6 సార్లు | అర్రే సైజ్ 5 అయితే, 5వ ఇండెక్స్ మెమరీ క్రాష్కు దారితీస్తుంది! |
for (int i = 1; i <= 5; i++) |
1, 2, 3, 4, 5 | 5 సార్లు | సాధారణ లెక్కింపులకు సరైనది (1 నుండి N వరకు) |
for (int i = 1; i < 5; i++) |
1, 2, 3, 4 | 4 సార్లు | 5వ విలువ మిస్ అవుతుంది (1 సారి తక్కువ)! |
చాలామంది ప్రోగ్రామర్లలో ఒక ఆసక్తికరమైన ప్రశ్న ఉంటుంది: "for లూప్ హెడర్లో i++ వాడాలా లేక ++i వాడాలా? రెండింటి మధ్య పనితీరులో (Performance) ఏమైనా తేడా ఉందా?"
// స్టైల్ 1: పోస్ట్-ఇంక్రిమెంట్
for (int i = 0; i < 5; i++) {
printf("%d ", i); // అవుట్పుట్: 0 1 2 3 4
}
// స్టైల్ 2: ప్రీ-ఇంక్రిమెంట్
for (int i = 0; i < 5; ++i) {
printf("%d ", i); // అవుట్పుట్: 0 1 2 3 4
}
వాస్తవ ఇంజనీరింగ్ సమాధానం:
ప్రాథమిక C డేటా టైప్స్ (int, char) విషయంలో: ఒక స్వతంత్ర స్టేట్మెంట్గా రన్ అయినప్పుడు i++ మరియు ++i రెండూ ఒకే ఒక్క అసెంబ్లీ ఇన్స్ట్రక్షన్ INC [i] లేదా add $1, %eax గా కంపైల్ అవుతాయి. కాబట్టి పనితీరులో 0% వ్యత్యాసం ఉంటుంది, రెండూ ఒకే వేగంతో రన్ అవుతాయి! లూప్ బాడీ ముగిసిన తర్వాతే ఈ అప్డేట్ జరుగుతుంది కాబట్టి లూప్ ఇటరేషన్ల సంఖ్యలో ఎలాంటి మార్పు ఉండదు.
ఆధునిక కంపైలర్లు (GCC, Clang) లూప్లను ఎలా ఆప్టిమైజ్ చేస్తాయో తెలుసుకోవడం ప్రొఫెషనల్ ఇంజనీరింగ్కు ఎంతో అవసరం. లూప్ ప్రతి ఇటరేషన్లోనూ CPU కండిషన్ను తనిఖీ చేసి మెమరీ జంప్ (JMP instruction) చేయాల్సి ఉంటుంది. ఇది బ్రాంచ్ ప్రిడిక్షన్ మిస్ అయితే సమయం వృధా అవుతుంది.
లూప్ అన్రోలింగ్ (Loop Unrolling) అంటే ఏమిటి?
ఇటరేషన్ల సంఖ్య తక్కువగా ఉన్నప్పుడు, కంపైలర్ లూప్ ఓవర్హెడ్ను తగ్గించడానికి లూప్ బాడీని వరుసగా కాపీ చేసి ఎగ్జిక్యూట్ చేస్తుంది. ఉదాహరణకు:
for (int i = 0; i < 4; i++) {
sum += arr[i];
}
sum += arr[0]; sum += arr[1]; sum += arr[2]; sum += arr[3];
ఇలా చేయడం ద్వారా కండిషన్ చెకింగ్ మరియు జంప్ ఇన్స్ట్రక్షన్లు పూర్తిగా తొలగిపోయి, కోడ్ అత్యధిక వేగంతో (Peak CPU throughput) ఎగ్జిక్యూట్ అవుతుంది!
ఒక నిజమైన ATM మెషీన్లో కస్టమర్ పిన్ నంబర్ నమోదు చేసే సిస్టమ్ను రూపొందిద్దాం. వినియోగదారుడికి గరిష్టంగా 3 అవకాశాలు మాత్రమే ఉంటాయి. 3 సార్లు తప్పుడు పిన్ ఎంటర్ చేస్తే ఖాతా తాత్కాలికంగా బ్లాక్ అవుతుంది. సరైన పిన్ ఇవ్వగానే తదుపరి బ్యాంకింగ్ సేవలకు అనుమతిస్తుంది. దీనికి do-while లూప్ అత్యంత సరైన ఎంపిక:
#include <stdio.h>
int main() {
const int CORRECT_PIN = 4826; // సరైన రహస్య పిన్
int enteredPin;
int attempts = 0;
const int MAX_ATTEMPTS = 3;
int authenticated = 0;
printf("=======================================\n");
printf(" మనా బ్యాంక్ ATM సర్వీసెస్ (Mana ATM)\n");
printf("=======================================\n");
do {
attempts++;
printf("\n[ప్రయత్నం %d/%d] దయచేసి మీ 4-అంకెల ATM పిన్ ఎంటర్ చేయండి: ", attempts, MAX_ATTEMPTS);
scanf("%d", &enteredPin);
if (enteredPin == CORRECT_PIN) {
authenticated = 1;
break; // సరైన పిన్ దొరికితే వెంటనే లూప్ నుండి నిష్క్రమించు
} else {
int remaining = MAX_ATTEMPTS - attempts;
if (remaining > 0) {
printf("❌ తప్పుడు పిన్! మీకు ఇంకా %d అవకాశాలు మాత్రమే ఉన్నాయి.\n", remaining);
}
}
} while (attempts < MAX_ATTEMPTS);
printf("\n---------------------------------------\n");
if (authenticated) {
printf("✅ పిన్ విజయవంతంగా ధృవీకరించబడింది!\n");
printf("🏦 వెల్కమ్! మీ ఖాతాలో బ్యాలెన్స్: రూ. 75,450.00\n");
} else {
printf("🚨 హెచ్చరిక: మీరు 3 సార్లు తప్పుడు పిన్ నమోదు చేశారు!\n");
printf("🔒 సెక్యూరిటీ కారణాల వల్ల మీ ATM కార్డ్ 24 గంటలు బ్లాక్ చేయబడింది.\n");
}
printf("=======================================\n");
return 0;
}
ఫైనాన్షియల్ ఇంజనీరింగ్లో కాంపౌండ్ ఇంట్రెస్ట్ (చక్రవడ్డీ) వార్షిక వృద్ధిని అంచనా వేసే ప్రొజెక్షన్ టేబుల్ జనరేటర్ను for లూప్ ఉపయోగించి నిర్మిద్దాం. ప్రతి సంవత్సరం వడ్డీ అసలుకు కలుస్తూ మూలధనం ఎలా పెరుగుతుందో లూప్ ద్వారా ఖచ్చితంగా లెక్కించవచ్చు:
#include <stdio.h>
int main() {
double principal = 100000.0; // ప్రారంభ పెట్టుబడి: రూ. 1,00,000
double annualRate = 12.0; // వార్షిక వడ్డీ రేటు: 12%
int totalYears = 5; // పెట్టుబడి కాలం: 5 సంవత్సరాలు
printf("====================================================\n");
printf(" కాంపౌండ్ ఇంట్రెస్ట్ ప్రొజెక్షన్ చార్ట్ (12%% వార్షిక వృద్ధి)\n");
printf("====================================================\n");
printf("%-8s | %-16s | %-14s | %-16s\n", "సంవత్సరం", "ప్రారంభ బ్యాలెన్స్", "వచ్చిన వడ్డీ", "ముగింపు బ్యాలెన్స్");
printf("----------------------------------------------------\n");
double currentBalance = principal;
for (int year = 1; year <= totalYears; year++) {
double interestEarned = currentBalance * (annualRate / 100.0);
double closingBalance = currentBalance + interestEarned;
printf("Year %-3d | రూ. %12.2f | రూ. %10.2f | రూ. %12.2f\n",
year, currentBalance, interestEarned, closingBalance);
currentBalance = closingBalance; // తర్వాతి సంవత్సరానికి ముగింపు బ్యాలెన్స్ ప్రారంభ బ్యాలెన్స్ అవుతుంది
}
printf("====================================================\n");
printf("5 సంవత్సరాల తర్వాత మొత్తం లాభం: రూ. %.2f\n", currentBalance - principal);
return 0;
}
సాధారణంగా బిగినర్స్ చేసే టాప్ 3 లూప్ తప్పులు:
- for హెడర్ చివర సెమికోలన్ పెట్టడం:
for (int i = 0; i < 5; i++);అని రాస్తే, సెమికోలన్ అక్కడితో లూప్ను ముగించేస్తుంది! కర్లీ బ్రేసెస్ లోపల ఉన్న కోడ్ లూప్ తర్వాత కేవలం ఒక్కసారి మాత్రమే రన్ అవుతుంది. - లూప్ వేరియబుల్ను అప్డేట్ చేయడం మర్చిపోవడం:
while (i < 10)రాసి లోపలi++రాయకపోతే నిరంతరం తిరుగుతూనే ఉంటుంది. - ఫ్లోటింగ్ పాయింట్ నంబర్లను లూప్ కౌంటర్లుగా వాడడం:
for (float f = 0.0; f != 1.0; f += 0.1)రాయకూడదు! ఫ్లోటింగ్ పాయింట్ ప్రెసిషన్ రౌండింగ్ ఎర్రర్స్ వలనfవిలువ ఖచ్చితంగా1.0కి సమానం కాక ఇన్ఫినిట్ లూప్గా మారే ప్రమాదం ఉంది.
ఈ పాఠంలో నేర్చుకున్న లూపింగ్ కాన్సెప్ట్లను క్రింది 5 లోతైన ప్రాక్టికల్ ప్రశ్నల ద్వారా పరీక్షించుకోండి:
❓ ప్రశ్న 1: while మరియు do-while లూప్ల మధ్య అతి ముఖ్యమైన తేడా ఏమిటి?
while అనేది ఎంట్రీ-కంట్రోల్డ్ లూప్, కండిషన్ ఫాల్స్ అయితే కనీసం ఒక్కసారి కూడా రన్ కాదు (0 సార్లు). కానీ do-while అనేది ఎగ్జిట్-కంట్రోల్డ్ లూప్, కండిషన్ ఫాల్స్ అయినా సరే కనీసం ఒక్కసారైనా గ్యారెంటీగా ఎగ్జిక్యూట్ అవుతుంది.
❓ ప్రశ్న 2: for(;;) అని రాస్తే ఏం జరుగుతుంది?
for (;;) లో మూడు భాగాలు (ఇనిషియలైజేషన్, కండిషన్, అప్డేట్) ఖాళీగా ఉన్నాయి. కండిషన్ లేనప్పుడు C కంపైలర్ దానిని శాశ్వతంగా TRUE (1) గా పరిగణిస్తుంది. కాబట్టి ఇది ఒక అనంత లూప్ (Infinite Loop) గా మారుతుంది.
❓ ప్రశ్న 3: int i = 0; while (i < 5); { printf("%d", i); i++; } ఈ కోడ్ అవుట్పుట్ ఏమిటి?
while (i < 5); చివర సెమికోలన్ ఉండటం వలన అక్కడే ఖాళీ లూప్ నిరంతరం తిరుగుతూనే ఉంటుంది. i విలువ ఎప్పటికీ పెరగదు, కర్లీ బ్రేసెస్ లోపలికి కంట్రోల్ రాదు!
❓ ప్రశ్న 4: 10 ఎలిమెంట్స్ ఉన్న C అర్రేను లూప్ చేసేటప్పుడు i < 10 వాడాలా లేక i <= 10 వాడాలా?
i < 10 వాడాలి! C లో అర్రే ఇండెక్స్ 0 నుండి ప్రారంభమై 9 వద్ద ముగుస్తుంది. i <= 10 రాస్తే 10వ ఇండెక్స్ యాక్సెస్ చేయడానికి ప్రయత్నించి ఆఫ్-బై-వన్ బగ్ (Buffer Overflow) ఏర్పడుతుంది.
❓ ప్రశ్న 5: లూప్ అన్రోలింగ్ (Loop Unrolling) వలన కలిగే ప్రధాన ప్రయోజనం ఏమిటి?
పైన వివరించిన ATM పిన్ సెక్యూరిటీ సిమ్యులేటర్ మరియు కాంపౌండ్ ఇంట్రెస్ట్ ప్రొజెక్షన్ ప్రోగ్రామ్లను మన ఆన్లైన్ C కంపైలర్లో ఓపెన్ చేసి మీ స్వంత టెస్ట్ డేటాతో రన్ చేయండి. లూప్ కండిషన్లను మార్చి ఫలితాలను గమనించండి!
📌 అధ్యాయ సారాంశం (Quick Summary):
- లూప్స్: ఒకే పనిని అలసట లేకుండా వేలసార్లు రన్ చేసే పునరావృత ఇంజిన్లు.
- 4 దశలు: Initialization, Condition Check, Body Execution, Updation.
- while: ఎంట్రీ-కంట్రోల్డ్ లూప్; కండిషన్ ట్రూ అయితేనే రన్ అవుతుంది.
- do-while: ఎగ్జిట్-కంట్రోల్డ్ లూప్; కనీసం ఒక్కసారైనా గ్యారెంటీగా రన్ అవుతుంది.
- for: మూడు దశలను ఒకే లైన్లో ఉంచే అత్యంత క్లీన్ మరియు ప్రాచుర్యం పొందిన లూప్.
- ఆఫ్-బై-వన్: కండిషన్లో
<మరియు<=తారుమారు కావడం వల్ల వచ్చే మోసపూరిత బగ్.