سؤال

في C، ما هو الفرق بين استخدام ++i و i++, ، والتي يجب استخدامها في كتلة الزيادة لـ a for حلقة؟

هل كانت مفيدة؟

المحلول

  • ++i سوف تزيد قيمة i, ، ثم قم بإرجاع القيمة المتزايدة.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
    
  • i++ سوف تزيد قيمة i, ، ولكن قم بإرجاع القيمة الأصلية التي i عقدت قبل أن يتم زيادتها.

     i = 1;
     j = i++;
     (i is 2, j is 1)
    

ل for حلقة، إما يعمل. ++i يبدو أكثر شيوعا، ربما لأن هذا هو ما يستخدم في ك&ر.

على أية حال، اتبع المبدأ التوجيهي "تفضل ++i زيادة i++"ولن تخطئ.

هناك بعض التعليقات بخصوص كفاءة ++i و i++.في أي مترجم غير مشروع طلابي، لن يكون هناك فرق في الأداء.يمكنك التحقق من ذلك من خلال النظر إلى الكود الذي تم إنشاؤه، والذي سيكون متطابقًا.

مسألة الكفاءة مثيرة للاهتمام ...ها هي محاولتي للإجابة:هل هناك فرق في الأداء بين i++ و++i في لغة C؟

مثل على فرويند الملاحظات، الأمر مختلف بالنسبة لكائن C++، منذ ذلك الحين operator++() هي وظيفة ولا يستطيع المترجم معرفة كيفية تحسين إنشاء كائن مؤقت للاحتفاظ بالقيمة المتوسطة.

نصائح أخرى

أنا++ معروف ب بعد الزيادة بينما ++أنا يسمى الزيادة المسبقة.

i++

i++ هو بعد الزيادة لأنه يزيد iالقيمة بمقدار 1 بعد انتهاء العملية.

لنرى المثال التالي:

int i = 1, j;
j = i++;

هنا قيمة j = 1 لكن i = 2.هنا قيمة i سيتم تعيينه ل j أولا ثم i سيتم زيادتها.

++i

++i هي الزيادة المسبقة لأنها تزيد iقيمة بمقدار 1 قبل العملية.هذا يعني j = i; سيتم التنفيذ بعد i++.

لنرى المثال التالي:

int i = 1, j;
j = ++i;

هنا قيمة j = 2 لكن i = 2.هنا قيمة i سيتم تعيينه ل j بعد i زيادة i.بصورة مماثلة ++i سيتم تنفيذه من قبل j=i;.

لسؤالك ما الذي يجب استخدامه في كتلة الزيادة في حلقة for؟ الجواب هو أنه يمكنك استخدام أي واحد.لا يهم.سيتم تنفيذ حلقة for الخاصة بك بنفس الرقم.من المرات.

for(i=0; i<5; i++)
   printf("%d ",i);

و

for(i=0; i<5; ++i)
   printf("%d ",i);

كل من الحلقات سوف تنتج نفس الناتج.أي 0 1 2 3 4.

يهم فقط المكان الذي تستخدمه فيه.

for(i = 0; i<5;)
    printf("%d ",++i);

في هذه الحالة سيكون الإخراج 1 2 3 4 5.

من فضلك لا تقلق بشأن "الكفاءة" (السرعة حقًا) أيهما أسرع.لدينا مجمعون هذه الأيام يهتمون بهذه الأشياء.استخدم أيًا كان منطقيًا للاستخدام، بناءً على ما يوضح نيتك بشكل أكثر وضوحًا.

++i يزيد القيمة، ثم يعيدها.

i++ تقوم بإرجاع القيمة ثم زيادتها.

إنه فرق دقيق.

للحصول على حلقة for، استخدم ++i, ، لأنه أسرع قليلاً. i++ سيتم إنشاء نسخة إضافية يتم التخلص منها للتو.

i++:في هذا السيناريو، يتم تعيين القيمة أولاً ثم تحدث الزيادة.

++i:في هذا السيناريو، تتم الزيادة أولاً ثم يتم تعيين القيمة

أدناه هو تصور الصورة وأيضا هنا فيديو عملي جميل الذي يدل على نفسه.

enter image description here

