[Hỏi] Vấn đề ++i . --i. i++,i -- trong C?
Em có 1 chương trình quản lí thuốc sau:
/*
nhap vao 1 danh sach thuoc gom ten, nam sx, nam het han den khi ten thuoc la dau * thi ngung
in ra thong tin va danh sach thuoc qua han(co nam het han < nam hien tai)
*/
#include <conio.h>
#include <stdio.h>
#include <string.h>
//------------------------------------------------------------------------------------------------------
typedef struct
{
char ten[50];
int namSX;
int namHH;
} danhsach;
void Input (danhsach [], int *);
void Output (danhsach [], int );
void Filter (danhsach [], int );
//------------------------------------------------------------------------------------------------------
main ()
{
int count=0;
danhsach thuoc [100];
Input(thuoc, &count);
if (count == 0 ) printf ("Chua co thuoc nao duoc nhap vao
");
else
{
Output(thuoc, count);
Filter(thuoc, count);
}
getch();
}
//------------------------------------------------------------------------------------------------------
void Input (danhsach thuoc[100], int *count)
{
int i=0;
char check[] = "*";
do
{
++*count;
printf ("Thuoc %d
", i+1);
printf ("Nhap ten ");
fflush(stdin);
gets(thuoc[i].ten);
printf ("Nhap nam san xuat ");
scanf ("%d", &thuoc[i].namSX);
printf ("Nhap nam het han ");
scanf ("%d", &thuoc[i].namHH);
printf ("
");
}
while ( strcmp ( thuoc[i++].ten , check) != 0 );
--*count;
}
//------------------------------------------------------------------------------------------------------
void Output (danhsach thuoc[50], int n)
{
int i;
printf ("STT TenThuoc NamSanXuat NamHetHan
");
for (i=0 ; i<n ; i++) printf ("%d %s %d %d
", i+1, thuoc[i].ten, thuoc[i].namSX, thuoc[i].namHH);
printf ("
");
}
//------------------------------------------------------------------------------------------------------
void Filter (danhsach thuoc[50], int n)
{
int i, check=0;
printf ("Danh sach thuoc het han
");
for (i=0 ; i<n ; i++)
if ( thuoc[i].namHH < 2015 )
{
check=1;
printf ("Thuoc het han: %d %s %d %d
", i+1, thuoc[i].ten, thuoc[i].namSX, thuoc[i].namHH);
}
if (check == 0) printf ("Khong co thuoc nao het han
");
}
em muốn hỏi ở hàm Input
nếu e để *count++ và *count-- thì chương trình chạy sai, giá trị count trả về hàm main vẫn =0
còn khi e để ++ * count và – * count hoặc *count+=1; và *count-=1; thì chương trình lại đúng
e đã tìm hiểu kĩ về --i ++i, i++, i–. đã có 1 ghi chép riêng, nhưng 1 số trường hợp e thấy nó không đúng với những gì đã ghi chép được, kết quả rất khó hiểu
ghi chép của e như sau
Note: luôn tránh những loại lệnh không rõ ràng, ++i, i++, --i, i-- . Chỉ dùng ++, -- khi biết chắc chắn thứ tự của chúng
j = ++i / i = i+1 , j =i tăng i lên rồi mới lấy i sử dụng
j = i++ / j = i , i = i +1 lấy i sử dụng trước rồi tăng i lên
a=10; b=a++; a =11, b=10
a=10; b=a--; a =9, b=10
a=10; b=++a; a =11, b=11
a=10; b=--a; a =9, b=9
++--i thực hiện trước +
a=10;
b = 1 + a++; -> b = 11 , a = 11
b = 1 + a--; -> b = 11 , a = 9
a=10;
b = 1 + ++a; -> b = 12 a = 11
b = 1 + --a; -> b = 10 a = 9
a=10;
b = 1 + a++; -> b = 11 , a = 11
c = 1 + ++a; -> c = 13 a = 12
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bản chất ++i ( --i tương tự )
{
return i+=1; // i = i + 1;
}
bản chất i++: ( i-- tương tự )
{
int temp;
temp = i;
i = i + 1;
return temp;
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
nên trong vòng lặp --i và ++i sẽ thực hiện nhanh hơn i-- và i++
--i và ++i thì -- được thực hiện trước
và i++ thực hiện nhanh hơn i = i +1 hoặc i+=1 vì i++ là 1 lệnh còn i = i+ 1 hoặc i+=1 là 1 phép toán
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bản chất i +1 (i -1 tương tự )
int i = 0;
printf("i ban đầu: %d", i); i ban đầu: 0
printf("i + 1 = %d", i + 1); i + 1 = 1
printf("i sau biểu thức ở trên: %d", i); i sau biểu thức ở trên: 0
bản chất i++ (i-- tương tự)
int i = 0;
printf("i ban đầu: %d", i); i ban đầu: 0
printf("i++ = %d", i++); i++ = 1
printf("i sau biểu thức ở trên: %d", i); i sau biểu thức ở trên: 1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
for (int i=10 ; i>0 ; i--) tốn 24 byte
{
}
và
for (int i=10 ; i>0 ; --i) tốn 13 byte
{
}
i--++ và --++i trong vòng lặp for không phân biệt về giá trị, chỉ phân biệt về bố nhớ sử dụng
i--++ và --++i phân biệt trong biểu thức tính toán và trong hàm in ra màn hình
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
for ( i++ ; i < n ; ) i trước dấu ; chưa được tăng , sau khi i được lấy để so sánh với n thì i mới tăng
for ( ++i ; i < n ; ) i trước dấu ; đã được tăng , rồi mới lấy i so sánh n
while ( strcmp ( info[i++].name , check) != 0 ); i sẽ được đặt vào info[i].name để so sánh, nếu đúng thì i mới được tăng
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int a = 10, b;
b = a++ + ++a;
lấy a = 10 để cộng ( rồi tăng a =11) + a =11 tăng a =12 rồi mới cộng cho số trước
b = 10 + 12 = 22
a = 12
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int a = 10,b;
b = a++ + ++a;
b, a++ , a , ++a
22 13 14 14
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int x = 10;
int a;
a = ++x + ++x;
in ra a = 24
x = x + 1;
x = x + 1;
a = x + x;
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int x = 10, a;
a = ++x + --x;
a = 20
đầu tiên ++x thì x=11 sau đó --x thì x=10
cuối cùng 10 + 10 =20
Đầu tiên --x thì x=9 sau đó ++x thì x=10
cuối cùng 10 + 10=20
Vì theo trình tự kết hợp thì -- được thực hiện trước
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int g=1;
printf("%d %d %d",g,++g,g++);
3 3 1
vì compiler này đặt hàm printf làm việc theo kiểu stack. Nó stack tham số từ phải sang trái.
Khi complier đọc đến tham số cuối, thấy g++, nó lấy trị g (tức là 1) chép vào tham số. Sau đó tăng g lên 1 (thành ra 2).
Complier quay qua tham số kế (áp cuối), thấy ++g, nó lấy trị g (tức là 2), tăng 1 (thành ra 3), và chép vào tham số.
Qua tham số kế nữa, g là 3
Như vây, 4 tham số nó nhận được là
"%d %d %d", 3, 3, 1 ---> và nó in ra 3 3 1
trong ghi chép của e có sai chỗ nào không ạ
có 1 sô chỗ e chưa hiểu như
int a = 10,b;
b = a++ + ++a;
b, a++ , a , ++a
22 13 14 14
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int x = 10;
int a;
a = ++x + ++x;
in ra a = 24
x = x + 1;
x = x + 1;
a = x + x;
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int x = 10, a;
a = ++x + --x;
a = 20
đầu tiên ++x thì x=11 sau đó --x thì x=10
cuối cùng 10 + 10 =20
Đầu tiên --x thì x=9 sau đó ++x thì x=10
cuối cùng 10 + 10=20
Vì theo trình tự kết hợp thì -- được thực hiện trước
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int g=1;
printf("%d %d %d",g,++g,g++);
3 3 1
vì compiler này đặt hàm printf làm việc theo kiểu stack. Nó stack tham số từ phải sang trái.
Khi complier đọc đến tham số cuối, thấy g++, nó lấy trị g (tức là 1) chép vào tham số. Sau đó tăng g lên 1 (thành ra 2).
Complier quay qua tham số kế (áp cuối), thấy ++g, nó lấy trị g (tức là 2), tăng 1 (thành ra 3), và chép vào tham số.
Qua tham số kế nữa, g là 3
Như vây, 4 tham số nó nhận được là
"%d %d %d", 3, 3, 1 ---> và nó in ra 3 3 1
*count++ thì C/C++ nó hiểu là *(count++). Tuy ++ và deref * có chung thứ tự ưu tiên (precedence) là 3 nhưng ++ được liên kết (bind) chặt hơn deref *, nên sẽ được nhóm với count trước rồi mới tới deref.
còn ++*count thì ++ cũng được bind trước, nhưng nó bind với *count, như vậy ở đây phải deref xong rồi mới tới ++, mặc dù ++ được gọi trước.
chỗ này phải in ra là i++ = 0.
mấy cái kiểu ghi này là undefined, tức là ko xác định rõ ràng, có thể ra 2 giá trị khác nhau, vd là 0 hoặc 2, ra giá trị nào cũng đúng. Bỏ hết mấy cái note về mấy dòng này đi. Đáng lẽ trình dịch phải báo lỗi và cấm lập trình viên viết như vậy.
để hiểu tại sao nó lại là ko xác định thì thử hỏi:
(a+b) * (c+d)
a+b được tính trước hay c+d được tính trước?
câu trả lời là ko xác định. Đừng hiểu lầm với “phép nhân tính từ trái qua phải” tức là a+b tính trước c+d, ko phải như vậy. “phép nhân tính từ trái qua phải” tức là nếu có 2 phép nhân thì phép nhân bên trái sẽ được tính trước phép nhân bên phải. Nếu hỏi là
(a+b) * (c+d) * (e+f)
thì có thể trả lời là e+f được tính sau a+b và c+d, vì (a+b) * (c+d) được tính trước, rồi mới lấy kết quả này nhân với (e+f), nhưng vẫn ko xác định được a+b được tính trước hay c+d được tính trước.
tương tự
++x + x++
thì ++x và x++ đều có độ ưu tiên như nhau, vậy tính cái nào trước? Ko xác định được.
e nghe nói đi phỏng vẫn người ta có hỏi mấy câu này
thì câu trả lời ngắn gọn là không xác định chứ tính toán lằng nhằng làm gì.
nếu được hỏi về ++ thì ta thích hỏi hàm ??? dưới đây có tên gọi là gì và giải thích