Trong C, sự khác biệt giữa việc sử dụng ++i
và i++
nên được sử dụng trong khối tăng của một for
vòng lặp là gì?
Trong C, sự khác biệt giữa việc sử dụng ++i
và i++
nên được sử dụng trong khối tăng của một for
vòng lặp là gì?
Câu trả lời:
++i
sẽ tăng giá trị của i
, và sau đó trả về giá trị tăng.
i = 1;
j = ++i;
(i is 2, j is 2)
i++
sẽ tăng giá trị của i
, nhưng trả về giá trị ban đầu i
được giữ trước khi tăng.
i = 1;
j = i++;
(i is 2, j is 1)
Đối với một for
vòng lặp, hoặc hoạt động. ++i
dường như phổ biến hơn, có lẽ vì đó là những gì được sử dụng trong K & R .
Trong mọi trường hợp, hãy làm theo hướng dẫn "thích ++i
hơn i++
" và bạn sẽ không đi sai.
Có một vài ý kiến liên quan đến hiệu quả của ++i
và i++
. Trong bất kỳ trình biên dịch phi sinh viên dự án, sẽ không có sự khác biệt hiệu suất. Bạn có thể xác minh điều này bằng cách xem mã được tạo, mã này sẽ giống hệt nhau.
Câu hỏi về hiệu quả rất thú vị ... đây là nỗ lực của tôi trong câu trả lời: Có sự khác biệt về hiệu năng giữa i ++ và ++ i trong C không?
Như @OnFreund lưu ý, nó khác với một đối tượng C ++, vì đây operator++()
là một hàm và trình biên dịch không thể biết để tối ưu hóa việc tạo ra một đối tượng tạm thời để giữ giá trị trung gian.
for(int i=0; i<10; i++){ print i; }
điều này sẽ không khác với for(int i=0; i<10; ++i){ print i; }
sự hiểu biết của tôi là một số ngôn ngữ sẽ cung cấp cho bạn các kết quả khác nhau tùy thuộc vào việc bạn sử dụng.
i++
vì nó có dạng "toán tử toán tử", là một phép gán "toán hạng-toán tử-giá trị". Nói cách khác, toán hạng đích nằm ở bên trái của biểu thức, giống như nó nằm trong một câu lệnh gán.
i++
và print i
nằm trong các tuyên bố khác nhau, mà bởi vì i++;
và i<10
là. Nhận xét của @ jonnyflash không phải là không có cơ sở. Giả sử bạn có for(int i=0; i++<10){ print i; }
và for(int i=0; ++i<10){ print i; }
. Chúng sẽ hoạt động khác nhau theo cách mà @johnnyflash mô tả trong bình luận đầu tiên.
i ++ được gọi là Post Increment trong khi ++ i được gọi là Pre Increment.
i++
i++
là gia tăng bài đăng bởi vì nó tăng i
giá trị của 1 sau khi hoạt động kết thúc.
Hãy xem ví dụ sau:
int i = 1, j;
j = i++;
Ở đây giá trị của j = 1
nhưng i = 2
. Ở đây giá trị của i
sẽ được gán cho j
đầu tiên sau đó i
sẽ được tăng lên.
++i
++i
là gia tăng trước bởi vì nó tăng i
giá trị của 1 trước khi hoạt động. Nó có nghĩa là j = i;
sẽ thực hiện sau i++
.
Hãy xem ví dụ sau:
int i = 1, j;
j = ++i;
Ở đây giá trị của j = 2
nhưng i = 2
. Ở đây giá trị của i
sẽ được gán cho j
sau khi i
tăng i
. Tương tự ++i
sẽ được thực hiện trước j=i;
.
Đối với câu hỏi của bạn nên được sử dụng trong khối tăng của vòng lặp for? Câu trả lời là, bạn có thể sử dụng bất kỳ một .. không quan trọng. Nó sẽ thực hiện vòng lặp for của bạn giống như không. thời gian.
for(i=0; i<5; i++)
printf("%d ",i);
Và
for(i=0; i<5; ++i)
printf("%d ",i);
Cả hai vòng lặp sẽ tạo ra cùng một đầu ra. tức 0 1 2 3 4
.
Nó chỉ quan trọng khi bạn đang sử dụng nó.
for(i = 0; i<5;)
printf("%d ",++i);
Trong trường hợp này đầu ra sẽ được 1 2 3 4 5
.
Xin đừng lo lắng về "hiệu quả" (tốc độ, thực sự) trong đó cái nào nhanh hơn. Chúng tôi có trình biên dịch những ngày này chăm sóc những điều này. Sử dụng bất cứ ai có ý nghĩa để sử dụng, dựa trên đó thể hiện rõ hơn ý định của bạn.
operator++(int)
(phiên bản postfix), mã khá nhiều phải tạo tạm thời sẽ được trả về. Bạn có chắc chắn rằng trình biên dịch luôn có thể tối ưu hóa điều đó không?
++i
tăng giá trị, sau đó trả về nó.
i++
trả về giá trị, và sau đó tăng nó.
Đó là một sự khác biệt tinh tế.
Đối với một vòng lặp for, sử dụng ++i
, vì nó nhanh hơn một chút. i++
sẽ tạo ra một bản sao thêm mà chỉ cần được ném đi.
i++
: Trong kịch bản này trước tiên, giá trị được gán và sau đó gia tăng xảy ra.
++i
: Trong kịch bản này, đầu tiên gia tăng được thực hiện và sau đó giá trị được gán
Dưới đây là hình ảnh trực quan và đây cũng là một video thực tế hay thể hiện điều tương tự.
Nguyên nhân ++i
có thể nhanh hơn một chút i++
là vì i++
có thể yêu cầu một bản sao cục bộ của giá trị của i trước khi nó được tăng lên, trong khi ++i
không bao giờ. Trong một số trường hợp, một số trình biên dịch sẽ tối ưu hóa nó đi nếu có thể ... nhưng không phải lúc nào cũng có thể, và không phải tất cả các trình biên dịch đều làm điều này.
Tôi cố gắng không phụ thuộc quá nhiều vào tối ưu hóa trình biên dịch, vì vậy tôi làm theo lời khuyên của Ryan Fox: khi tôi có thể sử dụng cả hai, tôi sử dụng ++i
.
i
hơn giá trị 1 khi bạn viết một câu lệnh 1;
.
Kết quả hiệu quả của việc sử dụng hoặc trong một vòng lặp là giống hệt nhau. Nói cách khác, vòng lặp sẽ làm điều tương tự chính xác trong cả hai trường hợp.
Về hiệu quả, có thể có một hình phạt liên quan đến việc chọn i ++ hơn ++ i. Về mặt đặc tả ngôn ngữ, sử dụng toán tử tăng sau sẽ tạo thêm một bản sao của giá trị mà toán tử đang thực hiện. Đây có thể là một nguồn của các hoạt động thêm.
Tuy nhiên, bạn nên xem xét hai vấn đề chính với logic trước đó.
Trình biên dịch hiện đại là tuyệt vời. Tất cả các trình biên dịch tốt đều đủ thông minh để nhận ra rằng nó đang nhìn thấy một số nguyên tăng trong một vòng lặp for và nó sẽ tối ưu hóa cả hai phương thức thành cùng một mã hiệu quả. Nếu việc sử dụng tăng sau so với tăng trước thực sự khiến chương trình của bạn có thời gian chạy chậm hơn, thì bạn đang sử dụng một trình biên dịch khủng .
Về độ phức tạp thời gian hoạt động, hai phương pháp (ngay cả khi một bản sao đang thực sự được thực hiện) là tương đương. Số lượng các lệnh được thực hiện bên trong vòng lặp sẽ chi phối đáng kể số lượng các hoạt động trong hoạt động gia tăng đáng kể. Do đó, trong bất kỳ vòng lặp nào có kích thước đáng kể, hình phạt của phương pháp tăng sẽ bị lu mờ ồ ạt khi thực hiện thân vòng lặp. Nói cách khác, bạn tốt hơn nhiều là lo lắng về việc tối ưu hóa mã trong vòng lặp hơn là gia tăng.
Theo tôi, toàn bộ vấn đề chỉ đơn giản là nắm bắt một sở thích phong cách. Nếu bạn nghĩ rằng tăng trước dễ đọc hơn, thì hãy sử dụng nó. Cá nhân, tôi thích phần tăng sau, nhưng đó có lẽ là vì đó là điều tôi được dạy trước khi tôi biết bất cứ điều gì về tối ưu hóa.
Đây là một ví dụ tinh túy về tối ưu hóa sớm và các vấn đề như thế này có khả năng đánh lạc hướng chúng ta khỏi các vấn đề nghiêm trọng trong thiết kế. Tuy nhiên, đây vẫn là một câu hỏi hay để hỏi vì không có sự thống nhất trong cách sử dụng hoặc sự đồng thuận trong "thực tiễn tốt nhất".
Cả hai đều tăng số lượng. ++i
tương đương với i = i + 1
.
i++
và ++i
rất giống nhau nhưng không hoàn toàn giống nhau. Cả hai đều tăng số, nhưng ++i
tăng số trước khi biểu thức hiện tại được ước tính, trong khii++
tăng số sau khi biểu thức được ước tính.
Thí dụ:
int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3
++i
(Hoạt động tiền tố): Tăng và sau đó gán giá trị
(ví dụ) : int i = 5
, int b = ++i
Trong trường hợp này, 6 được gán cho b trước và sau đó tăng lên 7 và cứ thế.
i++
(Hoạt động Postfix): Gán và sau đó tăng giá trị
(ví dụ) : int i = 5
,int b = i++
Trong trường hợp này, 5 được gán cho b trước và sau đó tăng lên 6 và cứ thế.
Incase of for loop: i++
chủ yếu được sử dụng bởi vì, thông thường chúng ta sử dụng giá trị bắt đầu i
trước khi tăng trong vòng lặp for. Nhưng tùy thuộc vào logic chương trình của bạn, nó có thể khác nhau.
Tôi giả sử bạn hiểu sự khác biệt về ngữ nghĩa bây giờ (mặc dù thật lòng tôi tự hỏi tại sao mọi người hỏi 'câu hỏi của nhà điều hành X có nghĩa là gì' trên stack stack thay vì đọc, bạn biết, một cuốn sách hoặc hướng dẫn web hoặc một cái gì đó.
Nhưng dù sao, theo như sử dụng cái nào, hãy bỏ qua các câu hỏi về hiệu năng, điều không thể quan trọng ngay cả trong C ++. Đây là nguyên tắc bạn nên sử dụng khi quyết định sử dụng:
Nói những gì bạn có nghĩa trong mã.
Nếu bạn không cần giá trị gia tăng trước trong tuyên bố của mình, đừng sử dụng hình thức của nhà điều hành. Đó là một vấn đề nhỏ, nhưng trừ khi bạn đang làm việc với một hướng dẫn phong cách cấm hoàn toàn một phiên bản có lợi cho phiên bản kia (hay còn gọi là hướng dẫn kiểu đầu xương), bạn nên sử dụng biểu mẫu thể hiện chính xác nhất những gì bạn đang cố gắng thực hiện.
QED, sử dụng phiên bản tăng trước:
for (int i = 0; i != X; ++i) ...
Sự khác biệt có thể được hiểu bởi mã C ++ đơn giản dưới đây:
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;
Sự khác biệt chính là
- i ++ Bài đăng ( Sau khi tăng ) và
++ i Pre ( Trước khi tăng )
- đăng nếu
i =1
vòng lặp tăng như1,2,3,4,n
- trước nếu
i =1
vòng lặp tăng như2,3,4,5,n
Mã nhỏ này có thể giúp hình dung sự khác biệt từ một góc độ khác với các câu trả lời đã được đăng:
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);
Kết quả là:
//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
Hãy chú ý đến các tình huống trước và sau.
Về việc một trong số chúng nên được sử dụng trong khối tăng của vòng lặp for, tôi nghĩ rằng cách tốt nhất chúng ta có thể làm để đưa ra quyết định là sử dụng một ví dụ hay:
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);
Kết quả là:
> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3
Tôi không biết về bạn, nhưng tôi không thấy bất kỳ sự khác biệt nào trong cách sử dụng, ít nhất là trong một vòng lặp for.
Đoạn mã C sau đây minh họa sự khác biệt giữa các toán tử tăng và giảm trước và sau:
int i;
int j;
Toán tử gia tăng:
i = 1;
j = ++i; // i is now 2, j is also 2
j = i++; // i is now 3, j is 2
Pre-crement có nghĩa là tăng trên cùng một dòng. Tăng sau có nghĩa là tăng sau khi dòng thực thi.
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
Khi đi kèm với các toán tử OR, AND, nó trở nên thú vị hơn.
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
}
Trong mảng
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
}
Trong C ++ bài / tăng trước của biến con trỏ
#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)
}
Ngắn gọn:
++i
và i++
hoạt động tương tự nếu bạn không viết chúng trong một hàm. Nếu bạn sử dụng một cái gì đó như function(i++)
hoặc function(++i)
bạn có thể thấy sự khác biệt.
function(++i)
cho biết lần đầu tiên tăng i lên 1, sau đó đưa i
giá trị này vào hàm với giá trị mới.
function(i++)
nói đặt đầu tiên i
vào hàm sau khi tăng 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
int j = ++i;
và int k = i++;
ngay cả khi không có chức năng gọi liên quan.
Sự khác biệt duy nhất là thứ tự các hoạt động giữa mức tăng của biến và giá trị mà toán tử trả về.
Mã này và đầu ra của nó giải thích sự khác biệt:
#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);
}
Đầu ra là:
i before: 1; value returned by i++: 0, i after: 1
i before: 1; value returned by ++i: 1, i after: 1
Vì vậy, về cơ bản ++i
trả về giá trị sau khi nó được tăng lên, trong khi ++i
trả về giá trị trước khi nó được tăng lên. Cuối cùng, trong cả hai trường hợp, i
giá trị của nó sẽ tăng lên.
Một vi dụ khac:
#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;
}
Đầu ra:
i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2
Sự khác biệt là rõ ràng khi giá trị trả về được gán cho một biến khác hoặc khi gia tăng được thực hiện kết hợp với các hoạt động khác trong đó các hoạt động được ưu tiên áp dụng ( i++*2
khác với ++i*2
, (i++)*2
và (++i)*2
trả về cùng một giá trị) trong nhiều trường hợp chúng có thể hoán đổi cho nhau. Một ví dụ cổ điển là cú pháp vòng lặp for:
for(int i=0; i<10; i++)
có tác dụng tương tự
for(int i=0; i<10; ++i)
Để không gây nhầm lẫn giữa hai nhà khai thác, tôi đã áp dụng quy tắc này:
Liên kết vị trí của toán tử ++
đối với biến i
với thứ tự của phép ++
toán đối với phép gán
Nói cách khác:
++
trước khi i
tăng có nghĩa là phải được thực hiện trước khi chuyển nhượng;++
sau khi i
tăng có nghĩa là phải được thực hiện sau khi gán:Bạn có thể nghĩ về chuyển đổi nội bộ của nó như là một báo cáo nhiều ;
i++;
bạn có thể nghĩ nó như là,
i;
i = i+1;
++i;
bạn có thể nghĩ nó như là,
i = i+i;
i;
a = i ++ có nghĩa là a chứa giá trị i hiện tại a = ++ i có nghĩa là giá trị chứa i tăng
a = i++;
có nghĩa là giá trị được lưu trữ a
sẽ là giá trị i
trước khi tăng, nhưng 'không tăng' ngụ ý i
không tăng, điều này hoàn toàn sai - i
được tăng lên, nhưng giá trị của biểu thức là giá trị trước khi tăng.
Dưới đây là ví dụ để hiểu sự khác biệt
int i=10;
printf("%d %d",i++,++i);
đầu ra: 10 12/11 11
(tùy theo thứ tự đánh giá các đối số choprintf
hàm, khác nhau giữa các trình biên dịch và kiến trúc)
Giải thích:
i++
-> i
được in, và sau đó tăng. (In 10, nhưng i
sẽ trở thành 11)
++i
-> i
tăng giá trị và in giá trị. (In 12 và giá trị của i
12)
i++
và++i