السبب ++i يستطيع يكون أسرع قليلا من i++ هل هذا i++ يمكن أن تتطلب نسخة محلية من قيمة i قبل زيادتها، بينما ++i لا أبدا.في بعض الحالات، يقوم بعض المترجمين بتحسينه إن أمكن...لكن هذا ليس ممكنًا دائمًا، ولا يقوم جميع المترجمين بذلك.

أحاول ألا أعتمد كثيرًا على تحسينات المترجمين، لذا سأتبع نصيحة ريان فوكس:عندما أستطيع استخدام كليهما، أستخدم ++i.

النتيجة الفعالة لاستخدام أي منهما متطابقة.بمعنى آخر، ستفعل الحلقة نفس الشيء بالضبط في كلتا الحالتين.

فيما يتعلق بالكفاءة، قد تكون هناك عقوبة عند اختيار i++ على ++i.فيما يتعلق بمواصفات اللغة، فإن استخدام عامل ما بعد الزيادة يجب أن ينشئ نسخة إضافية من القيمة التي يعمل عليها العامل.قد يكون هذا مصدرًا لعمليات إضافية.

ومع ذلك، يجب عليك مراعاة مشكلتين رئيسيتين في المنطق السابق.

  1. المترجمون الحديثون رائعون.يتمتع جميع المترجمين الجيدين بالذكاء الكافي لإدراك أنهم يرون زيادة صحيحة في حلقة for، وسيعملون على تحسين كلا الطريقتين لنفس الكود الفعال.إذا كان استخدام الزيادة اللاحقة على الزيادة المسبقة يؤدي في الواقع إلى جعل وقت تشغيل البرنامج أبطأ، فأنت تستخدم رهيب مترجم.

  2. من حيث التعقيد الزمني التشغيلي، فإن الطريقتين (حتى لو تم تنفيذ نسخة بالفعل) متكافئتان.يجب أن يسيطر عدد التعليمات التي يتم تنفيذها داخل الحلقة على عدد العمليات في عملية الزيادة بشكل ملحوظ.لذلك، في أي حلقة ذات حجم كبير، سيتم حجب عقوبة طريقة الزيادة بشكل كبير من خلال تنفيذ جسم الحلقة.بمعنى آخر، من الأفضل أن تقلق بشأن تحسين التعليمات البرمجية في الحلقة بدلاً من الزيادة.

في رأيي، المسألة برمتها تتلخص ببساطة في تفضيل الأسلوب.إذا كنت تعتقد أن الزيادة المسبقة أكثر قابلية للقراءة، فاستخدمها.أنا شخصياً أفضل ما بعد الزيادة، ولكن ربما يرجع ذلك إلى أن هذا هو ما تعلمته قبل أن أعرف أي شيء عن التحسين.

يعد هذا مثالًا جوهريًا للتحسين المبكر، ومثل هذه المشكلات لديها القدرة على صرف انتباهنا عن المشكلات الجادة في التصميم.ومع ذلك، لا يزال من الجيد طرح هذا السؤال، لأنه لا يوجد توحيد في الاستخدام أو إجماع في "أفضل الممارسات".

وكلاهما يزيد العدد. ++i يعادل i = i + 1.

i++ و ++i متشابهة جدًا ولكنها ليست متماثلة تمامًا.كلا زيادة العدد، ولكن ++i يزيد الرقم قبل تقييم التعبير الحالي، بينما i++ يزيد الرقم بعد تقييم التعبير.

مثال:

int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3

++i (عملية البادئة):يزيد ثم يعين القيمة
(على سبيل المثال): int i = 5, int b = ++iفي هذه الحالة، يتم تعيين 6 إلى b أولاً ثم يزيد إلى 7 وهكذا.

i++ (عملية Postfix):يعين ثم يزيد القيمة
(على سبيل المثال): int i = 5, int b = i++في هذه الحالة، يتم تعيين 5 إلى b أولاً ثم يزيد إلى 6 وهكذا.

حالة للحلقة: i++ يستخدم في الغالب لأننا عادة نستخدم قيمة البداية لـ i قبل الزيادة في الحلقة.ولكن اعتمادا على منطق البرنامج الخاص بك قد يختلف.

++i:هي الزيادة المسبقة والأخرى هي الزيادة اللاحقة.

