Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 32

Cơ sở lập trình

Số tín chỉ: 3
Giảng viên: Ths. Cù Nguyên Giáp
Bộ môn: Tin học

7/2010 Cơ sở lập trình 1


Chương 3 – Mảng, xâu và con trỏ
3.1 Mảng và xâu
3.2 Con trỏ

7/2010 Cơ sở lập trình 2


3.1 Mảng và xâu
3.1.1 Mảng
3.1.2 Xâu

7/2010 Cơ sở lập trình 3


3.1.1 Mảng
• Giới thiệu:
– Bài toán dãy số với n biến đơn  việc khai báo và
quản lý biến phức tạp  Biến mảng
– Mảng: là một dãy các phần tử có cùng kiểu dữ liệu
được đặt liên tiếp trong bộ nhớ và có thể truy xuất
đến từng phần tử thông qua chỉ số mảng.
– Các yếu tố của mảng:
• Kiểu mảng
• Tên mảng
• Số phần tử/kích thước của mảng
7/2010 Cơ sở lập trình 4
3.1.1 Mảng
• Khai báo mảng
<type> <name> [size1][size2]…[sizeN];
• Trong đó:
– type là các kiểu dữ liệu cơ sở/ cấu trúc
– name: là tên được đặt cho mảng
– Số lượng thành phần [ ] được đặt sau tên mảng sẽ
qui định so chiều của mảng đó.
– Size1, size2,.., sizeN là các số nguyên qui định kích cỡ
của mảng hoặc số phần tử của mảng.

7/2010 Cơ sở lập trình 5


3.1.1 Mảng
• Ví dụ:
– int a[10];
– float arr[2][3];
• Chú ý:
– Mảng chỉ thực sự làm việc tốt với mảng tối đa 3 chiều
– Trường size1,size2..sizeN phải là một giá trị hằng khi
khai báo một mảng (vì mảng là một khối nhớ tĩnh có
kích cỡ xác định)
• Ví dụ khai báo sai:
– int n,m;
– int a[n][m];

7/2010 Cơ sở lập trình 6


3.1.1 Mảng
• Khởi tạo mảng:
– Biến địa phương: không được khởi tạo
– Biến toàn cục: tất cả các phần tử được khởi tạo bằng
0/NULL
– Có thể gán giá trị khởi tạo cho các phần tử của mảng
• Với mảng 1chiều:
<type> <name> [size]={v1,v2,v3,..,vk}; //( k<=N)
Hoặc <type> <name> [ ]={v1,v2,v3,..,vk};
• Ví dụ:
char a[5] = { 0, 1, 4, 3, 2 };
char a[] = { 0, 1, 4, 3, 2 };
7/2010 Cơ sở lập trình 7
3.1.1 Mảng
• Với mảng 2chiều:
<type> <name> [size1][size2] ={
{a11,a12,a13,...},
{a21,a22,a23,... },

};
• Khi đó: a11,a12,a23, … là giá trị khởi đầu của hàng
đầu tiên của mảng.
• a­21,a22,a23, … là giá trị khởi đầu của hàng thứ
hai của mảng.
• ….
7/2010 Cơ sở lập trình 8
3.1.1 Mảng
• Ví dụ:
int a[][4]={
{0},{1,3,5}, {2,4,6,8} }
a[0][0] =0
a[1][0]=1, a[1][1]=3, a[1][2]=5, và
a[2][0]=2, a[2][1]=4, a[2][2]=6, a[2][3]=8

7/2010 Cơ sở lập trình 9


3.1.1 Mảng
• Cách khởi tạo khác:
<type> <name> [size1][size2] ={v1,v2,..,vK };
trong đó (k <= size1*size2)
– Khi đó m giá trị đầu tiên của k gán cho dòng 1, m giá
trị tiếp theo gán cho dòng 2, …., cho đến hết k giá trị,
còn lại gán là 0, NULL hoặc giá trị bất kì tuỳ theo kiểu
dữ liệu và mảng là biến toàn cục hay biến cục bộ.
• Ví dụ:
int a[3][2]={1,2,3,4,5,6};

7/2010 Cơ sở lập trình 10


3.1.1 Mảng
• Truy xuất phần tử của mảng
• Cấu trúc: name[chỉ_số]
– Mỗi phần tử của mảng đóng vai trò như một biến đơn
• Lưu ý:
– Trong ngôn ngữ C các phần tử của mảng được đánh số
bắt đầu từ 0  vấn đề vượt quá giới hạn của mảng.
– Tên của mảng tương ứng với địa chỉ phần tử đầu tiên
của nó.
• Ví dụ:
int a[5];
a[2]=8;

7/2010 Cơ sở lập trình 11


