Con trỏ
I Khái niệm con trỏ và biến con trỏ
A Khái niệm
1, Khái niệm Con Trỏ:
Một con trỏ là
1 biến chứa một địa chỉ bộ nhớ, địa chỉ này là vị trí của 1 đối tượng khác (thường
là 1 biến) trong bộ nhớ. Nếu một biến chứa địa chỉ của một biến khác, biến thứ
nhất được gọi là trỏ đến biến thứ hai.
2,Biến con trỏ:
Nếu một biến sẽ
chứa địa chỉ của một biến khác thì nó phải được khai báo là một con trỏ. Khai
báo 1 biến là là con trỏ gồm dữ liệu cơ sỏ, một dấu * và tên biến. Dạng tổng
quát để khai báo một biến con trỏ là:
type*pointerVariable;
type: Xác định kiểu dữ liệu của biến mà con trỏ có thể trỏ đến.
Ví dụ con trỏ có kiểu int sẽ trỏ đến
biến có kiểu int. Do các phép toán số
học trên con trỏ (tăng, giảm) liên quan đến type của nó cần phải khai báo type của con trỏ đúng đắn.
3,Khai báo / cấp phát / hủy Con Trỏ
Khai báo:
DataType*PointerVariable;
Cấp phát:
PointerVariable = new DataType;
Hủy bộ nhớ:
Delete PointerVariable;
Ex:
Bài tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *p , *t;
p = new int;
t = new int;
*p = 100;
*t = 1000;
*p = *t;
cout<<"Dia chi con tro:"<<t<<endl;
cout<<"Gia tri ma con tro:"<<*t;
delete t;
return 0;
}
II Các toán tử con trỏ
Có 2 toán tử
con trỏ quan trọng là toán tử * và &
1 Toán tử con trỏ &
Toán tử &
là toán tử 1 ngôi mà trả về địa chỉ bộ nhớ của toán hạng của nó. (toán tử 1
ngôi chỉ yêu cầu 1 toán hạng).
Vd:
int count;
int *m;
m = &count;
Lệnh m =
&count đặt địa chỉ bộ nhớ của biến count vào con trỏ m.
Lệnh trên được
phát biểu: “Con trỏ m nhận địa chỉ của biến count.”.
Ex:
Gỉa sử biến
count được cấp phát tại địa chỉ bộ nhớ 2000 để lưu trữ giá trị của nó.Gỉa sử
count có giá trị 100. Như vậy , tại địa chỉ bộ nhớ 2000 có chứa giá trị 100.
Sau lệnh m = &count; được thực hiện thì m sẽ có giá trị là 2000.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int count = 1000;
int *m;
m = new int;
*m = 100;
cout<<"Truoc khi chua tro: "<<*m<<endl;
m = &count;
cout<<"Sau khi tro den: "<<*m;
return 0;
}
2 Toán tử con trỏ *
Toán tử con trỏ
* là toán tử một ngôi trả về giá trị tại địa chỉ con trỏ trỏ đến
Vd: q = *m;w
Lấy giá trị tại
địa chỉ mà m trỏ đến và đặt vào biến q. Như vậy q sẽ có giá trị là 100 (là giá
trị của biến count).
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *m , p;
m = new int;
*m = 100;
p = *m;
cout<<"Gia tri bien: "<<p;
return 0;
}
Bài tập
minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int count = 100;
int *m = &count;
cout<<"Dia chi cua bien count:"<<&count<<endl;
cout<<"Gia tri cua bien count:"<<count<<endl;
cout<<"Dia chi cua bien m:"<<m<<endl;
cout<<"Gia tri cua bien m:"<<*m<<endl;
int p = *m;
cout<<"Gia tri p:"<<p<<endl;
int *x = m;
cout<<"Dia chi cua bien x: "<<x<<endl;
cout<<"Gia tri cua bien x: "<<*x<<endl;
*m = 1000;
cout<<"Dia chi cua bien x: "<<x<<endl;
cout<<"Gia tri cua bien x: "<<*x<<endl;
cout<<"Gia tri cua bien count: "<<count<<endl;
return 0;
}
Giải
thích:
Ta có: 1 biến
count = 100
Có 1 biến m trỏ
đến quản lý địa chỉ count = 100
ð
*m
có giá trị là 100
Tiếp ta gán biến
p = *m è p có
giá trị là 100
Ta tạo thêm con
trỏ *x cung tham quản lý địa chỉ count cùng *m nên è if *m thay đổi thi *x và count có giá
trị đều thay đổi giống như *m
III Các thao tác trên con trỏ
1 Lệnh gán con trỏ
Ta có thể dùng
1 con trỏ ở bên phải của câu lệnh gán (=) để gán giá trị của 1 con trỏ cho 1 con trỏ khác. Ví dụ:
int x;
int *p1, *p2;
p1 = &x;
p2 = p1;
Sau khi đoạn lệnh
được thực hiện , cả hai p1 và p2 cùng trỏ đến biến x.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 1882002;
int *p1, *p2;
p1 = &x;
p2 = p1;
cout<<"Gia tri p1 truoc khi gan lai: "<<*p1<<endl;
cout<<"Gia tri p2 truoc khi gan lai: "<<*p1<<endl;
*p2 = 100;
cout<<"Gia tri p1 sau khi gan lai: "<<*p1<<endl;
cout<<"Gia tri p2 sau khi gan lai: "<<*p2<<endl;
return 0;
}
2 Phép toán số học trên con trỏ
Chỉ có 2 phép
toán số học ta có thể dùng trên con trỏ đó là cộng và trừ. Gỉa sử p1 là một con
trỏ nguyên với giá trị hiện tại là 2000. Cũng giả sử rằng số nguyên chiếm 2
bytes bộ nhớ. Như vậy, sau khi thực hiện lệnh p1++; thì có giá trị là 2002 chứ
không phải là 2001 . Tương tự, giả sử p1 là một con trỏ nguyên với giá trị hiện
tại là 2000. Cũng giả sử rằng số nguyên chiếm 2 bytes bộ nhớ. Như vậy , sau khi
thực hiện lệnh p1--; thì p1 có giá trị là 1998 chứ không phải là 1999
VD:
Con trỏ i chứa
địa chỉ 3000 vậy lệnh:
i = i + 2;
i sẽ chứa địa
chỉ 3004
Lưu ý : Đơn vị tăng của con trỏ char là 1 Byte,
con trỏ int là 2 Bytes.
Tương tự, giả sử
con trỏ char ch chứa địa chỉ 3003, vậy lệnh
ch = ch – 3;
Bài tập
Cho a = 20 , b
= 15
Hoán đổi thành
a = 15 , b = 20;
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a = 20 , b = 15;
int *pa , *pb, temp;
pa = &a;
pb = &b;
temp = *pa;
*pa = *pb;
*pb = temp;
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
return 0;
}
IV Con trỏ Void và con trỏ Null
1 Con trỏ Void
Kiểu dữ liệu
khai báo biến con trỏ chính là kiểu dữ liệu mà con trỏ có thể trỏ đến , địa chỉ
đặt vào biến con trỏ đến địa chỉ đặt vào biến con trỏ phải cùng kiểu với kiểu
con trỏ. Xem xét đoạn mã sau:
Lưu ý:
int a;
float f;
int *pa;
float *pf;
/*
Những lệnh sau là hợp lệ:
pa = &a;
pf = &f;
Những lệnh sau là không hợp lệ
pa = &f; // pa là con trỏ int do đó chỉ chứa địa chỉ của biến kiểu int
pb = &a; // pb là con trỏ float do đó chỉ chứa chỉ chứa địa chỉ của kiểu float
*/
Con trỏ void là
một loại con trỏ đặc biệt mà có thể trỏ đến bất kỳ dữ liệu nào. Cú pháp khai
báo con trỏ như sau:
Void*pointerVariable;
Nếu ta khai báo
con trỏ void sau:
Void*p;
Thì các lệnh
sau đây là hợp lệ
P = &a; //
sau lệnh này p trỏ đến biến số nguyên a;
P = &f; //
sau lệnh f trỏ đến biến số thực f;
Tuy nhiên, tùy
thuộc con trỏ void đang trỏ đến kiểu dữ liệu nào, ta phải ép đúng kiểu tương ứng
khi dùng trong các biểu thức
Vd:
P đang trỏ đến
biến nguyên a, để tăng giá trị của biến a lên 10 ta phải dùng lệnh a sau:
(int*)*p+10;
Nếu p đang trỏ
đến biến thực f, để tăng giá trị của biển f lên 10:
Phải sử dụng
lênh: (float*)*p+10;
2 Con trỏ NULL
Một con trỏ hiện
hành không trỏ đến một địa chỉ bộ nhớ hợp lệ thì gán giá trị NULL. Bởi vì qui ước
, con trỏ NULL là con trỏ không trỏ đến đâu cả và không nên dùng.
Nếu chương
trình vô tình dùng con trỏ NULL như dưới đây thì sẽ nhận lỗi khi thực thi
chương trình (run-time error).
int*p;
cout<<”Gia
tri con tro p tro đến la: “<<*p;
Bài tập minh họa
Con trỏ
void
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a = 10;
float b = 8.8;
int *pa = &a;
float *pb = &b;
void *p;
p = &a;
(*(int*)p) = 100;
p = &b;
(*(float*)p) = 99.9;
cout<<"Gia tri a: "<<a<<endl;
cout<<"Gia tri b: "<<b<<endl;
return 0;
}
Con trỏ Null
#include <bits/stdc++.h>
using namespace std;
int main()
{
/*
int *a;
cout<<"Gia tri tri cua bien a: "<<*a<<endl;
cho ra gia tri rong
Loi run time error
*/
int *a = new int;
cout<<"Gia tri tri cua bien a: "<<*a;
// ==> cho ra 1 gia tri bat ky
return 0;
}
V Con trỏ và mảng
Giữa mảng và
con trỏ có một mối quan hệ gần. Xem xét đoạn mã dưới đây:
Char ch[80],
*p;
p = ch;
p |
p + 1 |
p + 2 |
p + 3 |
p + 4 |
p + 5 |
p + 6 |
p + 7 |
p + 8 |
p + 9 |
Ch[0] Ch[1] Ch[2]
Ch[3] Ch[4]
Ch[5] Ch[6]
Ch[7] Ch[8] Ch[9]
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[]={0,1,2,3,4,5,6,7,8,9};
for(int i = 0 ; i < 10 ; i++)
{
cout<<a[i]<<" ";
}
int *p = a;
cout<<endl;
for(int i = 0 ; i < 10 ; i++)
{
cout<<*(p+i)<<" ";
}
// *(p+i) == a[i]
return 0;
}
VI Mảng con trỏ
Mảng con trỏ là
một biến đơn . Ta có thể tạo mảng của các con trỏ. Mỗi phần tử của mảng là một
con trỏ thông thường . Cú pháp khai báo mảng con trỏ là:
type *pointerArray[elements];
type: kiểu dữ liệu mà các con trỏ phần tử trỏ
đến.
pointerArray:
tên mảng con trỏ.
Elements:
số phần tử của mảng con
trỏ.
Ví dụ:
int *p[5]; lệnh
này khai báo mảng con trỏ p có 5 phần tử.
Các lệnh dưới
đây minh họa cách sử dụng mảng này:
P[0] = &a;
//gán địa chỉ của biến nguyên a cho con trỏ p[0]
P[2] = p[0];
//sao chép địa chỉ có trong p[0] và p[2]
b = *p[0];//gán
giá trị tại địa chỉ p[0] trỏ đến vào biến b.
trường hợp này
, lệnh trương đương với b=a; vì hiện tại p[0] chứa địa chỉ của biến a.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *p[5];
for(int i = 0 ; i < 5 ; i++)
{
p[i] = new int;
*p[i] = 2*i;
}
for(int i = 0 ; i < 5 ; i++)
{
cout<<"Dia chi: "<<p[i]<<"==> "<<"Gia tri: "<<*p[i]<<endl;
}
return 0;
}
Lưu ý: Khi khai báo mảng con trỏ cần phải cấp
phát bộ nhớ cho từng phần của mảng con trỏ
VII Tương quan giữa mảng 2 chiều và con trỏ cấp
2
Con trỏ cấp 2
int **p = new int*[5];
for(int i = 0 ; i < 5 ; i++)
{
*(p+i)=new int[7];
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
p[i][j] = i + j
}
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
//cach 1: cout<<p[i][j]<<endl;
//cach 2: cout<<*(*(p+i)+j)<<endl;
}
cout<<endl;
}
Bài
tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int **p = new int*[5];
for(int i = 0 ; i < 5 ; i++)
*(p+i) = new int[7];
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
p[i][j] = i + j;
}
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
cout<<*(*(p+i) + j)<<"\t";
}
cout<<endl;
}
return 0;
}
Bài tập rèn luyện
Bài 1:
Viết hàm hoán vị
hai biến thực a, b bằng cách sử dụng con trỏ (đối vào là hai con trỏ). Viết
chương trình chính nhập hai số thực a,b. Sử dụng hàm để đổi chỗ a và b.
Code:
#include <bits/stdc++.h>
using namespace std;
void hoanvi(float a , float b)
{
float *pa, *pb, temp;
pa = &a;
pb = &b;
temp = *pa;
*pa = *pb;
*pb = temp;
cout<<"a:"<<a<<endl;
cout<<"b:"<<b;
}
int main()
{
float a,b;
cin>>a>>b;
hoanvi(a,b);
return 0;
}
Bài 2:
Viết chương trình nhập vào một mảng a gồm n phần tử nguyên
ngẫu nhiên [0…100]. Sắp xếp mảng theo chiều giảm dần (lưu ý sử dụng tên mảng
như con trỏ và sử dụng con trỏ).
Code:
#include <bits/stdc++.h>
using namespace std;
void NhapMang(int *&a, int n)
{
a = new int[n];
for(int i = 0 ; i < n ; i++)
{
cin>>*(a+i);
}
}
int main()
{
int n;
cin>>n;
int *a = new int[n];
for(int i = 0 ; i < n ;i++)
cin>>*(a+i);
for(int i = 0 ; i < n ; i++)
cout<<*(a+i)<<" ";
cout<<endl;
for(int i = 0 ; i < n - 1 ; i++)
{
for(int j = i + 1 ; j < n ; j++)
{
if(*(a+i) *(a+j))
{
int temp = *(a+i);
*(a+i) = *(a+j);
*(a+j) = temp;
}
}
}
for(int i = 0 ; i < n ; i++)
cout<<*(a+i)<<" ";
return 0;
}
Bài 3:
Hãy viết hàm để
nhập / xuất vào một ma trận vuông cấp n với các số ngẫu nhiên [-50,100] và hàm
tìm phần tử Max của ma trận này (dùng con trỏ thay thế cho mảng 2 chiều).
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int **a = new int*[n];
for(int i = 0 ; i < n ; i++)
*(a+i) = new int[m];
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
cin>>*(*(a+i)+j);
}
}
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
cout<<*(*(a+i)+j)<<"\t";
}
cout<<endl;
}
int Max = a[0][0];
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
if(*(*(a+i)+j) > Max)
Max = *(*(a+i)+j);
}
}
cout<<"Gia tri lon nhat: "<<Max;
return 0;
}
Xử lý
chuỗi
I Khái niệm và cấu trúc của chuỗi
1. Khái
niệm
· Chuỗi là một mảng ký tự được
kết thúc bằng ký tự null (‘\0’).
· Ký tự null (‘\0’) là ký tự dùng để
kết thúc Chuỗi
· Hằng
chuỗi là Chuỗi được bao quanh bởi cặp dấu nháy đôi.
Ví
dụ:
“Hello”
· Ví dụ: để
khai báo một mảng str chứa chuỗi có độ dài 20 ký tự , ta khai báo:
char str[21];
Có thể
dùng Con trỏ để khai báo: char *str;
‘H’ |
‘e’ |
‘l’ |
‘l’ |
‘o’ |
‘\0’ |
str[0]
str[1] str[2] str[3] str[4] str[5]
str[5] è Ký tự
null
2. Cách khai
báo và khởi tạo chuỗi
· Có 2
cách khai báo và khởi tạo Chuỗi
- Cách 1: Dùng
mảng một chiều
char<Tên Biến>[Chiều dài tối đa]
o
Ví dụ: char str[12;
o Ví dụ: char str[25];
§ Ý
nghĩa khai báo một mảng kiểu ký tự tên là str có 25 phần tử (như vậy tối đa ta
có thể nhập 24 ký tự vì phần tử thứ 25 đã chứa ký tự kết thức chuỗi ‘\0’.
§ Lưu ý:
Chuỗi ký tự được kết thúc bằng ký tự ‘\0’.Do đó khai báo độ dài của chuỗi luôn
luôn khai báo dư 1 phần tử để chứa ký tự ‘\0’.
- Cách 2: Dùng
con trỏ
char *<Tên biến>
o
Ví dụ: char *<Tên biến>
§ Trong
khai báo này, bộ nhớ sẽ dành 2 byte để lưu trữ địa chỉ của biến con trỏ str
đang chỉ đến, chưa cung cấp nơi để lưu trữ dữ liệu.
v Trước
khi sử dụng phải dùng từ khóa new để cấp phát vùng nhớ.
o Ví dụ:
§
char *str;
§ str = new char[51]; // Cấp phát 51 ký tự
v Chuỗi
ký tự giống như mảng do đó để khởi tạo một Chuỗi ký tự với giá trị xác định ta
có thể thực hiện tương tự như với mảng.
char<biến>[]=<”Hằng Chuỗi”>
o Ví dụ:
char str[] = {‘H’, ’e’, ’l’, ’l’,
’o’, ’\0’};
char str[] = “Hello”;
char *str = “Hello”;
‘H’ |
‘e’ |
‘l’ |
‘l’ |
‘o’ |
‘\0’ |
str[0] str[1] str[2]
str[3] str[4]
str[5]
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char *str = "Hello";
cout<<str<<endl;
char str2[]="Obama";
cout<<str2<<endl;
char str3[]={'K','i','m','j','o','n','n','g','\0'};
cout<<str3<<endl;
char str4[10];
str4[0] = 'P';
str4[1] = 'u';
str4[2] = 't';
str4[3] = 'i';
str4[4] = 'n';
cout<<str4;
return 0;
}
II Cách xuất chuỗi – nhập cuối
Để nhập dữ liệu cho biến chuỗi, ta dùng tham gets():
char *gets(char *s);
Hàm gets()
đọc các ký tự từ bàn phím vào trong mảng con trỏ đén bởi s cho đến
khí nhấn Enter. Ký tự null
sẽ được đặt sau ký tự cuối cùng của chuỗi nhập vào trong mảng.
Lưu ý: Khi
dung cin>> để nhập dữ liệu chuỗi,
chương trình sẽ tự động ngắt chuỗi khi gặp ký tự khoảng trắng trong chuỗi. Do
đó, để chuỗi không bị ngắt khi gặp ký tự khoảng trắng, ta sẽ dùng hàm gets(), hoặc cin.getline() thay vì hàm cin thông thường
.
*cin.getline(chuỗi,số ký tự tối đa);
*Ví dụ:
o
char *str;
o
str = new char[30];
o
cin.getline(str,30);
Hàm để xuất chuỗi ra màn hình, ta dùng hàm puts():
int puts(const char *s);
Hoặc ta có thể dùng cout
cout<<s;
Ex 1:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char str[30];
cout<<"Nhap chuoi:";
gets(str);
cout<<"Xuat chuoi:";
puts(str);
return 0;
}
Ex 2:
#include <bits/stdc++.h>
using namespace std;
#define MAX 255
int main()
{
char str1[MAX];
char *str2;
cout<<"Nhap chuoi str1: ";
gets(str1);
str2 = new char[MAX];
cout<<"Nhap chuoi str2: ";
cin.getline(str2,MAX);
cout<<"Chuoi str1: "<<str1<<endl;
cout<<"Chuoi str2: ";
puts(str2);
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
char str1[25];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
char *str2 = new char[50];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
char str3[50];
cout<<"Moi ban nhap chuoi: ";
cin.getline(str3,50);
cout<<"Chuoi cua ban sau khi nhap: ";
cout<<str3;
cout<<endl;
char *str4 = new char[50];
cout<<"Moi ban nhap chuoi: ";
cin.getline(str4,50);
cout<<"Chuoi cua ban sau khi nhap: ";
cout<<str4;
return 0;
}
Hàm strlen
Tính độ
dài của chuỗi s
-strlen(char *s);
Thư viện hàm: #include <string.h>
void main()
{
char *ch = “Lap trinh C”;
cout<<”Do
dai s =”<<strlen(ch);
}
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[25];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
cout<<"Kich thuoc ban nhap: "<<strlen(str1)<<endl;
return 0;
}
III Hàm strcpy ,strncpy – sao chép chuỗi
1 Hàm strcpy
Ø Để sử
dụng các hàm này, ta phải khai báo dòng lệnh sau:
#include <string.h>
Ø Sao
chép nội dung chuỗi nguồn vào chuỗi đích , nội dung của chuỗi đích sẽ bị xóa.
Strcpy(char *đích, char *nguồn);
Ex:
Sao chép s1 vào s2: strcpy(s2,s1)
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[20], str2[40];
gets(str1);
strcpy(str2,str1);
puts(str2);
return 0;
}
2 Hàm strncpy
Ø Chép n
ký tự từ chuỗi nguồn sang chuỗi đích. Nếu chiều dài nguồn < n thì hàm sẽ điền
khoảng trẳng cho đủ n ký tự vào đích.
strncpy (char *đích, char *nguồn, int n);
Ví dụ:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[20],str2[20];
cout<<"Nhap chuoi 1:";
gets(str1);
strncpy(str2,str1,5);
cout<<"Xuat chuoi 2:";
puts(str2);
return 0;
}
IV Hàm strcat , strncat – nối chuỗi
1 Hàm strcat
Nối chuỗi s2 vào cuối chuỗi s1
#include <bits/stdc++.h>
#include <string.h>
int main()
{
char *s1 = new char[50];
gets(s1);
char *s2 = new char[50];
gets(s2);
strcat(s1,s2);
puts(s1);
return 0;
}
2 Hàm strncat
Ø Hàm n
ký tự đầu tiên của chuỗi s2 vào chuỗi s1
strncat(char s1[],char s2[],int n);
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[20], s2[20];
strcpy(s1,"To be ");
strcpy(s2,"or not to be");
strncat(s1,s2,6);
cout<<"Ket qua: "<<s1;
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[50],s2[50];
gets(s1),gets(s2);
strcat(s1,s2);
puts(s1);
char *s3 = new char[50],*s4 = new char[50];
strcpy(s3,"I love ");
strcpy(s4,"you");
strncat(s3,s4,3);
cout<<s3;
cout<<endl;
char ho[50],ten[50],hovaten[50];
cout<<"Ho: ";
gets(ho);
cout<<"Ten: ";
gets(ten);
strcpy(hovaten,"");
strcpy(hovaten,ho);
strcat(hovaten,ten);
puts(hovaten);
return 0;
}
V Hàm strchr , strstr – tìm ký tự , chuỗi
1 Hàm strchr
strchr(s1,ch): Trả về con trỏ đến vị trí xuất
hiện đầu tiên của ký tự ch trong Chuỗi s1
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *p,h,str1[20];
cout<<"Nhap chuoi 1:";
gets(str1);
cout<<"Nhap ky tu muon tim:";
cin>>h;
p = strchr(str1,h);
if(p == "\0") // Ghi NULL Hoac "\0" <=> NULL = "\0"
cout<<"Khong tim thay";
else
cout<<"Tim thay vi tri:"<<(p-str1);
return 0;
}
Ex:
Nhập chuỗi ký tự là: hello
Nhập ký tự cần tìm là l
h |
e |
l |
l |
o |
[0] [1] [2] [3] [4]
è vị
trí l cần tìm là vị trí số 2
2 Hàm strstr
Ø strstr(s1,s2): Trả về con trỏ đến vị trí xuất
hiện đầu tiên của chuỗi s2 trong s1.
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *p, str1[20],str2[20];
cout<<"Nhap chuoi 1:";
gets(str1);
cout<<"Nhap chuoi 2:";
gets(str2);
p = strstr(str1,str2);
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay tai vi tri:"<<(p-str1);
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[50];
strcpy(str1,"hello");
char *p = strchr(str1,'l');
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay 'l' tai vi tri:"<<(p-str1);
cout<<endl;
char str3[50],str4[50];
strcpy(str3,"Quanh nam buon ban o mom song nuoi du 5 con voi 1 chong");
strcpy(str4,"chong");
char *z = strstr(str3,str4);
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay 'chong' tai vi tri:"<<(z-str1);
return 0;
}
VI Hàm strcmp, strcncmp – So sánh chuỗi
1 Hàm strcmp
Ø So
sánh 2 chuỗi s1 và s2 theo nguyên tắc thứ tự từ điển. Phân biệt chữ hoa và thường.
Trả về:
o
0 : if s1 ==
s2
o
>0 : if s1 lớn hơn s2
o
<0 : if s1 bé hơn s2
strcmp(char s1[],char s2[]);
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *s1 = "a";
char *s2 = "a";
int ret = strcmp(s1,s2);
if(ret == 0)
cout<<"2 thang do bang nhau"<<endl;
if(ret > 0)
cout<<"thang 1 lon hon thang 2"<<endl;
if(ret < 0)
cout<<"thang 2 lon hon thang 1"<<endl;
return 0;
}
2 Hàm strncmp
Ø int strncmp(const char *str1, const char
*str2, size_t n)
o
0 : if
str1 == str2
o
>0 : if str1 lớn hơn str2
o
<0 : if str1 bé hơn str2
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[50],str2[50];
strcpy(str1,"abcd chao");
strcpy(str2,"abcd");
int ret = strncmp(str1,str2,4);
if(ret == 0)
cout<<"str1 is equal to str2"<<endl;
if(ret > 0)
cout<<"str2 is less than str1"<<endl;
if(ret < 0)
cout<<"str1 is less than str2"<<endl;
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[50],s2[50];
strcpy(s1,"Xin chao!");
strcpy(s2,"obama!");
int ret = strcmp(s1,s2);
if(ret == 0)
cout<<"str1 is equal to str2"<<endl;
if(ret > 0)
cout<<"str2 is less than str1"<<endl;
if(ret < 0)
cout<<"str1 is less than str2"<<endl;
char s3[50],s4[50];
strcpy(s3,"Xin chao!");
strcpy(s4,"obama!");
int rets = strncmp(s3,s4,4);
if(ret == 0)
cout<<"str3 is equal to str4"<<endl;
if(ret > 0)
cout<<"str3 is less than str4"<<endl;
if(ret < 0)
cout<<"str4 is less than str3"<<endl;
return 0;
}
VI Hàm toupper , tolower – In Hoa , Thường
Ø Hàm
toupper: Chuyển ký tự thường sang ký tự hoa
o
toupper(int
ch);
Ø Hàm
tolower: Chuyển ký tự hoa sang ký tự thường
o
tolower(ịnt
ch);
Bài tập minh họa:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[] = "obama hahaha ali33";
int n1 = strlen(str1);
for(int i = 0 ; i < n1 ; i++)
{
char c = str1[i];
putchar(toupper(c));
}
cout<<endl;
char str2[] = "obama hahaha ali33";
int n2 = strlen(str2);
for(int i = 0 ; i < n2 ; i++)
{
char c = str2[i];
putchar(tolower(c));
}
return 0;
}
Bài tập tự luyện
Bài 1:
Viết chương trình nhập một chuỗi ký tự từ bàn phím, xuất ra
màn hình mã ASCII của ký tự vừa nhập vào (gợi ý mỗi ký tự trên một dòng).
Code:
#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char s[50];
cout<<"Moi ban nhap chuoi:";
gets(s);
int k = strlen(s);
for(int i = 0 ; i < k ; i++)
{
char c = *(s+i);
cout<<"ASCII: "<<(int)c<<endl;
}
return 0;
}
Bài 2:
Viết chương trình nhập 1 chuỗi ký tự từ bàn phím , xuất ra
màn hình đảo ngược của chuỗi đó.Ví dụ của “abcd egh” là “hge dcba”.
Code:
Cách 1:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *s = new char[50];
cout<<"Moi ban nhap chuoi: ";
gets(s);
int k = strlen(s);
for(int i = k - 1 ; i >= 0 ; i--)
cout<<*(s+i);
return 0;
}
Cách 2:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s[50];
strcpy(s,"abcd egh");
int k = strlen(s);
for(int i = k - 1 ; i >= 0 ; i--)
cout<<*(s+i);
return 0;
}
Bài 3:
Viết chương nhập một chuỗi ký tự.
a) In ra
màn hình từ bên trái nhất và phần còn lại của chuỗi
Ex:
Input: “Nguyễn Văn Minh”
Output:
Nguyễn
Văn
Minh
Code:
#include <bits/stdc++.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
char *s = new char[100];
cout<<"Moi ban nhap chuoi ky tu: ";
//input char
gets(s);
//count char
int k = strlen(s);
//find ' '
char *p = strchr(s,' ');
int z = p - s;
char *sdau = new char[50];
strncpy(sdau,s,z);
cout<<sdau;
cout<<endl;
for(int i = z + 1; i < k ; i++)
cout<<*(s+i);
return 0;
}
b) In ra
màn hình từ bên phải nhất và phần còn lại của chuỗi
Ex:
Input: ”Nguyễn Văn Minh”
Output:
Minh
Nguyễn Văn
Code:
#include <bits/stdc++.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
// Nguyen van Minh
//==>hniM naV neyugN
char *s = new char[100];
cout<<"Moi ban nhap chuoi ky tu: ";
//input char
gets(s);
//count char
int k = strlen(s);
char *z;
char *p = strchr(s,' ');
char num[50];
int j = 0;
for(int i = k - 1 ; i >= 0 ; i--)
{
num[j] = *(s+i);
j++;
if(*(s+i) == ' ')
break;
}
for(int i = j - 2 ; i >= 0 ; i--)
cout<<num[i];
cout<<endl;
char *sdau = new char[50];
strncpy(sdau,s,k-j+1);
cout<<sdau;
return 0;
}
Kiểu dữ
liệu có cấu trúc
I Khái niệm và cách khai báo có cấu trúc
1. Khái
niệm
Structures
Một cấu trúc là một tập hợp các biến được
tham chiếu thông qua một tên chung. Một khai báo cấu trúc thành 1 khuôn mẫu
(template) mà có thể dùng để tạo nên các biến cấu trúc có cùng kiểu. Những biến
tạo mà tạo nên cấu trúc được gọi là các thành viên (members).
Nói gắn ngọn: Thực ra nó là một kiểu dữ liệu
phức hợp do ta tạo ra
2. Dạng tổng
quát của một khai báo cấu trúc
struct structureName
{
type member_1;
type member_2;
…
type member_n;
…
}varNames;
Struct: Từ khóa tạo cấu trúc trong C++
structureName: Tên của cấu trúc
type: Kiểu dữ liệu của thành viên tương ứng
member_1,member_2,…,member_n:Tên các biến thành viên của cấu trúc
varNames:Tên các biến cấu trúc phân cách
nhau bằng dấu phẩy.
Ví dụ:
struct addr
{
char name[30];
char street[30];
char city[30];
char state[30];
unsinged long int zip;
};
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct DiaChi
{
char sonha[25];
char TenDuong[250];
char Quan[25];
char TinhThanh[25];
};
struct SinhVien
{
char MaSV[10];
char TenSV[255];
bool GioiTinh;
DiaChi Diachinha;
DiaChi Diachitruong;
}teo,ty;
II Truy cập các biến thành viên của biến cấu
trúc
Nội dung:
Toán tử dấu chấm (dot operator) dùng để truy cập (access)
các thành viên của một biến cấu trúc. Dạng tổng quát để truy cập một thành viên
của một biến cấu trúc là:
structureName.memberName
Ví dụ: Xem xét khai báo cấu trúc sau
Struct coordXY
{
int x;
int y;
}diemA,diemB;
Để gán giá trị tọa độ cho diemA, ta dung lệnh sau:
diemA.x = 100;
diemA.y = 200;
Để in tạo độ điểm A, ta dùng lệnh sau:
cout<<”A(“<<diemA.x<<”,”<<diemA.y<<”)”;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct DiaChi
{
char sonha[25];
char TenDuong[250];
char Quan[25];
char TinhThanh[25];
};
struct SinhVien
{
char MaSV[10];
char TenSV[255];
bool GioiTinh;
DiaChi Diachinha;
DiaChi Diachitruong;
}teo,ty;
int main()
{
strcpy(teo.TenSV,"Nguyen Van Teo");
strcpy(teo.MaSV,"SV123");
teo.GioiTinh == false;
cout<<"------------------------\n";
cout<<"Ma: "<<teo.MaSV<<endl;
cout<<"Ten: "<<teo.TenSV<<endl;
cout<<"Gioi: "<<(teo.GioiTinh == true ? "Nu":"Nam")<<endl;
cout<<"------------------------\n";
SinhVien Luyen;
strcpy(Luyen.TenSV,"Le Van Luyen");
strcpy(Luyen.MaSV,"SV1234");
Luyen.GioiTinh == false;
cout<<"------------------------\n";
cout<<"Ma: "<<Luyen.MaSV<<endl;
cout<<"Ten: "<<Luyen.TenSV<<endl;
cout<<"Gioi: "<<(Luyen.GioiTinh == true ? "Nu":"Nam")<<endl;
cout<<"------------------------\n";
return 0;
}
III Lệnh gán cấu trúc
Nội dung:
Nội dung trong 1 biến cấu trúc có thể gán cho một biến cấu
trúc khác có cùng kiểu dùng một câu lệnh gán.
Ví dụ:
Để gán nội dung biến cấu trúc pointA cho pointB, ta thực hiện
lệnh sau:
pointB =
pointA;
Sau lệnh này,biến pointB có cùng nội dung như pointA.
Tuy nhiên, ta cũng có thể sao chép từng thành viên như sau:
pointB.x =
pointA.x;
pointB.y =
pointA.y;
VD:
struct book
{
char
title[30];
char
author[20];
int pages;
float price;
};
book b;
cout<<”Input book information:”<<endl;
cout<<”Title: ”;gets(b.title);
cout<<”Author:”;gets(b.author);
cout<<”Number of pages:”;cin>>b.pages;
cout<<”Price:”;cin>>b.price;
book a = b;
cout<<”Input book information:”<<endl;
cout<<”Title: ”<<a.title<<endl;
cout<<”Author:”<<a.author<<endl;
cout<<”Number of pages:”<<a.pages<<endl;
cout<<”Price:”<<a.price;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct Book
{
char title[30];
char author[20];
int pages;
float price;
};
int main()
{
Book b;
cout<<"Input book information:"<<endl;
cout<<"Title: ";
gets(b.title);
cout<<"Author:";
gets(b.author);
cout<<"Number of pages:";
cin>>b.pages;
cout<<"Price:";
cin>>b.price;
Book a = b;
cout<<"Input book information:"<<endl;
cout<<"Title: "<<a.title<<endl;
cout<<"Author:"<<a.author<<endl;
cout<<"Number of pages:"<<a.pages<<endl;
cout<<"Price:"<<a.price;
return 0;
}
III Mảng cấu trúc
Nội dung
Để khai báo một mảng cấu trúc, đầu tiên ta khai báo cấu
trúc , sau đó khai báo một mảng của cấu trúc đó.
Ta khai báo theo công thức tổng quát:
structerName
arrayName[Number of elements];
Ví dụ, khai báo mảng points có 100 phần tử, khai báo như
sau:
coordXY
points[100];
Để truy cập đến từng thành viên của phần tử của mảng, ta
dùng chỉ mục của phần tử và toán tử thành viên (.).Ví dụ, để gán tọa độ x,y cho
phần tử thứ 10, ta dùng các lệnh:
Point[9].x = 100;
Point[9].y = 200;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct SinhVien
{
int ma;
char ten[255];
};
void nhapMang(SinhVien dsSV[] , int siso)
{
for(int i = 0; i < siso ; i++)
{
cout<<"Nhap sinh vien thu "<<i<<endl;
cout<<"Nhap ma:";
cin>>dsSV[i].ma;
cout<<"Nhap ten:";
cin.ignore();
gets(dsSV[i].ten);
}
}
void XuatMang(SinhVien dsSV[] , int siso)
{
for(int i = 0 ; i < siso ; i++)
{
cout<<dsSV[i].ma<<endl;
cout<<dsSV[i].ten<<endl;
}
}
int main()
{
int n = 3;
SinhVien a[n];
cin>>n;
nhapMang(a,n);
XuatMang(a,n);
return 0;
}
IV Con trỏ cấu trúc
Nội dung
C/C++ cho phép dùng con trỏ với cấu trúc như với bất kỳ kiểu
dữ liệu nào của biến.
Cú pháp khai báo con trỏ cấu trúc giống như các loại con trỏ
khác.
Dạng tổng quát để khai báo con trỏ cấu trúc:
structureName
*structurePointers;
Và cũng phải cấp phát bộ nhớ để sủ dụng (new) , cũng dùng à để truy suất
points *p; //Khai báo con trỏ p có kiểu cấu trúc points
p = &pointA; //gán địa chỉ của biến cấu trúc pointA cho
con trỏ p
p à x =
100; //gán giá trị 100 thành viên x của biến cấu trúc pointA
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct SinhVien
{
int ma;
char ten[255];
};
int main()
{
SinhVien teo;
teo.ma = 113;
strcpy(teo.ten,"Teo");
cout<<teo.ma<<"\t"<<teo.ten<<endl;
SinhVien *ty = new SinhVien;
ty -> ma = 114;
strcpy(ty->ten,"Ty");
cout<<ty ->ma<<"\t"<<ty ->ten<<endl;
return 0;
}
Con trỏ
I Khái niệm con trỏ và biến con trỏ
A Khái niệm
1, Khái niệm Con Trỏ:
Một con trỏ là
1 biến chứa một địa chỉ bộ nhớ, địa chỉ này là vị trí của 1 đối tượng khác (thường
là 1 biến) trong bộ nhớ. Nếu một biến chứa địa chỉ của một biến khác, biến thứ
nhất được gọi là trỏ đến biến thứ hai.
2,Biến con trỏ:
Nếu một biến sẽ
chứa địa chỉ của một biến khác thì nó phải được khai báo là một con trỏ. Khai
báo 1 biến là là con trỏ gồm dữ liệu cơ sỏ, một dấu * và tên biến. Dạng tổng
quát để khai báo một biến con trỏ là:
type*pointerVariable;
type: Xác định kiểu dữ liệu của biến mà con trỏ có thể trỏ đến.
Ví dụ con trỏ có kiểu int sẽ trỏ đến
biến có kiểu int. Do các phép toán số
học trên con trỏ (tăng, giảm) liên quan đến type của nó cần phải khai báo type của con trỏ đúng đắn.
3,Khai báo / cấp phát / hủy Con Trỏ
Khai báo:
DataType*PointerVariable;
Cấp phát:
PointerVariable = new DataType;
Hủy bộ nhớ:
Delete PointerVariable;
Ex:
int *p;
p = new int; // Cấp phát bộ nhớ
// Lưu ý ta khai báo con trỏ kiểu gì thì ta cấp phát bộ nhớ kiểu dữ liệu đó
// Vd trên ta khai báo kiểu int thì ta cấp phát bộ nhớ kiểu int
*p = 100;//gán giá trị là 100 cho biến con trỏ p
cout<<"At"<<p<<" ";//sẽ cho ra địa chỉ chứa p
cout<<"Is the value"<<*p<<"\n";//sẽ cho ra giá trị của p
delete p; // thu hồi bộ nhớ
// nếu
không thu hồi bộ nhớ sẽ bị lỗi Memory Leak
Bài tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *p , *t;
p = new int;
t = new int;
*p = 100;
*t = 1000;
*p = *t;
cout<<"Dia chi con tro:"<<t<<endl;
cout<<"Gia tri ma con tro:"<<*t;
delete t;
return 0;
}
II Các toán tử con trỏ
Có 2 toán tử
con trỏ quan trọng là toán tử * và &
1 Toán tử con trỏ &
Toán tử &
là toán tử 1 ngôi mà trả về địa chỉ bộ nhớ của toán hạng của nó. (toán tử 1
ngôi chỉ yêu cầu 1 toán hạng).
Vd:
int count;
int *m;
m = &count;
Lệnh m =
&count đặt địa chỉ bộ nhớ của biến count vào con trỏ m.
Lệnh trên được
phát biểu: “Con trỏ m nhận địa chỉ của biến count.”.
Ex:
Gỉa sử biến
count được cấp phát tại địa chỉ bộ nhớ 2000 để lưu trữ giá trị của nó.Gỉa sử
count có giá trị 100. Như vậy , tại địa chỉ bộ nhớ 2000 có chứa giá trị 100.
Sau lệnh m = &count; được thực hiện thì m sẽ có giá trị là 2000.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int count = 1000;
int *m;
m = new int;
*m = 100;
cout<<"Truoc khi chua tro: "<<*m<<endl;
m = &count;
cout<<"Sau khi tro den: "<<*m;
return 0;
}
2 Toán tử con trỏ *
Toán tử con trỏ
* là toán tử một ngôi trả về giá trị tại địa chỉ con trỏ trỏ đến
Vd: q = *m;w
Lấy giá trị tại
địa chỉ mà m trỏ đến và đặt vào biến q. Như vậy q sẽ có giá trị là 100 (là giá
trị của biến count).
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *m , p;
m = new int;
*m = 100;
p = *m;
cout<<"Gia tri bien: "<<p;
return 0;
}
Bài tập
minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int count = 100;
int *m = &count;
cout<<"Dia chi cua bien count:"<<&count<<endl;
cout<<"Gia tri cua bien count:"<<count<<endl;
cout<<"Dia chi cua bien m:"<<m<<endl;
cout<<"Gia tri cua bien m:"<<*m<<endl;
int p = *m;
cout<<"Gia tri p:"<<p<<endl;
int *x = m;
cout<<"Dia chi cua bien x: "<<x<<endl;
cout<<"Gia tri cua bien x: "<<*x<<endl;
*m = 1000;
cout<<"Dia chi cua bien x: "<<x<<endl;
cout<<"Gia tri cua bien x: "<<*x<<endl;
cout<<"Gia tri cua bien count: "<<count<<endl;
return 0;
}
Giải
thích:
Ta có: 1 biến
count = 100
Có 1 biến m trỏ
đến quản lý địa chỉ count = 100
ð
*m
có giá trị là 100
Tiếp ta gán biến
p = *m è p có
giá trị là 100
Ta tạo thêm con
trỏ *x cung tham quản lý địa chỉ count cùng *m nên è if *m thay đổi thi *x và count có giá
trị đều thay đổi giống như *m
III Các thao tác trên con trỏ
1 Lệnh gán con trỏ
Ta có thể dùng
1 con trỏ ở bên phải của câu lệnh gán (=) để gán giá trị của 1 con trỏ cho 1 con trỏ khác. Ví dụ:
int x;
int *p1, *p2;
p1 = &x;
p2 = p1;
Sau khi đoạn lệnh
được thực hiện , cả hai p1 và p2 cùng trỏ đến biến x.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 1882002;
int *p1, *p2;
p1 = &x;
p2 = p1;
cout<<"Gia tri p1 truoc khi gan lai: "<<*p1<<endl;
cout<<"Gia tri p2 truoc khi gan lai: "<<*p1<<endl;
*p2 = 100;
cout<<"Gia tri p1 sau khi gan lai: "<<*p1<<endl;
cout<<"Gia tri p2 sau khi gan lai: "<<*p2<<endl;
return 0;
}
2 Phép toán số học trên con trỏ
Chỉ có 2 phép
toán số học ta có thể dùng trên con trỏ đó là cộng và trừ. Gỉa sử p1 là một con
trỏ nguyên với giá trị hiện tại là 2000. Cũng giả sử rằng số nguyên chiếm 2
bytes bộ nhớ. Như vậy, sau khi thực hiện lệnh p1++; thì có giá trị là 2002 chứ
không phải là 2001 . Tương tự, giả sử p1 là một con trỏ nguyên với giá trị hiện
tại là 2000. Cũng giả sử rằng số nguyên chiếm 2 bytes bộ nhớ. Như vậy , sau khi
thực hiện lệnh p1--; thì p1 có giá trị là 1998 chứ không phải là 1999
VD:
Con trỏ i chứa
địa chỉ 3000 vậy lệnh:
i = i + 2;
i sẽ chứa địa
chỉ 3004
Lưu ý : Đơn vị tăng của con trỏ char là 1 Byte,
con trỏ int là 2 Bytes.
Tương tự, giả sử
con trỏ char ch chứa địa chỉ 3003, vậy lệnh
ch = ch – 3;
Bài tập
Cho a = 20 , b
= 15
Hoán đổi thành
a = 15 , b = 20;
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a = 20 , b = 15;
int *pa , *pb, temp;
pa = &a;
pb = &b;
temp = *pa;
*pa = *pb;
*pb = temp;
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
return 0;
}
IV Con trỏ Void và con trỏ Null
1 Con trỏ Void
Kiểu dữ liệu
khai báo biến con trỏ chính là kiểu dữ liệu mà con trỏ có thể trỏ đến , địa chỉ
đặt vào biến con trỏ đến địa chỉ đặt vào biến con trỏ phải cùng kiểu với kiểu
con trỏ. Xem xét đoạn mã sau:
Lưu ý:
int a;
float f;
int *pa;
float *pf;
/*
Những lệnh sau là hợp lệ:
pa = &a;
pf = &f;
Những lệnh sau là không hợp lệ
pa = &f; // pa là con trỏ int do đó chỉ chứa địa chỉ của biến kiểu int
pb = &a; // pb là con trỏ float do đó chỉ chứa chỉ chứa địa chỉ của kiểu float
*/
Con trỏ void là
một loại con trỏ đặc biệt mà có thể trỏ đến bất kỳ dữ liệu nào. Cú pháp khai
báo con trỏ như sau:
Void*pointerVariable;
Nếu ta khai báo
con trỏ void sau:
Void*p;
Thì các lệnh
sau đây là hợp lệ
P = &a; //
sau lệnh này p trỏ đến biến số nguyên a;
P = &f; //
sau lệnh f trỏ đến biến số thực f;
Tuy nhiên, tùy
thuộc con trỏ void đang trỏ đến kiểu dữ liệu nào, ta phải ép đúng kiểu tương ứng
khi dùng trong các biểu thức
Vd:
P đang trỏ đến
biến nguyên a, để tăng giá trị của biến a lên 10 ta phải dùng lệnh a sau:
(int*)*p+10;
Nếu p đang trỏ
đến biến thực f, để tăng giá trị của biển f lên 10:
Phải sử dụng
lênh: (float*)*p+10;
2 Con trỏ NULL
Một con trỏ hiện
hành không trỏ đến một địa chỉ bộ nhớ hợp lệ thì gán giá trị NULL. Bởi vì qui ước
, con trỏ NULL là con trỏ không trỏ đến đâu cả và không nên dùng.
Nếu chương
trình vô tình dùng con trỏ NULL như dưới đây thì sẽ nhận lỗi khi thực thi
chương trình (run-time error).
int*p;
cout<<”Gia
tri con tro p tro đến la: “<<*p;
Bài tập minh họa
Con trỏ
void
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a = 10;
float b = 8.8;
int *pa = &a;
float *pb = &b;
void *p;
p = &a;
(*(int*)p) = 100;
p = &b;
(*(float*)p) = 99.9;
cout<<"Gia tri a: "<<a<<endl;
cout<<"Gia tri b: "<<b<<endl;
return 0;
}
Con trỏ Null
#include <bits/stdc++.h>
using namespace std;
int main()
{
/*
int *a;
cout<<"Gia tri tri cua bien a: "<<*a<<endl;
cho ra gia tri rong
Loi run time error
*/
int *a = new int;
cout<<"Gia tri tri cua bien a: "<<*a;
// ==> cho ra 1 gia tri bat ky
return 0;
}
V Con trỏ và mảng
Giữa mảng và
con trỏ có một mối quan hệ gần. Xem xét đoạn mã dưới đây:
Char ch[80],
*p;
p = ch;
p |
p + 1 |
p + 2 |
p + 3 |
p + 4 |
p + 5 |
p + 6 |
p + 7 |
p + 8 |
p + 9 |
Ch[0] Ch[1] Ch[2]
Ch[3] Ch[4]
Ch[5] Ch[6]
Ch[7] Ch[8] Ch[9]
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[]={0,1,2,3,4,5,6,7,8,9};
for(int i = 0 ; i < 10 ; i++)
{
cout<<a[i]<<" ";
}
int *p = a;
cout<<endl;
for(int i = 0 ; i < 10 ; i++)
{
cout<<*(p+i)<<" ";
}
// *(p+i) == a[i]
return 0;
}
VI Mảng con trỏ
Mảng con trỏ là
một biến đơn . Ta có thể tạo mảng của các con trỏ. Mỗi phần tử của mảng là một
con trỏ thông thường . Cú pháp khai báo mảng con trỏ là:
type *pointerArray[elements];
type: kiểu dữ liệu mà các con trỏ phần tử trỏ
đến.
pointerArray:
tên mảng con trỏ.
Elements:
số phần tử của mảng con
trỏ.
Ví dụ:
int *p[5]; lệnh
này khai báo mảng con trỏ p có 5 phần tử.
Các lệnh dưới
đây minh họa cách sử dụng mảng này:
P[0] = &a;
//gán địa chỉ của biến nguyên a cho con trỏ p[0]
P[2] = p[0];
//sao chép địa chỉ có trong p[0] và p[2]
b = *p[0];//gán
giá trị tại địa chỉ p[0] trỏ đến vào biến b.
trường hợp này
, lệnh trương đương với b=a; vì hiện tại p[0] chứa địa chỉ của biến a.
Ex:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int *p[5];
for(int i = 0 ; i < 5 ; i++)
{
p[i] = new int;
*p[i] = 2*i;
}
for(int i = 0 ; i < 5 ; i++)
{
cout<<"Dia chi: "<<p[i]<<"==> "<<"Gia tri: "<<*p[i]<<endl;
}
return 0;
}
Lưu ý: Khi khai báo mảng con trỏ cần phải cấp
phát bộ nhớ cho từng phần của mảng con trỏ
VII Tương quan giữa mảng 2 chiều và con trỏ cấp
2
Con trỏ cấp 2
int **p = new int*[5];
for(int i = 0 ; i < 5 ; i++)
{
*(p+i)=new int[7];
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
p[i][j] = i + j
}
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
//cach 1: cout<<p[i][j]<<endl;
//cach 2: cout<<*(*(p+i)+j)<<endl;
}
cout<<endl;
}
Bài
tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
int **p = new int*[5];
for(int i = 0 ; i < 5 ; i++)
*(p+i) = new int[7];
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
p[i][j] = i + j;
}
}
for(int i = 0 ; i < 5 ; i++)
{
for(int j = 0 ; j < 7 ; j++)
{
cout<<*(*(p+i) + j)<<"\t";
}
cout<<endl;
}
return 0;
}
Bài tập rèn luyện
Bài 1:
Viết hàm hoán vị
hai biến thực a, b bằng cách sử dụng con trỏ (đối vào là hai con trỏ). Viết
chương trình chính nhập hai số thực a,b. Sử dụng hàm để đổi chỗ a và b.
Code:
#include <bits/stdc++.h>
using namespace std;
void hoanvi(float a , float b)
{
float *pa, *pb, temp;
pa = &a;
pb = &b;
temp = *pa;
*pa = *pb;
*pb = temp;
cout<<"a:"<<a<<endl;
cout<<"b:"<<b;
}
int main()
{
float a,b;
cin>>a>>b;
hoanvi(a,b);
return 0;
}
Bài 2:
Viết chương trình nhập vào một mảng a gồm n phần tử nguyên
ngẫu nhiên [0…100]. Sắp xếp mảng theo chiều giảm dần (lưu ý sử dụng tên mảng
như con trỏ và sử dụng con trỏ).
Code:
#include <bits/stdc++.h>
using namespace std;
void NhapMang(int *&a, int n)
{
a = new int[n];
for(int i = 0 ; i < n ; i++)
{
cin>>*(a+i);
}
}
int main()
{
int n;
cin>>n;
int *a = new int[n];
for(int i = 0 ; i < n ;i++)
cin>>*(a+i);
for(int i = 0 ; i < n ; i++)
cout<<*(a+i)<<" ";
cout<<endl;
for(int i = 0 ; i < n - 1 ; i++)
{
for(int j = i + 1 ; j < n ; j++)
{
if(*(a+i) *(a+j))
{
int temp = *(a+i);
*(a+i) = *(a+j);
*(a+j) = temp;
}
}
}
for(int i = 0 ; i < n ; i++)
cout<<*(a+i)<<" ";
return 0;
}
Bài 3:
Hãy viết hàm để
nhập / xuất vào một ma trận vuông cấp n với các số ngẫu nhiên [-50,100] và hàm
tìm phần tử Max của ma trận này (dùng con trỏ thay thế cho mảng 2 chiều).
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int **a = new int*[n];
for(int i = 0 ; i < n ; i++)
*(a+i) = new int[m];
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
cin>>*(*(a+i)+j);
}
}
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
cout<<*(*(a+i)+j)<<"\t";
}
cout<<endl;
}
int Max = a[0][0];
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++)
{
if(*(*(a+i)+j) > Max)
Max = *(*(a+i)+j);
}
}
cout<<"Gia tri lon nhat: "<<Max;
return 0;
}
Xử lý
chuỗi
I Khái niệm và cấu trúc của chuỗi
1. Khái
niệm
· Chuỗi là một mảng ký tự được
kết thúc bằng ký tự null (‘\0’).
· Ký tự null (‘\0’) là ký tự dùng để
kết thúc Chuỗi
· Hằng
chuỗi là Chuỗi được bao quanh bởi cặp dấu nháy đôi.
Ví
dụ:
“Hello”
· Ví dụ: để
khai báo một mảng str chứa chuỗi có độ dài 20 ký tự , ta khai báo:
char str[21];
Có thể
dùng Con trỏ để khai báo: char *str;
‘H’ |
‘e’ |
‘l’ |
‘l’ |
‘o’ |
‘\0’ |
str[0]
str[1] str[2] str[3] str[4] str[5]
str[5] è Ký tự
null
2. Cách khai
báo và khởi tạo chuỗi
· Có 2
cách khai báo và khởi tạo Chuỗi
- Cách 1: Dùng
mảng một chiều
char<Tên Biến>[Chiều dài tối đa]
o
Ví dụ: char str[12;
o Ví dụ: char str[25];
§ Ý
nghĩa khai báo một mảng kiểu ký tự tên là str có 25 phần tử (như vậy tối đa ta
có thể nhập 24 ký tự vì phần tử thứ 25 đã chứa ký tự kết thức chuỗi ‘\0’.
§ Lưu ý:
Chuỗi ký tự được kết thúc bằng ký tự ‘\0’.Do đó khai báo độ dài của chuỗi luôn
luôn khai báo dư 1 phần tử để chứa ký tự ‘\0’.
- Cách 2: Dùng
con trỏ
char *<Tên biến>
o
Ví dụ: char *<Tên biến>
§ Trong
khai báo này, bộ nhớ sẽ dành 2 byte để lưu trữ địa chỉ của biến con trỏ str
đang chỉ đến, chưa cung cấp nơi để lưu trữ dữ liệu.
v Trước
khi sử dụng phải dùng từ khóa new để cấp phát vùng nhớ.
o Ví dụ:
§
char *str;
§ str = new char[51]; // Cấp phát 51 ký tự
v Chuỗi
ký tự giống như mảng do đó để khởi tạo một Chuỗi ký tự với giá trị xác định ta
có thể thực hiện tương tự như với mảng.
char<biến>[]=<”Hằng Chuỗi”>
o Ví dụ:
char str[] = {‘H’, ’e’, ’l’, ’l’,
’o’, ’\0’};
char str[] = “Hello”;
char *str = “Hello”;
‘H’ |
‘e’ |
‘l’ |
‘l’ |
‘o’ |
‘\0’ |
str[0] str[1] str[2]
str[3] str[4]
str[5]
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char *str = "Hello";
cout<<str<<endl;
char str2[]="Obama";
cout<<str2<<endl;
char str3[]={'K','i','m','j','o','n','n','g','\0'};
cout<<str3<<endl;
char str4[10];
str4[0] = 'P';
str4[1] = 'u';
str4[2] = 't';
str4[3] = 'i';
str4[4] = 'n';
cout<<str4;
return 0;
}
II Cách xuất chuỗi – nhập cuối
Để nhập dữ liệu cho biến chuỗi, ta dùng tham gets():
char *gets(char *s);
Hàm gets()
đọc các ký tự từ bàn phím vào trong mảng con trỏ đén bởi s cho đến
khí nhấn Enter. Ký tự null
sẽ được đặt sau ký tự cuối cùng của chuỗi nhập vào trong mảng.
Lưu ý: Khi
dung cin>> để nhập dữ liệu chuỗi,
chương trình sẽ tự động ngắt chuỗi khi gặp ký tự khoảng trắng trong chuỗi. Do
đó, để chuỗi không bị ngắt khi gặp ký tự khoảng trắng, ta sẽ dùng hàm gets(), hoặc cin.getline() thay vì hàm cin thông thường
.
*cin.getline(chuỗi,số ký tự tối đa);
*Ví dụ:
o
char *str;
o
str = new char[30];
o
cin.getline(str,30);
Hàm để xuất chuỗi ra màn hình, ta dùng hàm puts():
int puts(const char *s);
Hoặc ta có thể dùng cout
cout<<s;
Ex 1:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char str[30];
cout<<"Nhap chuoi:";
gets(str);
cout<<"Xuat chuoi:";
puts(str);
return 0;
}
Ex 2:
#include <bits/stdc++.h>
using namespace std;
#define MAX 255
int main()
{
char str1[MAX];
char *str2;
cout<<"Nhap chuoi str1: ";
gets(str1);
str2 = new char[MAX];
cout<<"Nhap chuoi str2: ";
cin.getline(str2,MAX);
cout<<"Chuoi str1: "<<str1<<endl;
cout<<"Chuoi str2: ";
puts(str2);
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
using namespace std;
int main()
{
char str1[25];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
char *str2 = new char[50];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
char str3[50];
cout<<"Moi ban nhap chuoi: ";
cin.getline(str3,50);
cout<<"Chuoi cua ban sau khi nhap: ";
cout<<str3;
cout<<endl;
char *str4 = new char[50];
cout<<"Moi ban nhap chuoi: ";
cin.getline(str4,50);
cout<<"Chuoi cua ban sau khi nhap: ";
cout<<str4;
return 0;
}
Hàm strlen
Tính độ
dài của chuỗi s
-strlen(char *s);
Thư viện hàm: #include <string.h>
void main()
{
char *ch = “Lap trinh C”;
cout<<”Do
dai s =”<<strlen(ch);
}
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[25];
cout<<"Moi ban nhap chuoi: ";
gets(str1);
cout<<"Chuoi cua ban sau khi nhap: ";
puts(str1);
cout<<"Kich thuoc ban nhap: "<<strlen(str1)<<endl;
return 0;
}
III Hàm strcpy ,strncpy – sao chép chuỗi
1 Hàm strcpy
Ø Để sử
dụng các hàm này, ta phải khai báo dòng lệnh sau:
#include <string.h>
Ø Sao
chép nội dung chuỗi nguồn vào chuỗi đích , nội dung của chuỗi đích sẽ bị xóa.
Strcpy(char *đích, char *nguồn);
Ex:
Sao chép s1 vào s2: strcpy(s2,s1)
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[20], str2[40];
gets(str1);
strcpy(str2,str1);
puts(str2);
return 0;
}
2 Hàm strncpy
Ø Chép n
ký tự từ chuỗi nguồn sang chuỗi đích. Nếu chiều dài nguồn < n thì hàm sẽ điền
khoảng trẳng cho đủ n ký tự vào đích.
strncpy (char *đích, char *nguồn, int n);
Ví dụ:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[20],str2[20];
cout<<"Nhap chuoi 1:";
gets(str1);
strncpy(str2,str1,5);
cout<<"Xuat chuoi 2:";
puts(str2);
return 0;
}
IV Hàm strcat , strncat – nối chuỗi
1 Hàm strcat
Nối chuỗi s2 vào cuối chuỗi s1
#include <bits/stdc++.h>
#include <string.h>
int main()
{
char *s1 = new char[50];
gets(s1);
char *s2 = new char[50];
gets(s2);
strcat(s1,s2);
puts(s1);
return 0;
}
2 Hàm strncat
Ø Hàm n
ký tự đầu tiên của chuỗi s2 vào chuỗi s1
strncat(char s1[],char s2[],int n);
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[20], s2[20];
strcpy(s1,"To be ");
strcpy(s2,"or not to be");
strncat(s1,s2,6);
cout<<"Ket qua: "<<s1;
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[50],s2[50];
gets(s1),gets(s2);
strcat(s1,s2);
puts(s1);
char *s3 = new char[50],*s4 = new char[50];
strcpy(s3,"I love ");
strcpy(s4,"you");
strncat(s3,s4,3);
cout<<s3;
cout<<endl;
char ho[50],ten[50],hovaten[50];
cout<<"Ho: ";
gets(ho);
cout<<"Ten: ";
gets(ten);
strcpy(hovaten,"");
strcpy(hovaten,ho);
strcat(hovaten,ten);
puts(hovaten);
return 0;
}
V Hàm strchr , strstr – tìm ký tự , chuỗi
1 Hàm strchr
strchr(s1,ch): Trả về con trỏ đến vị trí xuất
hiện đầu tiên của ký tự ch trong Chuỗi s1
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *p,h,str1[20];
cout<<"Nhap chuoi 1:";
gets(str1);
cout<<"Nhap ky tu muon tim:";
cin>>h;
p = strchr(str1,h);
if(p == "\0") // Ghi NULL Hoac "\0" <=> NULL = "\0"
cout<<"Khong tim thay";
else
cout<<"Tim thay vi tri:"<<(p-str1);
return 0;
}
Ex:
Nhập chuỗi ký tự là: hello
Nhập ký tự cần tìm là l
h |
e |
l |
l |
o |
[0] [1] [2] [3] [4]
è vị
trí l cần tìm là vị trí số 2
2 Hàm strstr
Ø strstr(s1,s2): Trả về con trỏ đến vị trí xuất
hiện đầu tiên của chuỗi s2 trong s1.
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *p, str1[20],str2[20];
cout<<"Nhap chuoi 1:";
gets(str1);
cout<<"Nhap chuoi 2:";
gets(str2);
p = strstr(str1,str2);
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay tai vi tri:"<<(p-str1);
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[50];
strcpy(str1,"hello");
char *p = strchr(str1,'l');
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay 'l' tai vi tri:"<<(p-str1);
cout<<endl;
char str3[50],str4[50];
strcpy(str3,"Quanh nam buon ban o mom song nuoi du 5 con voi 1 chong");
strcpy(str4,"chong");
char *z = strstr(str3,str4);
if(p == NULL)
cout<<"Khong tim thay";
else
cout<<"Tim thay 'chong' tai vi tri:"<<(z-str1);
return 0;
}
VI Hàm strcmp, strcncmp – So sánh chuỗi
1 Hàm strcmp
Ø So
sánh 2 chuỗi s1 và s2 theo nguyên tắc thứ tự từ điển. Phân biệt chữ hoa và thường.
Trả về:
o
0 : if s1 ==
s2
o
>0 : if s1 lớn hơn s2
o
<0 : if s1 bé hơn s2
strcmp(char s1[],char s2[]);
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *s1 = "a";
char *s2 = "a";
int ret = strcmp(s1,s2);
if(ret == 0)
cout<<"2 thang do bang nhau"<<endl;
if(ret > 0)
cout<<"thang 1 lon hon thang 2"<<endl;
if(ret < 0)
cout<<"thang 2 lon hon thang 1"<<endl;
return 0;
}
2 Hàm strncmp
Ø int strncmp(const char *str1, const char
*str2, size_t n)
o
0 : if
str1 == str2
o
>0 : if str1 lớn hơn str2
o
<0 : if str1 bé hơn str2
Ex:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[50],str2[50];
strcpy(str1,"abcd chao");
strcpy(str2,"abcd");
int ret = strncmp(str1,str2,4);
if(ret == 0)
cout<<"str1 is equal to str2"<<endl;
if(ret > 0)
cout<<"str2 is less than str1"<<endl;
if(ret < 0)
cout<<"str1 is less than str2"<<endl;
return 0;
}
Bài tập minh họa
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s1[50],s2[50];
strcpy(s1,"Xin chao!");
strcpy(s2,"obama!");
int ret = strcmp(s1,s2);
if(ret == 0)
cout<<"str1 is equal to str2"<<endl;
if(ret > 0)
cout<<"str2 is less than str1"<<endl;
if(ret < 0)
cout<<"str1 is less than str2"<<endl;
char s3[50],s4[50];
strcpy(s3,"Xin chao!");
strcpy(s4,"obama!");
int rets = strncmp(s3,s4,4);
if(ret == 0)
cout<<"str3 is equal to str4"<<endl;
if(ret > 0)
cout<<"str3 is less than str4"<<endl;
if(ret < 0)
cout<<"str4 is less than str3"<<endl;
return 0;
}
VI Hàm toupper , tolower – In Hoa , Thường
Ø Hàm
toupper: Chuyển ký tự thường sang ký tự hoa
o
toupper(int
ch);
Ø Hàm
tolower: Chuyển ký tự hoa sang ký tự thường
o
tolower(ịnt
ch);
Bài tập minh họa:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char str1[] = "obama hahaha ali33";
int n1 = strlen(str1);
for(int i = 0 ; i < n1 ; i++)
{
char c = str1[i];
putchar(toupper(c));
}
cout<<endl;
char str2[] = "obama hahaha ali33";
int n2 = strlen(str2);
for(int i = 0 ; i < n2 ; i++)
{
char c = str2[i];
putchar(tolower(c));
}
return 0;
}
Bài tập tự luyện
Bài 1:
Viết chương trình nhập một chuỗi ký tự từ bàn phím, xuất ra
màn hình mã ASCII của ký tự vừa nhập vào (gợi ý mỗi ký tự trên một dòng).
Code:
#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char s[50];
cout<<"Moi ban nhap chuoi:";
gets(s);
int k = strlen(s);
for(int i = 0 ; i < k ; i++)
{
char c = *(s+i);
cout<<"ASCII: "<<(int)c<<endl;
}
return 0;
}
Bài 2:
Viết chương trình nhập 1 chuỗi ký tự từ bàn phím , xuất ra
màn hình đảo ngược của chuỗi đó.Ví dụ của “abcd egh” là “hge dcba”.
Code:
Cách 1:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char *s = new char[50];
cout<<"Moi ban nhap chuoi: ";
gets(s);
int k = strlen(s);
for(int i = k - 1 ; i >= 0 ; i--)
cout<<*(s+i);
return 0;
}
Cách 2:
#include <bits/stdc++.h>
#include <string.h>
using namespace std;
int main()
{
char s[50];
strcpy(s,"abcd egh");
int k = strlen(s);
for(int i = k - 1 ; i >= 0 ; i--)
cout<<*(s+i);
return 0;
}
Bài 3:
Viết chương nhập một chuỗi ký tự.
a) In ra
màn hình từ bên trái nhất và phần còn lại của chuỗi
Ex:
Input: “Nguyễn Văn Minh”
Output:
Nguyễn
Văn
Minh
Code:
#include <bits/stdc++.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
char *s = new char[100];
cout<<"Moi ban nhap chuoi ky tu: ";
//input char
gets(s);
//count char
int k = strlen(s);
//find ' '
char *p = strchr(s,' ');
int z = p - s;
char *sdau = new char[50];
strncpy(sdau,s,z);
cout<<sdau;
cout<<endl;
for(int i = z + 1; i < k ; i++)
cout<<*(s+i);
return 0;
}
b) In ra
màn hình từ bên phải nhất và phần còn lại của chuỗi
Ex:
Input: ”Nguyễn Văn Minh”
Output:
Minh
Nguyễn Văn
Code:
#include <bits/stdc++.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
// Nguyen van Minh
//==>hniM naV neyugN
char *s = new char[100];
cout<<"Moi ban nhap chuoi ky tu: ";
//input char
gets(s);
//count char
int k = strlen(s);
char *z;
char *p = strchr(s,' ');
char num[50];
int j = 0;
for(int i = k - 1 ; i >= 0 ; i--)
{
num[j] = *(s+i);
j++;
if(*(s+i) == ' ')
break;
}
for(int i = j - 2 ; i >= 0 ; i--)
cout<<num[i];
cout<<endl;
char *sdau = new char[50];
strncpy(sdau,s,k-j+1);
cout<<sdau;
return 0;
}
Kiểu dữ
liệu có cấu trúc
I Khái niệm và cách khai báo có cấu trúc
1. Khái
niệm
Structures
Một cấu trúc là một tập hợp các biến được
tham chiếu thông qua một tên chung. Một khai báo cấu trúc thành 1 khuôn mẫu
(template) mà có thể dùng để tạo nên các biến cấu trúc có cùng kiểu. Những biến
tạo mà tạo nên cấu trúc được gọi là các thành viên (members).
Nói gắn ngọn: Thực ra nó là một kiểu dữ liệu
phức hợp do ta tạo ra
2. Dạng tổng
quát của một khai báo cấu trúc
struct structureName
{
type member_1;
type member_2;
…
type member_n;
…
}varNames;
Struct: Từ khóa tạo cấu trúc trong C++
structureName: Tên của cấu trúc
type: Kiểu dữ liệu của thành viên tương ứng
member_1,member_2,…,member_n:Tên các biến thành viên của cấu trúc
varNames:Tên các biến cấu trúc phân cách
nhau bằng dấu phẩy.
Ví dụ:
struct addr
{
char name[30];
char street[30];
char city[30];
char state[30];
unsinged long int zip;
};
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct DiaChi
{
char sonha[25];
char TenDuong[250];
char Quan[25];
char TinhThanh[25];
};
struct SinhVien
{
char MaSV[10];
char TenSV[255];
bool GioiTinh;
DiaChi Diachinha;
DiaChi Diachitruong;
}teo,ty;
II Truy cập các biến thành viên của biến cấu
trúc
Nội dung:
Toán tử dấu chấm (dot operator) dùng để truy cập (access)
các thành viên của một biến cấu trúc. Dạng tổng quát để truy cập một thành viên
của một biến cấu trúc là:
structureName.memberName
Ví dụ: Xem xét khai báo cấu trúc sau
Struct coordXY
{
int x;
int y;
}diemA,diemB;
Để gán giá trị tọa độ cho diemA, ta dung lệnh sau:
diemA.x = 100;
diemA.y = 200;
Để in tạo độ điểm A, ta dùng lệnh sau:
cout<<”A(“<<diemA.x<<”,”<<diemA.y<<”)”;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct DiaChi
{
char sonha[25];
char TenDuong[250];
char Quan[25];
char TinhThanh[25];
};
struct SinhVien
{
char MaSV[10];
char TenSV[255];
bool GioiTinh;
DiaChi Diachinha;
DiaChi Diachitruong;
}teo,ty;
int main()
{
strcpy(teo.TenSV,"Nguyen Van Teo");
strcpy(teo.MaSV,"SV123");
teo.GioiTinh == false;
cout<<"------------------------\n";
cout<<"Ma: "<<teo.MaSV<<endl;
cout<<"Ten: "<<teo.TenSV<<endl;
cout<<"Gioi: "<<(teo.GioiTinh == true ? "Nu":"Nam")<<endl;
cout<<"------------------------\n";
SinhVien Luyen;
strcpy(Luyen.TenSV,"Le Van Luyen");
strcpy(Luyen.MaSV,"SV1234");
Luyen.GioiTinh == false;
cout<<"------------------------\n";
cout<<"Ma: "<<Luyen.MaSV<<endl;
cout<<"Ten: "<<Luyen.TenSV<<endl;
cout<<"Gioi: "<<(Luyen.GioiTinh == true ? "Nu":"Nam")<<endl;
cout<<"------------------------\n";
return 0;
}
III Lệnh gán cấu trúc
Nội dung:
Nội dung trong 1 biến cấu trúc có thể gán cho một biến cấu
trúc khác có cùng kiểu dùng một câu lệnh gán.
Ví dụ:
Để gán nội dung biến cấu trúc pointA cho pointB, ta thực hiện
lệnh sau:
pointB =
pointA;
Sau lệnh này,biến pointB có cùng nội dung như pointA.
Tuy nhiên, ta cũng có thể sao chép từng thành viên như sau:
pointB.x =
pointA.x;
pointB.y =
pointA.y;
VD:
struct book
{
char
title[30];
char
author[20];
int pages;
float price;
};
book b;
cout<<”Input book information:”<<endl;
cout<<”Title: ”;gets(b.title);
cout<<”Author:”;gets(b.author);
cout<<”Number of pages:”;cin>>b.pages;
cout<<”Price:”;cin>>b.price;
book a = b;
cout<<”Input book information:”<<endl;
cout<<”Title: ”<<a.title<<endl;
cout<<”Author:”<<a.author<<endl;
cout<<”Number of pages:”<<a.pages<<endl;
cout<<”Price:”<<a.price;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct Book
{
char title[30];
char author[20];
int pages;
float price;
};
int main()
{
Book b;
cout<<"Input book information:"<<endl;
cout<<"Title: ";
gets(b.title);
cout<<"Author:";
gets(b.author);
cout<<"Number of pages:";
cin>>b.pages;
cout<<"Price:";
cin>>b.price;
Book a = b;
cout<<"Input book information:"<<endl;
cout<<"Title: "<<a.title<<endl;
cout<<"Author:"<<a.author<<endl;
cout<<"Number of pages:"<<a.pages<<endl;
cout<<"Price:"<<a.price;
return 0;
}
III Mảng cấu trúc
Nội dung
Để khai báo một mảng cấu trúc, đầu tiên ta khai báo cấu
trúc , sau đó khai báo một mảng của cấu trúc đó.
Ta khai báo theo công thức tổng quát:
structerName
arrayName[Number of elements];
Ví dụ, khai báo mảng points có 100 phần tử, khai báo như
sau:
coordXY
points[100];
Để truy cập đến từng thành viên của phần tử của mảng, ta
dùng chỉ mục của phần tử và toán tử thành viên (.).Ví dụ, để gán tọa độ x,y cho
phần tử thứ 10, ta dùng các lệnh:
Point[9].x = 100;
Point[9].y = 200;
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct SinhVien
{
int ma;
char ten[255];
};
void nhapMang(SinhVien dsSV[] , int siso)
{
for(int i = 0; i < siso ; i++)
{
cout<<"Nhap sinh vien thu "<<i<<endl;
cout<<"Nhap ma:";
cin>>dsSV[i].ma;
cout<<"Nhap ten:";
cin.ignore();
gets(dsSV[i].ten);
}
}
void XuatMang(SinhVien dsSV[] , int siso)
{
for(int i = 0 ; i < siso ; i++)
{
cout<<dsSV[i].ma<<endl;
cout<<dsSV[i].ten<<endl;
}
}
int main()
{
int n = 3;
SinhVien a[n];
cin>>n;
nhapMang(a,n);
XuatMang(a,n);
return 0;
}
IV Con trỏ cấu trúc
Nội dung
C/C++ cho phép dùng con trỏ với cấu trúc như với bất kỳ kiểu
dữ liệu nào của biến.
Cú pháp khai báo con trỏ cấu trúc giống như các loại con trỏ
khác.
Dạng tổng quát để khai báo con trỏ cấu trúc:
structureName
*structurePointers;
Và cũng phải cấp phát bộ nhớ để sủ dụng (new) , cũng dùng à để truy suất
points *p; //Khai báo con trỏ p có kiểu cấu trúc points
p = &pointA; //gán địa chỉ của biến cấu trúc pointA cho
con trỏ p
p à x =
100; //gán giá trị 100 thành viên x của biến cấu trúc pointA
Minh họa
Code:
#include <bits/stdc++.h>
using namespace std;
struct SinhVien
{
int ma;
char ten[255];
};
int main()
{
SinhVien teo;
teo.ma = 113;
strcpy(teo.ten,"Teo");
cout<<teo.ma<<"\t"<<teo.ten<<endl;
SinhVien *ty = new SinhVien;
ty -> ma = 114;
strcpy(ty->ten,"Ty");
cout<<ty ->ma<<"\t"<<ty ->ten<<endl;
return 0;
}