i++:يحصل على العنصر ثم يزيده.
++i:يزيد i ثم يقوم بإرجاع العنصر.

مثال:

int i = 0;
printf("i: %d\n", i);
printf("i++: %d\n", i++);
printf("++i: %d\n", ++i);

انتاج:

i: 0
i++: 0
++i: 2

أفترض أنك تفهم الفرق في الدلالات الآن (على الرغم من أن بصراحة أتساءل لماذا يسأل الناس "ماذا يعني المشغل X" أسئلة حول سعة مكدس بدلاً من القراءة ، كما تعلمون ، كتاب أو برنامج تعليمي على الويب أو شيء ما.

ولكن على أي حال ، بقدر ما هو الشخص الذي يجب استخدامه ، يتجاهل أسئلة الأداء ، والتي من غير المرجح أن تكون مهمة حتى في C ++.هذا هو المبدأ الذي يجب أن تستخدمه عند تحديد ما الذي يجب استخدامه:

قل ما تقصده في الكود.

إذا لم تكن بحاجة إلى القيمة قبل الزيادة في بيانك، فلا تستخدم نموذج عامل التشغيل هذا.إنها مشكلة بسيطة ، ولكن ما لم تكن تعمل مع دليل نمط يحظر إصدارًا واحدًا لصالح الآخر تمامًا (ويعرف أيضًا باسم دليل الأسلوب الذي يرأسه العظام) ، فيجب عليك استخدام النموذج الذي يعبر عن أكثر ما تحاول القيام به.

QED، استخدم إصدار الزيادة المسبقة:

for (int i = 0; i != X; ++i) ...

يمكن فهم الفرق من خلال رمز C++ البسيط أدناه:

int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;

الفرق الرئيسي هو

  • أنا ++ مشاركة(بعد الزيادة) و
  • ++i قبل (قبل الزيادة)

    • نشر إذا i =1 تزداد الحلقة مثل 1,2,3,4,n
    • قبل إذا i =1 تزداد الحلقة مثل 2,3,4,5,n

ط ++ و ++ ط

قد يساعد هذا الرمز الصغير في تصور الفرق من زاوية مختلفة عن الإجابات المنشورة بالفعل:

int i = 10, j = 10;

printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);

printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);

النتيجة هي:

//Remember that the values are i = 10, and j = 10

i is 10 
i++ is 10     //Assigns (print out), then increments
i is 11 

j is 10 
++j is 11    //Increments, then assigns (print out)
j is 11 

انتبه إلى المواقف قبل وبعد.

لحلقة

أما بالنسبة لأي منها يجب استخدامه في كتلة تزايدية للحلقة، فأعتقد أن أفضل ما يمكننا القيام به لاتخاذ قرار هو استخدام مثال جيد:

int i, j;

for (i = 0; i <= 3; i++)
    printf (" > iteration #%i", i);

printf ("\n");

for (j = 0; j <= 3; ++j)
    printf (" > iteration #%i", j);

النتيجة هي:

> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3 

لا أعرف عنك، لكني لا أرى أي فرق في استخدامه، على الأقل في حلقة for.

يوضح جزء كود C التالي الفرق بين عوامل الزيادة والنقصان السابقة واللاحقة:

int  i;
int  j;

عوامل الزيادة:

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2

الإضافة المسبقة تعني الزيادة على نفس السطر.Post-increment تعني الزيادة بعد تنفيذ السطر.

int j=0;
System.out.println(j); //0
System.out.println(j++); //0. post-increment. It means after this line executes j increments.

int k=0;
System.out.println(k); //0
System.out.println(++k); //1. pre increment. It means it increments first and then the line executes

عندما يتعلق الأمر بعوامل تشغيل OR وAND، يصبح الأمر أكثر إثارة للاهتمام.

int m=0;
if((m == 0 || m++ == 0) && (m++ == 1)) { //false
/* in OR condition if first line is already true then compiler doesn't check the rest. It is technique of compiler optimization */
System.out.println("post-increment "+m);
}

int n=0;
if((n == 0 || n++ == 0) && (++n == 1)) { //true
System.out.println("pre-increment "+n); //1
}

في المصفوفة

System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 } ;
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); //12