3.1.1 Mảng
• Đối với mảng 2 chiều:
– Thường sử dụng define để định nghĩa trước kích thước của
mảng
– Cách truy xuất cũng tương tự như mảng 1 chiều. Phần tử đầu
tiên có chỉ số 0, a[0][0], phần tử a[i][j] là phần tử ở dòng i cột j.
• Lưu ý:
– Truy xuất tới một phần tử vượt ra ngoài phạm vi khai báo của
mảng: không bị báo lỗi nhưng giá trị của phần tử đó sẽ không
kiểm soát được.

7/2010 Cơ sở lập trình 12


3.1.1 Mảng
• Làm việc với mảng: dùng câu lệnh for để duyệt các
phần tử của mảng với biến điều khiển chạy theo chỉ
số của mảng.
• Ví dụ: Làm việc với dãy số
– Nhập dãy số
– In dãy số
– Đếm số phần tử chia hết cho 5.
– Tính tổng các phần tử chẵn.
– Sắp xếp dãy
3.1.2 Xâu (string)
• Giới thiệu:
– Xâu được xây dựng như một mảng các kí tự kể cả
khoảng trắng.
– Một hằng xâu có nội dung được đặt trong cặp dấu
“ ” và kết thúc xâu là kí tự ‘\0’ hay còn gọi là kí tự
NULL
• Lưu ý:
– Kí tự ‘a’ khác với xâu “a”. Vì xâu “a” bao gồm hai kí
tự là ‘a’ và ‘\0’

7/2010 Cơ sở lập trình 14


3.1.2 Xâu
• Khai báo xâu:
– Dùng mảng kí tự: char a[size];
– Dùng con trỏ kí tự: char *str;
• Khởi tạo xâu:
– Dùng mảng hoặc con trỏ
• Ví dụ:
– char a[15] = “hello world”;
• hoặc
– char *str = (char*) malloc (15*sizeof (char));
– char *str=”hello world”;

7/2010 Cơ sở lập trình 15


3.1.2 Xâu
• Nhập dữ liệu cho xâu:
• Cách 1: khởi tạo giá trị mặc định:
char *str=”hello world”;
• Cách 2: Dùng hàm scanf:
char *s = (char*) malloc (9*sizeof (char));
for( i =0; i< 9; i++)
scanf(“%c”, s+i);
• Lưu ý: cơ chế làm việc của vùng nhớ đệm có thể
nhận được kết quả không theo mong muốn
cần làm sạch vùng đệm

7/2010 Cơ sở lập trình 16


3.1.2 Xâu
char *s = (char*) malloc (9*sizeof (char));
for( i =0; i< 9; i++)
{
fflush(stdin) ;
scanf(“%c”, s+i);
}
• Nhận xét:
• Dài dòng và phức tạp  hạn chế sử dụng hàm scanf
để nhập dữ liệu cho xâu

7/2010 Cơ sở lập trình 17


3.1.2 Xâu
• Cách 3: dùng hàm gets
• Cú pháp:
char * gets(char *str);
• Hoạt động:
– cho phép nhập vào một dãy kí tự cho đến khi gặp kí hiệu
‘\n’(Enter).
– Kí tự ‘\n’ sẽ không được đặt vào chuỗi str, trình biên
dịch sẽ thêm vào cuối str là kí tự ‘\0’ (ký tự kết thúc
chuỗi)
- làm sạch vùng đệm trước khi gọi hàm: fflush(stdin);

7/2010 Cơ sở lập trình 18


3.1.2 Xâu
• Xuất xâu ra màn hình:
• Dùng hàm printf hoặc puts
int puts(const char *);
• Sự khác nhau: puts in xong thì con trỏ tự động nhảy
xuống dòng
• Ví dụ:
char hello[] = "Hello World";
printf("\nChuoi in ra = %s", hello);
puts(hello);

7/2010 Cơ sở lập trình 19


3.1.2 Xâu
• Ví dụ: Viết chương trình tìm độ dài của xâu.

7/2010 Cơ sở lập trình 20


3.1.2 Xâu
• Một số hàm xử lý xâu:
– strlen
– strchr
– strstr
– toupper
– tolower
• Yêu cầu: viết chương trình để thể hiện các
hàm trên

7/2010 Cơ sở lập trình 21


3.2 Con trỏ
3.2.1 Khái quát về con trỏ
3.2.2 Các phép toán trên con trỏ
3.2.3 Con trỏ và mảng

7/2010 Cơ sở lập trình 22


