Nhân cái ngày mưa gió này làm cái blog vui :)
Dựa trên đề cương ôn tập môn Kĩ thuật lập trình (Programming Technique) của thầy Trịnh Thành Trung
1. Thứ tự thực hiện các phép toán trong C
1.1 Viết chương trình nhập các tham số tương ứng và tính giá trị các biểu thức sau
int a,b,c,d; a=b=c++=d=10; in ra a,b,c,d a=b=++c=d=10; in ra a,b,c,d
Giữ nguyên đoạn code trên, sửa dòng khai báo thành int a,c,d,b; chạy chương trình và xem kết quả và đưa ra nhận xét
- Trong biểu thức gán
a=b=c++=d=10; (1)
a=b=++c=d=10; (2)
khi cho vào trình biên dịch chạy (như của mình là TDM GCC 4.9.2 64bit Release) thì biểu thức (1) sinh ra lỗi, trình biên dịch thông báo "[Error] lvalue required as left operand of assignment" , biểu thức (2) không sinh ra lỗi, console hiển thị các giá trị a=b=c=d=1. Lý giải như sau :
- Trong C++ có 2 kiểu trả về là tham trị (value) và tham chiếu (reference) :
- Đối với biểu thức hậu tố (postfix), sau khi thực hiện c++, sẽ trả về tham trị, nên ta không thể thực hiện phép gán được.
- Đối với biểu thức tiền tố (prefix), sau khi thực hiện ++c, sẽ trả về tham chiếu, nên ta có thể thực hiện được phép gán.
1.2 Viết chương trình nhập các tham số tương ứng và tính giá trị các biểu thức sau :
int a,b Nhập a b= a++ + 2 * a; in ra a,b b= ++a + 2 * a; in ra a,b b= (2*a)+ ++a; in ra a,b b= (2*a)+ a++; in ra a,b b= ++a + (2*a); in ra a,b b= a++ + (2*a); a=10; printf(" \n a++,a = %d, %d",a++,a); a=10; printf(" \n ++a,a = %d, %d",++a,a); a=10; printf(" \n a,a++ = %d, %d",a,a++); a=10; printf(" \n a,++a = %d, %d",a,++a);
Chạy chương trình trên TURBO C++, VC++ và GCC, xem kết quả và đưa ra nhận xét về thứ tự thực hiện các phép toán, cùng cơ chế truyền tham số cho hàm của C
- Trong bài này chỉ cần lưu ý, đối với phép toán, thứ tự thực hiện là từ trái sang phải, còn dường như với printf thì việc truyền giá trị cho biến là phải sang trái :)
2. Array
2.1.a Viết CT nhập vào 1 xâu ký tự va in ra số lần xuất hiện của mỗi ký tự trong xâu.
- Dùng 1 mảng f để lưu tần số xuất hiện của các chữ cái trong xâu.
#include<iostream>
#include<string>
using namespace std;
main(){
string line;
getline(cin,line);
int len = line.length();
int *f = new int[len];
for(int i = 0; i < len; i++){
f[i] = 0;
}
int count = 0;
for(int i = 0; i < len; i++){
int k = 0;
while(k != i){
if(line[i] == line[k]){
count++;
break;
}
k++;
}
f[k]++;
}
for(int i = 0; i < len -count; i++){
cout << f[i];
}
}
2.1.b Nhập vào 2 ký tự rồi in ra xâu với ký tự thứ nhất ( nếu có) trong xâu được thay thế bằng ký tự thứ 2.Trình bày giải pháp
- Ban đầu có 1 xâu rỗng. mình tìm duyệt xâu đầu vào nhé. nếu ký tự đang xét là ký tự thứ nhất thì thêm vào xâu rỗng ký tự thứ 2, nếu không thì thêm ký tự này vào xâu rỗng. Hàm trả về xâu này.
#include<iostream>
#include<string>
using namespace std;
main(){
string line;
getline(cin,line);
string temp;
char ch1, ch2;
cin >> ch1 >> ch2;
int len = line.length();
for(int i=0; i < len; i++){
if(line[i] == ch1) temp += ch2;
else temp += line[i];
}
cout << endl << temp;
}
2.2 Viết chương trình tính tổng 2 ma trận:
2.3 Viết chương trình tính tích 2 ma trận
http://codepad.org/67yoVnuL
3. Pointer
3.1 Chép chương trình sau, chạy, xem kết quả rồi tìm và chỉnh sửa lỗi :
#include <stdio.h>#include <conio.h>void main() { int a,b,c; int *p=&c; c = 3; /* divide c by itself */ a = c / *p; b = c; /* set b to 3 */ printf("a=%d, b=%d, c=%d\n", a,b,c); getch();}
=> Lỗi : void -> int
4. Functions
Xây dựng hàm tính căn bậc ba của 1 số thực, rồi nhập dãy các số thực x1, x2, ..., xn và tính tổng
Biết rằng
- 0 khi x = 0
- khi x > 0
- khi x < 0
#include<iostream>
#include<math.h>
using namespace std;
double Can3(double n){
if(n == 0) return 0;
else if(n > 0) return exp(1.0/3*log(n));
else return -exp(1.0/3*log(-n));
}
main(){
double a[10];
double s = 0.0;
int n;
cout << "n = "; cin >> n;
for(int i = 1; i <= n; i++){
cout << "x" << i << " = ";
cin >> a[i];
s += Can3(a[i]);
}
cout << "\nTong : " << s;
}
5. Pointer và cấp phát bộ nhớ động
5.1 Viết lại chương trình 2.2,2.3 dùng cấp phát bộ nhớ động ( sử dụng mảng 1 chiều, và 2 chiều)
5.2 Viết CT nhập vào danh sách hộ và tên sv của 1 lớp, rồi in ra ds theo thứ tự kiểu vietnam, với yêu cầu tiết kiệm bộ nhớ tối đa
http://codepad.org/AestuA02
6. Overloading Operator
6.1 Xây dựng cấu trúc phân số , hàm tiện ích xác lập phân số ( setpPS(int,int), hàm tối giản phân số, và đa năng hóa các toán tử +,-,*,/, ++,--
http://codepad.org/komYO9li
6.3 Xây dựng cấu trúc Time và các đa năng hóa toán tử cần thiết
http://codepad.org/0KdeLib3
7. Array + overloading operator
7.1 xây dựng cấu trúc matrix với các trường kiểu nguyên R và C để xác định số hàng và số cột của mà trận, trường float ** data để cấp phát bộ nhớ động dùng mảng hai chiều. Và định nghĩa các phép toán +, * để cộng và nhân 2 ma trận ** sau khi cài đặt xong các phép toán, hãy khai báo các matran a,b,c,d tương ứng và thực hiện biểu thức a=b+c; in ra a, d=b*c; in ra d;
http://codepad.org/IIsKsTvQ
Sau do cho a=b+c; và d=b*c; 2000 lần ( lặp); rồi in kết quả a,d và so sánh với các kết quả ở trên !! ( về nguyên tắc thì a và d phải không đổi, vì b,c không đổi thì chạy bao nhiêu lần, kết quả vẫn không thay đổi, nhưng thực tế?, hãy tìm hiểu nguyên nhân tại sao)
- Chắc thầy định nói đến mấy cái đồng bộ tiến trình, cơ mà mình chạy 10k lần vẫn thấy ra kết quả đúng. CHS :))
8. Array and Pointer
8.1 Chép chương trình sau, chạy, xem kết quả và giải thích những điểm bất thường trong chương trình :
#include <stdio.h>#include <conio.h> #include <string.h> void main() { int i,m[5]; char x1[10],x2[10]; char *s1,*s2; for (i=1; i<7;i++) i[m] =i*2; for (i=1;i<7;i++) printf(“\n m[%d] = %d”,i,m[i]); s1= new char[10]; s2= new char[10]; strcpy(s2,”xau 2”); strcpy(s1,”Dai hoc bach khoa ha noi”); printf(“\n s1= %s”,s1); printf(“\n s2= %s”,s2); strcpy(x2,”xau x2”); strcpy(x1,”Dai hoc bach khoa ha noi”); printf(“\n x1= %s”,x1); printf(“\n x2= %s”,x2); getch(); }
( Lưu ý về phạm vi của mạng, cách sử dụng i[m]=…, giải thích tại sao kết quả đối với mảng m vẫn dùng và chỉ ra được nguy cơ tiềm ẩn. So sánh s1,s2 với x1,x2, giải thích cơ chế thực hiện !)
- Trong bài này ta thấy khi cố tình truy cập ngoài phạm vi cấp phát của mảng, ta có thể thu được các giá trị không được mong muốn. Rõ ràng, mảng là con trỏ nên việc truy cập ra ngoài mảng là hoàn toàn hợp lệ, máy tình không phân biệt điều này. Tuy nhiên, rất có thể vùng nhớ mà ta truy cập ngoài mảng đã được cấp phát cho 1 tiến trình khác nên khi ta truy cập vượt mảng sẽ đem lại những kết quả không như mong muốn.
- Mảng hay con trỏ là 1, giả sử ta a là địa chỉ của phần tử đầu tiên trong mảng, ta thấy phép truy cập a[i] và *(a+i) là hoàn toàn giống nhau. Mặt khác do phép cộng có tính chất phân phối nên *(a+i) hay *(i+a) là như nhau. Vậy truy cập i[m] chính là truy cập m[i].
- Trong bài này, ta có 2 khai báo char* s1, s2 là 2 con trỏ xâu và 2 mảng ký tự char x1[10], x2[10]. Các giá trị cấp pháp cạnh nhau sẽ được hệ điều hành cấp phát cho những vùng nhớ liên tục trong bộ nhớ chính. Việc truy cập các phần tử *(s1 + i) và *(s2 + i) là hoàn toàn tự do. Ta có thể ghi đè giá trị của xâu s2 lên s1, hoặc s1 hoàn toàn có thể chứa s2. Tuy việc truy cập các phần tử của mảng ký tự cũng tự do như con trỏ, nhưng khi ta ghi đè giá trị của 2 vùng nhớ cấp phát của 2 mảng này lên nhau có thể gây ra lỗi (hệ điều hanh không cho phép)
- Tham khảo code :
#include <stdio.h>
#include <conio.h>
#include <string.h>
int main() {
int i,m[11],l,n;
char x1[10],x2[10];
char *s1,*s2;
n = 1000;
for (i=1; i<50;i++) i[m] =i*2;
n = 1000;
for (i=-5;i<50;i++) printf("\n m[%0xd] = %d %d %0xd %0xd",&i,m[i],i,&n,&l);
s1= new char[10];
s2= new char[10];
strcpy(s1,"Dai hoc bach khoa ha noi1111111111111");
strcpy(s2,"xau 2");
printf("\n s1= %s %0xd",s1,&s1);
printf("\n s2= %s %0xd",s2,&s2);
strcpy(x1,"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
strcpy(x2,"xau x2");
printf("\n x1= %s %0xd",x1,&x1);
printf("\n x2= %s %0xd",x2,&x2);
getch();
}
9. Đệ quy
9.1 Viết hàm đệ qui tính tổng các chữ số chẵn( lẻ) của số nguyê n dương n
#include<iostream>
using namespace std;
int S(int n){
if(n == 0) return 0;
else {
int hangdonvi = n % 10;
if(hangdonvi % 2 == 0) return hangdonvi + S(n/10);
else return S(n/10);
}
}
main(){
int n;
cin >> n;
cout << S(n);
}
9.2 Viết Hàm đệ qui đổi 1 số nguyên dạng thập phân sang 1 cơ số bất kỳ (2,8,16)
http://codepad.org/e8S3STt9
9.3Tính S(n) = s qrt(1 + s qrt(2 + sqrt (3 + ...s qrt (n-1 + sqrt (n)))))
#include<iostream>
#include<math.h>
using namespace std;
main(){
int n;
cin >> n;
float s = sqrt(n);
for(int i = n; i > 1; i--){
s = sqrt( i-1 + s);
}
cout <<endl << s;
}
9.4 Tính S(n) = 1/2 + 3/4 + 5/6 + 7/8 +9/10 + .....
#include<iostream>
using namespace std;
float S(int n){
if(n == 1) return 0.5;
else return (float) (2*n-1)/(2*n) + S(n-1);
}
main(){
int n;
cin >> n;
cout << S(4);
}
#include<iostream>
#include<math.h>
using namespace std;
main(){
int n;
cin >> n;
float s = sqrt(n);
for(int i = n; i > 1; i--){
s = sqrt( i-1 + s);
}
cout <<endl << s;
}
9.4 Tính S(n) = 1/2 + 3/4 + 5/6 + 7/8 +9/10 + .....
#include<iostream>
using namespace std;
float S(int n){
if(n == 1) return 0.5;
else return (float) (2*n-1)/(2*n) + S(n-1);
}
main(){
int n;
cin >> n;
cout << S(4);
}
10. Phong cách lập trình
10.1 Ap dung cac ky thuat phan tich, thiet ke va cai dat cung phong cach lap trinh trong vi du “Text formatting”. Tien hanh phan tich thiet ke va cai dat bai toan sau :
Cho mot xau ky tu gom day cac so co 3 chu so co dang nhu sau : “101,102,103,104,201,202,205,206,207,208,209,210,212,215,301,302,303,304,305,401,403….” ( do dai tuy y)
Hay to chuc lai de in ra ket qua tren nhieu dong, moi dong khong qua 32 ky tu. Noi dung moi dong co dang nhu sau :
101-104,201,202,205-210,212,215 301-305,401,403 ….
(tức là nếu dãy các số liên tục gồm nhiều hơn 3 số thì đưa về dạng somin-somax)
http://codepad.org/1loQGY3t
______________________________________________________________________________
<3
Trả lờiXóa