jj = a[1]++; //12
System.out.println(a[1]); //a[1] = 13

mm = a[1];//13
System.out.printf ( "\n%d %d %d\n", ii, jj, mm ) ; //12, 12, 13

for (int val: a) {
     System.out.print(" " +val); //55, 13, 15, 20, 25
}

في C++، النشر/الزيادة المسبقة لمتغير المؤشر

#include <iostream>
using namespace std;

int main() {

    int x=10;
    int* p = &x;

    std::cout<<"address = "<<p<<"\n"; //prints address of x
    std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
    std::cout<<"address = "<<&x<<"\n"; //prints address of x

    std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}

قريبا:

++i و i++ يعمل بنفس الطريقة إذا كنت لا تكتبها في وظيفة.إذا كنت تستخدم شيئا مثل function(i++) أو function(++i) يمكنك ان ترى الفرق.

function(++i) يقول الزيادة الأولى i بمقدار 1، وبعد ذلك ضع هذا i في الدالة بقيمة جديدة.

function(i++) يقول ضع أولا i في الوظيفة بعد تلك الزيادة i بواسطة 1.

int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now

والفرق الوحيد هو ترتيب العمليات بين زيادة المتغير والقيمة التي يرجعها المشغل.

يشرح هذا الكود ومخرجاته الفرق:

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  a = i++;
  printf("i before: %d; value returned by i++: %d, i after: %d\n", i, a, i);
  i=0;
  a = ++i;
  printf("i before: %d; value returned by ++i: %d, i after: %d\n", i, a, i);
}

الإخراج هو:

i before: 1; value returned by i++: 0, i after: 1
i before: 1; value returned by ++i: 1, i after: 1

ذلك في الأساس ++i تقوم بإرجاع القيمة بعد زيادتها، بينما ++i قم بإرجاع القيمة قبل زيادتها.وفي النهاية في كلتا الحالتين i ستزداد قيمته.

مثال آخر:

#include<stdio.h>

int main ()
  int i=0;
  int a = i++*2;
  printf("i=0, i++*2=%d\n", a);
  i=0;
  a = ++i * 2;
  printf("i=0, ++i*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  return 0;
}

انتاج:

i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2

في كثير من الأحيان لا يوجد فرق

تكون الاختلافات واضحة عندما يتم تعيين القيمة التي تم إرجاعها إلى متغير آخر أو عند إجراء الزيادة بالتسلسل مع العمليات الأخرى حيث يتم تطبيق أسبقية العمليات (i++*2 يختلف عن ++i*2, ، لكن (i++)*2 و (++i)*2 ترجع نفس القيمة) في كثير من الحالات تكون قابلة للتبديل.المثال الكلاسيكي هو بناء جملة الحلقة:

for(int i=0; i<10; i++)

له نفس التأثير

for(int i=0; i<10; ++i)

قاعدة للتذكر

لتجنب الخلط بين المشغلين، اعتمدت هذه القاعدة:

ربط موقف المشغل ++ فيما يتعلق بالمتغير i لأمر ++ العملية فيما يتعلق بالمهمة

قال بمعنى آخر:

  • ++ قبل i يعني يجب أن تتم الزيادة قبل تكليف؛
  • ++ بعد i يعني يجب أن تتم الزيادة بعد تكليف:

يمكنك التفكير في التحويل الداخلي لذلك على أنه ملف تصريحات متعددة;

// case 1 :

i++;

/* you can think as,
 * i;
 * i= i+1;
 */

// case 2

++i;

/* you can think as,
 * i = i+i;
 * i;
 */

A = i تعني أن a يحتوي على قيمة i الحالية a = i تعني أن a يحتوي على قيمة i متزايدة

هنا هو المثال لفهم الفرق

int i=10;
printf("%d %d",i++,++i);

انتاج: 10 12/11 11 (اعتمادًا على ترتيب تقييم الحجج لـ printf وظيفة، والتي تختلف عبر المجمعين والبنيات)

توضيح:i++->i تتم طباعتها، ثم الزيادات.(المطبوعات 10، ولكن i سوف تصبح 11)++i->i زيادات القيمة وطباعة القيمة.(المطبوعات 12، وقيمة i أيضا 12)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top