3.2.1 Khái quát về con trỏ
• Ý nghĩa: lưu trữ địa chỉ của vùng nhớ, có khả năng tham
chiếu trực tiếp đến giá trị mà chúng trỏ tới.
• Khai báo:
<Type> *<name>;
• Trong đó:
– Trong đó Type là kiểu dữ liệu của vùng nhớ được trỏ tới
không phải là kiểu của bản thân con trỏ
 Mỗi kiểu địa chỉ có một kiểu con trỏ tương ứng.
– Sau khi khai báo nhưng chưa được chỉ định trỏ vào đâu
thì con trỏ mang giá trị NULL

7/2010 Cơ sở lập trình 23


3.2.1 Khái quát về con trỏ
• Ví dụ:
int *number;
char *character;
float *greatnumber;
• Lưu ý:
– Đều là con trỏ và đều chiếm một lượng bộ nhớ như
nhau ((kích thước của một biến con trỏ tùy thuộc
vào hệ điều hành)
– Nhưng dữ liệu mà chúng trỏ tới không chiếm lượng
bộ nhớ như nhau

7/2010 Cơ sở lập trình 24


3.2.1 Khái quát về con trỏ
• Sử dụng con trỏ: cần phân biệt giá trị và địa chỉ của
con trỏ
• Ví dụ:
Int *p;
p chứa địa chỉ các vùng nhớ
*p chứa giá trị trong các vùng nhớ mà nó trỏ đến
• Nhập giá trị cho các biến trỏ:
–C1: sử dụng phép gán hoặc khởi tạo ban đầu
–C2: sử dụng các hàm cấp phát động

7/2010 Cơ sở lập trình 25


3.2.1 Khái quát về con trỏ
• Khởi tạo con trỏ: để chỉ định rõ ràng con trỏ sẽ
trỏ tới biến nào khi khai báo
• Ví dụ:
int cat;
int *tommy = &cat;
Tương đương với:
int cat;
int *tommy;
tommy = &cat;

7/2010 Cơ sở lập trình 26


3.2.1 Khái quát về con trỏ
• Cấp phát bộ nhớ cho con trỏ
• Thư viện: alloc.h
• Hàm cấp phát: malloc/ calloc
• Cú pháp:
<name> = <(type*)>malloc(size);// dùng cho các kiểu dl
cơ sở
<name> = <(type*)>calloc(n,sizeof (type));//dùng cho
kiểu dl người dùng định nghĩa

7/2010 Cơ sở lập trình 27


3.2.1 Khái quát về con trỏ
• Ví dụ: so sánh
int *ptr;
ptr = (int *) malloc(sizeof(int));
int x = 5;
*ptr = x;

int *ptr;
int x = 5;
ptr = &x;
• Lưu ý: khi gán con trỏ chúng ta phải luôn luôn gán địa chỉ
mà nó trỏ tới chứ không phải là giá trị mà nó trỏ tới.

7/2010 Cơ sở lập trình 28


3.2.2 Các phép toán trên con trỏ
• Phép so sánh
• Phép cộng con trỏ với số nguyên
• Phép trừ hai con trỏ

7/2010 Cơ sở lập trình 29


3.2.2 Các phép toán trên con trỏ
• Phép so sánh: là phép so sánh địa chỉ mà con
trỏ lưu giữ
• Phép cộng con trỏ với số nguyên
– Ptr là con trỏ kiểu T, k là số nguyên thì (Ptr+k) là
con trỏ kiểu T.
– Ptr trỏ tới phần tử t thì (Ptr+k) trỏ tới phần tử cách
t một khoảng là k.

7/2010 Cơ sở lập trình 30


3.2.3 Con trỏ và mảng
• Giống nhau: Tên của một mảng tương đương với địa chỉ
phần tử đầu tiên của nó. Một con trỏ tương đương với địa
chỉ của phần tử đầu tiên mà nó trỏ tới.
• Ví dụ:
int numbers [20], *p;
p = numbers; //hợp lệ
numbers = p; //không hợp lệ
• p và numbers là tương đương và chúng có cùng thuộc
tính, nhưng có thể gán một giá trị khác cho con trỏ p
trong khi numbers luôn trỏ đến phần tử đầu tiên trong số
20 phần tử mà nó được định nghĩa. Vì p - là một biến con
trỏ bình thường, còn numbers là một con trỏ hằng

7/2010 Cơ sở lập trình 31


3.2.3 Con trỏ và mảng
• Mối liên hệ
– Các phần tử của mảng có thể được truy xuất thông
qua chỉ số hoặc con trỏ
• Ví dụ:
a[5] = 0;
*(a+5) = 0;
– Mảng a[n] thì a là một con trỏ trỏ tới địa chỉ của
phần tử đầu tiên a[0]. Hay (a+i) &a[i], *(a+i) 
a[i]

7/2010 Cơ sở lập trình 32

You might also like