1. Hãy dành vài giây Đăng nhập hoặc Đăng ký tài khoản để truy cập và sử dụng TBit hiệu quả nhất.
    Ẩn thông báo
  2. Bạn hãy like trang Facebook của TBit để nhận được tin tức công nghệ nhanh nhất từ chúng tôi.
    Ẩn thông báo

Khi nào dùng ++i và khi nào dùng i++ (Phần 1)

Thảo luận trong 'Lập trình' bắt đầu bởi Phạm Đạt, 22/3/20.

0/5, 0 phiếu

    1. Phạm Đạt TBit-Mod

      Chắc hẳn khi mới bắt đầu học một ngôn ngữ lập trình thì bạn sẽ gặp qua phép tính tăng, giảm (++, --). Nhưng liệu nó có đơn giản như cách viết ấy không? Sự khác biệt giữa ++i và i++ là gì? Hãy cùng nhau tìm câu trả lời nhé!

      [​IMG]

      1/ Điểm khác biệt giữa ++i và i++
      Khác biệt cơ bản này áp dụng cho hầu hết các ngôn ngữ và compiler hiện nay.
      Mã (Text):
      1. int a=0, b=0;
      2. a++; // a = 1
      3. ++b; // b = 1
      4. b = ++a; // b = a = 2
      5. a = b++; // a = 2, b = 3
      Lý thuyết chỉ đơn giản có vậy. Nhưng mà cũng có nhiều vấn đề phức tạp lắm nhé. Đừng xem thường ;)

      Một điểm đáng lưu ý ở đây, không nên nhầm lẫn là i++ sẽ trả về giá trị i cho phép gán trước khi nó được tăng lên.
      Hãy xem ví dụ sau để hiểu kĩ hơn về cách làm việc của i++ nhé:
      Về bản chất,chương trình sẽ tạo ra một biến tạm (temp) để lưu giá trị ban đầu của i và trả về giá trị đó cho phép gán sau khi phép toán i++ thực hiện xong.
      Mã (Text):
      1. int MePlusPlus(int &me)
      2. {
      3.     int temp = me;
      4.     me = me + 1;
      5.     return temp;
      6. }
      OK, giờ là phần thực hành. Hãy thử giải thích cách hoạt động của đoạn code sau nhé:

      Mã (Text):
      1. int a = 10;
      2. int x = --a + a++;
      3. cout << x; // In giá trị của biến x
      Giờ bạn hãy copy đoạn code C++ trên vào một trình dịch và Run. Có lẽ trên màn hình kết quả sẽ xuất hiện số 18. Tại sao vậy ? :-??(Đáp án sẽ có trong phần sau của bài viết này nhé)

      2/ Performance
      Từ ví dụ MePlusPlus bạn có thể thấy, tuy phải tốn công tạo một biến temp cho i++ nhưng thực tế sự khác biệt về performance là không lớn. Hầu như tất cả compiler hiện đại sẽ optimize phép toán đó. Bằng chứng là trong ví dụ này trên stackoverflow, gcc cho kết quả biên dịch là như nhau cho hai file code chứa vòng lặp xài ++i và i++.

      Nhưng riêng với C++, sự chênh lệch có thể là đáng kể trong một số trường hợp. Cụ thể là với user-defined type, tức là class bạn tạo ra, vì operator++() là một hàm và compiler không biết làm cách nào để optimize việc tạo ra cái temp object trong đó cả. Sao nó biết được bạn define cái gì và sẽ bự cỡ nào trong class.
      Vậy nên xài cái nào trong vòng for?

      Riêng đối với mình thì ++i thường được sử dụng nhiều hơn. Dù cho đang trong project nào mình cũng xài nó mà chả quan tâm nhiều performance. Và mình đã từng đọc ở đâu đó một lời khuyên:
      3/ Đặt vấn đề về side effect và undefined behavior
      Tại đây, mình có 1 một số ví dụ, bạn hãy thử nghiên cứu để xem chúng có vấn đề gì không nhé.
      Ví dụ 1:
      Mã (Text):
      1. int add(int x, int y)
      2. {
      3.     return x + y;
      4. }
      5.  
      6. int main()
      7. {
      8.     int x = 5;
      9.     // tùy thuộc vào thứ tự evaluate các param của conmpiler
      10.     // mà phép cộng này có thể là 5+6 hoặc 6+6
      11.     int value = add(x, ++x);
      12.  
      13.     std::cout << value; // 11 or 12?
      14.     return 0;
      15. }
      Ví dụ 2:
      Mã (Text):
      1. int main()
      2. {
      3.     int arr[3] = {0, 1, 2};
      4.     int i = 0;
      5.  
      6.     arr[i++] = ++i;
      7.     int x = ++i + ++i;
      8.  
      9.     std::cout << arr[i] << endl;
      10.     std::cout << x;
      11.     return 0;
      12. }[/i]

      Hãy thử chạy 2 ví dụ trên và nghiên cứu. Mình tin, bạn sẽ thấy được sự nguy hiểm của chúng, đặc biệt là nếu phép gán thứ nhất ở ví dụ 2 mà trong vòng lặp nữa thì .

      Hẹn gặp các bạn ở những bài viết sau!
       
      Admin thích bài này.
      Đang tải...
    2. Chợ Tốt Nhất

      Chợ Tốt Nhất TBit-Member

      Điểm:
      20ß
      Rất hay! Thanks đã chia sê
       

Chia sẻ trang này

Đang tải...